package midware import ( "context" "fmt" "net/http" "ems.agt/lib/core/cache" "ems.agt/lib/core/utils/ctx" "ems.agt/lib/core/vo" "ems.agt/lib/core/vo/result" "ems.agt/lib/dborm" ) // Authorize 用户身份授权认证校验 // // 只需含有其中角色 "hasRoles": {"xxx"}, // // 只需含有其中权限 "hasPerms": {"xxx"}, // // 同时匹配其中角色 "matchRoles": {"xxx"}, // // 同时匹配其中权限 "matchPerms": {"xxx"}, func Authorize(options map[string][]string) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // 获取请求头标识信息 accessToken := r.Header.Get("AccessToken") if accessToken == "" { ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization token error")) return } // 验证令牌 == 这里直接查数据库session if !dborm.XormExistValidToken(accessToken, 0) { ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization valid error")) return } se, err := dborm.XormUpdateSessionShakeTime(accessToken) if err != nil { ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization shake error")) return } // 获取缓存的用户信息 data, ok := cache.GetLocalTTL(se.AccountId) if data == nil || !ok { ctx.JSON(w, 401, result.CodeMsg(401, "Invalid identity authorization info error")) return } loginUser := data.(vo.LoginUser) // 登录用户角色权限校验 if options != nil { var roles []string for _, item := range loginUser.User.Roles { roles = append(roles, item.RoleKey) } perms := loginUser.Permissions verifyOk := verifyRolePermission(roles, perms, options) if !verifyOk { msg := fmt.Sprintf("Unauthorized access %s %s", r.Method, r.RequestURI) ctx.JSON(w, 403, result.CodeMsg(403, msg)) return } } // 在请求的 Context 中存储数据 rContext := r.Context() rContext = context.WithValue(rContext, ctx.ContextKey("LoginUser"), loginUser) // 继续处理请求 next.ServeHTTP(w, r.WithContext(rContext)) }) } } // verifyRolePermission 校验角色权限是否满足 // // roles 角色字符数组 // // perms 权限字符数组 // // options 参数 func verifyRolePermission(roles, perms []string, options map[string][]string) bool { // 直接放行 管理员角色或任意权限 if contains(roles, "admin") || contains(perms, "*:*:*") { return true } opts := make([]bool, 4) // 只需含有其中角色 hasRole := false if arr, ok := options["hasRoles"]; ok && len(arr) > 0 { hasRole = some(roles, arr) opts[0] = true } // 只需含有其中权限 hasPerms := false if arr, ok := options["hasPerms"]; ok && len(arr) > 0 { hasPerms = some(perms, arr) opts[1] = true } // 同时匹配其中角色 matchRoles := false if arr, ok := options["matchRoles"]; ok && len(arr) > 0 { matchRoles = every(roles, arr) opts[2] = true } // 同时匹配其中权限 matchPerms := false if arr, ok := options["matchPerms"]; ok && len(arr) > 0 { matchPerms = every(perms, arr) opts[3] = true } // 同时判断 含有其中 if opts[0] && opts[1] { return hasRole || hasPerms } // 同时判断 匹配其中 if opts[2] && opts[3] { return matchRoles && matchPerms } // 同时判断 含有其中且匹配其中 if opts[0] && opts[3] { return hasRole && matchPerms } if opts[1] && opts[2] { return hasPerms && matchRoles } return hasRole || hasPerms || matchRoles || matchPerms } // contains 检查字符串数组中是否包含指定的字符串 func contains(arr []string, target string) bool { for _, str := range arr { if str == target { return true } } return false } // some 检查字符串数组中含有其中一项 func some(origin []string, target []string) bool { has := false for _, t := range target { for _, o := range origin { if t == o { has = true break } } if has { break } } return has } // every 检查字符串数组中同时包含所有项 func every(origin []string, target []string) bool { match := true for _, t := range target { found := false for _, o := range origin { if t == o { found = true break } } if !found { match = false break } } return match }