feat: (rbac) permission map
This commit is contained in:
parent
2acae3582a
commit
c472adbf32
|
@ -2,7 +2,6 @@ package biz
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
@ -13,7 +12,6 @@ import (
|
|||
"infini.sh/framework/core/orm"
|
||||
"infini.sh/framework/core/util"
|
||||
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -156,7 +154,7 @@ func UpdatePassword(localUser *User, req dto.UpdatePassword) (err error) {
|
|||
user.ID = localUser.UserId
|
||||
_, err = orm.Get(&user)
|
||||
if err != nil {
|
||||
err = ErrNotFound
|
||||
|
||||
return
|
||||
}
|
||||
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.OldPassword))
|
||||
|
@ -173,93 +171,50 @@ func UpdatePassword(localUser *User, req dto.UpdatePassword) (err error) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = orm.Save(GenerateEvent(event.ActivityMetadata{
|
||||
Category: "platform",
|
||||
Group: "rbac",
|
||||
Name: "user",
|
||||
Type: "update",
|
||||
Labels: util.MapStr{
|
||||
"old_password": req.OldPassword,
|
||||
"new_password": req.NewPassword,
|
||||
},
|
||||
User: util.MapStr{
|
||||
"userid": user.ID,
|
||||
"username": user.Username,
|
||||
},
|
||||
}, nil, nil))
|
||||
return
|
||||
}
|
||||
func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) {
|
||||
|
||||
if authorizationHeader == "" {
|
||||
err = errors.New("authorization header is empty")
|
||||
return
|
||||
}
|
||||
fields := strings.Fields(authorizationHeader)
|
||||
if fields[0] != "Bearer" || len(fields) != 2 {
|
||||
err = errors.New("authorization header is invalid")
|
||||
return
|
||||
}
|
||||
tokenString := fields[1]
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
return []byte(Secret), nil
|
||||
})
|
||||
func UpdateProfile(localUser *User, req dto.UpdateProfile) (err error) {
|
||||
user := rbac.User{}
|
||||
user.ID = localUser.UserId
|
||||
_, err = orm.Get(&user)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
clams, ok := token.Claims.(*UserClaims)
|
||||
|
||||
if clams.UserId == "" {
|
||||
err = errors.New("user id is empty")
|
||||
user.Name = req.Name
|
||||
user.Email = req.Email
|
||||
user.Phone = req.Phone
|
||||
err = orm.Save(&user)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
fmt.Println("user token", clams.UserId, TokenMap[clams.UserId])
|
||||
tokenVal, ok := TokenMap[clams.UserId]
|
||||
if !ok {
|
||||
err = errors.New("token is invalid")
|
||||
return
|
||||
}
|
||||
if tokenVal.ExpireIn < time.Now().Unix() {
|
||||
err = errors.New("token is expire in")
|
||||
delete(TokenMap, clams.UserId)
|
||||
return
|
||||
}
|
||||
if ok && token.Valid {
|
||||
return clams, nil
|
||||
}
|
||||
err = orm.Save(GenerateEvent(event.ActivityMetadata{
|
||||
Category: "platform",
|
||||
Group: "rbac",
|
||||
Name: "user",
|
||||
Type: "update",
|
||||
Labels: util.MapStr{
|
||||
"name": req.Name,
|
||||
"email": req.Email,
|
||||
"phone": req.Phone,
|
||||
},
|
||||
User: util.MapStr{
|
||||
"userid": user.ID,
|
||||
"username": user.Username,
|
||||
},
|
||||
}, nil, nil))
|
||||
return
|
||||
|
||||
}
|
||||
func ValidatePermission(claims *UserClaims, permissions []string) (err error) {
|
||||
|
||||
user := claims.User
|
||||
|
||||
if user.UserId == "" {
|
||||
err = errors.New("user id is empty")
|
||||
return
|
||||
}
|
||||
if user.Roles == nil {
|
||||
err = errors.New("api permission is empty")
|
||||
return
|
||||
}
|
||||
|
||||
// 权限校验
|
||||
userPermissionMap := make(map[string]struct{})
|
||||
for _, role := range user.Roles {
|
||||
if _, ok := RoleMap[role]; ok {
|
||||
for _, v := range RoleMap[role].Platform {
|
||||
|
||||
userPermissionMap[v] = struct{}{}
|
||||
//all include read
|
||||
if strings.Contains(v, "all") {
|
||||
key := v[:len(v)-3] + "read"
|
||||
userPermissionMap[key] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var count int
|
||||
for _, v := range permissions {
|
||||
if _, ok := userPermissionMap[v]; ok {
|
||||
count++
|
||||
continue
|
||||
}
|
||||
}
|
||||
if count == len(permissions) {
|
||||
return nil
|
||||
}
|
||||
err = errors.New("permission denied")
|
||||
return
|
||||
|
||||
}
|
||||
|
|
|
@ -4,20 +4,60 @@ import (
|
|||
"time"
|
||||
)
|
||||
|
||||
const UserRead = "system.user:read"
|
||||
const UserAll = "system.user:all"
|
||||
var PermissionMap = make(map[string][]string)
|
||||
|
||||
const RoleRead = "system.role:read"
|
||||
const RoleAll = "system.role:all"
|
||||
const (
|
||||
UserRead = "system.user:read"
|
||||
UserAll = "system.user:all"
|
||||
RoleRead = "system.role:read"
|
||||
RoleAll = "system.role:all"
|
||||
RuleRead = "alerting.rule:read"
|
||||
RuleAll = "alerting.rule:all"
|
||||
InstanceRead = "gateway.instance:read"
|
||||
InstanceAll = "gateway.instance:all"
|
||||
FlowRead = "gateway.flow:read"
|
||||
FlowAll = "gateway.flow:all"
|
||||
IndexAll = "data.index:read"
|
||||
IndexRead = "data.index:all"
|
||||
ViewsAll = "data.views:read"
|
||||
ViewsRead = "data.views:all"
|
||||
DiscoverAll = "data.discover:read"
|
||||
DiscoverRead = "data.discover:all"
|
||||
ClusterAll = "system.cluster:all"
|
||||
ClusterRead = "system.cluster:read"
|
||||
|
||||
const RuleRead = "alerting.rule:read"
|
||||
const RuleAll = "alerting.rule:all"
|
||||
CommandAll = "system.command:all"
|
||||
CommandRead = "system.command:read"
|
||||
|
||||
const InstanceRead = "gateway.instance:read"
|
||||
const InstanceAll = "gateway.instance:all"
|
||||
EntryAll = "gateway.entry:all"
|
||||
EntryRead = "gateway.entry:read"
|
||||
RouterRead = "gateway.router:read"
|
||||
RouterAll = "gateway.router:all"
|
||||
)
|
||||
|
||||
var UserReadPermission = []string{"user:read"}
|
||||
var UserAllPermission = []string{"user:read", "user:write"}
|
||||
|
||||
var RoleReadPermission = []string{"role:read"}
|
||||
var RoleAllPermission = []string{"role:read", "role:write"}
|
||||
|
||||
var RuleReadPermission = []string{"rule:read"}
|
||||
var RuleAllPermission = []string{"rule:read", "rule:write"}
|
||||
|
||||
var InstanceReadPermission = []string{"instance:read"}
|
||||
var InstanceAllPermission = []string{"instance:all"}
|
||||
|
||||
var EntryReadPermission = []string{"entry:read"}
|
||||
var EntryAllPermission = []string{"entry:all"}
|
||||
|
||||
var RouterReadPermission = []string{"router:read"}
|
||||
var RouterAllPermission = []string{"router:all"}
|
||||
|
||||
var AdminPrivilege = []string{
|
||||
UserRead, UserAll, RoleRead, RoleAll,
|
||||
UserAll, RoleAll, RuleAll, EntryAll,
|
||||
InstanceAll, ClusterAll, CommandAll, RouterAll,
|
||||
FlowRead, FlowAll, IndexAll, ViewsAll,
|
||||
DiscoverAll,
|
||||
}
|
||||
|
||||
var BuildRoles = make(map[string]map[string]interface{}, 0)
|
||||
|
@ -33,5 +73,19 @@ func init() {
|
|||
"description": "is admin",
|
||||
"created": time.Now(),
|
||||
}
|
||||
PermissionMap = map[string][]string{
|
||||
UserRead: UserReadPermission,
|
||||
UserAll: UserAllPermission,
|
||||
RoleRead: RoleReadPermission,
|
||||
RoleAll: RoleAllPermission,
|
||||
RuleRead: RuleReadPermission,
|
||||
RuleAll: RuleAllPermission,
|
||||
InstanceRead: InstanceReadPermission,
|
||||
InstanceAll: InstanceAllPermission,
|
||||
EntryRead: EntryReadPermission,
|
||||
EntryAll: EntryAllPermission,
|
||||
RouterRead: RouterReadPermission,
|
||||
RouterAll: RouterAllPermission,
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,9 +2,13 @@ package biz
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"infini.sh/console/internal/biz/enum"
|
||||
httprouter "infini.sh/framework/core/api/router"
|
||||
"infini.sh/framework/core/util"
|
||||
"src/github.com/golang-jwt/jwt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type EsRequest struct {
|
||||
|
@ -159,3 +163,98 @@ func FilterIndex(roles []string, index []string) []string {
|
|||
}
|
||||
return realIndex
|
||||
}
|
||||
func ValidateLogin(authorizationHeader string) (clams *UserClaims, err error) {
|
||||
|
||||
if authorizationHeader == "" {
|
||||
err = errors.New("authorization header is empty")
|
||||
return
|
||||
}
|
||||
fields := strings.Fields(authorizationHeader)
|
||||
if fields[0] != "Bearer" || len(fields) != 2 {
|
||||
err = errors.New("authorization header is invalid")
|
||||
return
|
||||
}
|
||||
tokenString := fields[1]
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, &UserClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
|
||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||
}
|
||||
return []byte(Secret), nil
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
clams, ok := token.Claims.(*UserClaims)
|
||||
|
||||
if clams.UserId == "" {
|
||||
err = errors.New("user id is empty")
|
||||
return
|
||||
}
|
||||
fmt.Println("user token", clams.UserId, TokenMap[clams.UserId])
|
||||
tokenVal, ok := TokenMap[clams.UserId]
|
||||
if !ok {
|
||||
err = errors.New("token is invalid")
|
||||
return
|
||||
}
|
||||
if tokenVal.ExpireIn < time.Now().Unix() {
|
||||
err = errors.New("token is expire in")
|
||||
delete(TokenMap, clams.UserId)
|
||||
return
|
||||
}
|
||||
if ok && token.Valid {
|
||||
return clams, nil
|
||||
}
|
||||
return
|
||||
|
||||
}
|
||||
func ValidatePermission(claims *UserClaims, permissions []string) (err error) {
|
||||
|
||||
user := claims.User
|
||||
|
||||
if user.UserId == "" {
|
||||
err = errors.New("user id is empty")
|
||||
return
|
||||
}
|
||||
if user.Roles == nil {
|
||||
err = errors.New("api permission is empty")
|
||||
return
|
||||
}
|
||||
|
||||
// 权限校验
|
||||
userPermissions := make([]string, 0)
|
||||
for _, role := range user.Roles {
|
||||
if _, ok := RoleMap[role]; ok {
|
||||
for _, v := range RoleMap[role].Platform {
|
||||
userPermissions = append(userPermissions, v)
|
||||
|
||||
//all include read
|
||||
if strings.Contains(v, "all") {
|
||||
key := v[:len(v)-3] + "read"
|
||||
userPermissions = append(userPermissions, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
userPermissionMap := make(map[string]struct{})
|
||||
for _, val := range userPermissions {
|
||||
for _, v := range enum.PermissionMap[val] {
|
||||
userPermissionMap[v] = struct{}{}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var count int
|
||||
for _, v := range permissions {
|
||||
if _, ok := userPermissionMap[v]; ok {
|
||||
count++
|
||||
continue
|
||||
}
|
||||
}
|
||||
if count == len(permissions) {
|
||||
return nil
|
||||
}
|
||||
err = errors.New("permission denied")
|
||||
return
|
||||
|
||||
}
|
||||
|
|
|
@ -8,3 +8,8 @@ type UpdatePassword struct {
|
|||
OldPassword string `json:"old_password"`
|
||||
NewPassword string `json:"new_password"`
|
||||
}
|
||||
type UpdateProfile struct {
|
||||
Name string `json:"name"`
|
||||
Phone string `json:"phone"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
|
|
@ -92,7 +92,13 @@ func (h Account) CurrentUser(w http.ResponseWriter, req *http.Request, ps httpro
|
|||
}
|
||||
}
|
||||
func (h Account) Logout(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
reqUser, err := biz.FromUserContext(r.Context())
|
||||
if err != nil {
|
||||
h.ErrorInternalServer(w, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
delete(biz.TokenMap, reqUser.UserId)
|
||||
h.WriteOKJSON(w, util.MapStr{
|
||||
"status": "ok",
|
||||
})
|
||||
|
@ -149,8 +155,22 @@ func (h Account) UpdatePassword(w http.ResponseWriter, r *http.Request, ps httpr
|
|||
h.ErrorInternalServer(w, err.Error())
|
||||
return
|
||||
}
|
||||
h.WriteOKJSON(w, util.MapStr{
|
||||
"status": "ok",
|
||||
})
|
||||
|
||||
h.WriteOKJSON(w, core.UpdateResponse(reqUser.UserId))
|
||||
return
|
||||
}
|
||||
func (h Account) UpdateProfile(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
reqUser, err := biz.FromUserContext(r.Context())
|
||||
if err != nil {
|
||||
h.ErrorInternalServer(w, err.Error())
|
||||
return
|
||||
}
|
||||
var req dto.UpdateProfile
|
||||
err = h.DecodeJSON(r, &req)
|
||||
err = biz.UpdateProfile(reqUser, req)
|
||||
if err != nil {
|
||||
h.ErrorInternalServer(w, err.Error())
|
||||
return
|
||||
}
|
||||
h.WriteOKJSON(w, core.UpdateResponse(reqUser.UserId))
|
||||
return
|
||||
}
|
||||
|
|
|
@ -22,19 +22,19 @@ func init() {
|
|||
|
||||
r := Rbac{}
|
||||
api.HandleAPIMethod(api.GET, "/permission/:type", r.ListPermission)
|
||||
api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAll))
|
||||
api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.RoleRead))
|
||||
api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.RoleAll))
|
||||
api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.RoleAll))
|
||||
api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.RoleRead))
|
||||
api.HandleAPIMethod(api.POST, "/role/:type", m.PermissionRequired(r.CreateRole, enum.RoleAllPermission...))
|
||||
api.HandleAPIMethod(api.GET, "/role/:id", m.PermissionRequired(r.GetRole, enum.RoleReadPermission...))
|
||||
api.HandleAPIMethod(api.DELETE, "/role/:id", m.PermissionRequired(r.DeleteRole, enum.RoleAllPermission...))
|
||||
api.HandleAPIMethod(api.PUT, "/role/:id", m.PermissionRequired(r.UpdateRole, enum.RoleAllPermission...))
|
||||
api.HandleAPIMethod(api.GET, "/role/_search", m.PermissionRequired(r.SearchRole, enum.RoleReadPermission...))
|
||||
|
||||
api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.UserAll))
|
||||
api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.UserRead))
|
||||
api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.UserAll))
|
||||
api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UserAll))
|
||||
api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UserAll))
|
||||
api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.UserRead))
|
||||
api.HandleAPIMethod(api.PUT, "/user/:id/password", m.PermissionRequired(r.UpdateUserPassword, enum.UserAll))
|
||||
api.HandleAPIMethod(api.POST, "/user", m.PermissionRequired(r.CreateUser, enum.UserAllPermission...))
|
||||
api.HandleAPIMethod(api.GET, "/user/:id", m.PermissionRequired(r.GetUser, enum.UserReadPermission...))
|
||||
api.HandleAPIMethod(api.DELETE, "/user/:id", m.PermissionRequired(r.DeleteUser, enum.UserAllPermission...))
|
||||
api.HandleAPIMethod(api.PUT, "/user/:id", m.PermissionRequired(r.UpdateUser, enum.UserAllPermission...))
|
||||
api.HandleAPIMethod(api.PUT, "/user/:id/role", m.PermissionRequired(r.UpdateUserRole, enum.UserAllPermission...))
|
||||
api.HandleAPIMethod(api.GET, "/user/_search", m.PermissionRequired(r.SearchUser, enum.UserReadPermission...))
|
||||
api.HandleAPIMethod(api.PUT, "/user/:id/password", m.PermissionRequired(r.UpdateUserPassword, enum.UserAllPermission...))
|
||||
}
|
||||
|
||||
func loadJsonConfig() {
|
||||
|
|
|
@ -185,7 +185,7 @@ func (h Rbac) UpdateUserPassword(w http.ResponseWriter, r *http.Request, ps http
|
|||
h.ErrorInternalServer(w, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
delete(biz.TokenMap, localUser.UserId)
|
||||
_ = h.WriteOKJSON(w, core.UpdateResponse(id))
|
||||
return
|
||||
|
||||
|
|
Loading…
Reference in New Issue