package authorization import ( "github.com/dchest/captcha" "github.com/gin-gonic/gin" "goskeleton/app/global/consts" "goskeleton/app/global/variable" userstoken "goskeleton/app/service/users/token" "goskeleton/app/utils/response" "strings" ) type HeaderParams struct { Authorization string `header:"Authorization" binding:"required,min=20"` } // CheckTokenAuth 检查token完整性、有效性中间件 func CheckTokenAuth() gin.HandlerFunc { return func(context *gin.Context) { headerParams := HeaderParams{} // 推荐使用 ShouldBindHeader 方式获取头参数 if err := context.ShouldBindHeader(&headerParams); err != nil { response.TokenErrorParam(context, consts.JwtTokenMustValid+err.Error()) return } token := strings.Split(headerParams.Authorization, " ") if len(token) == 2 && len(token[1]) >= 20 { tokenIsEffective := userstoken.CreateUserFactory().IsEffective(token[1]) if tokenIsEffective { if customToken, err := userstoken.CreateUserFactory().ParseToken(token[1]); err == nil { key := variable.ConfigYml.GetString("Token.BindContextKeyName") // token验证通过,同时绑定在请求上下文 context.Set(key, customToken) } context.Next() } else { response.ErrorTokenAuthFail(context) } } else { response.ErrorTokenBaseInfo(context) } } } // CheckTokenAuthWithRefresh 检查token完整性、有效性并且自动刷新中间件 func CheckTokenAuthWithRefresh() gin.HandlerFunc { return func(context *gin.Context) { headerParams := HeaderParams{} // 推荐使用 ShouldBindHeader 方式获取头参数 if err := context.ShouldBindHeader(&headerParams); err != nil { response.TokenErrorParam(context, consts.JwtTokenMustValid+err.Error()) return } token := strings.Split(headerParams.Authorization, " ") if len(token) == 2 && len(token[1]) >= 20 { tokenIsEffective := userstoken.CreateUserFactory().IsEffective(token[1]) // 判断token是否有效 if tokenIsEffective { if customToken, err := userstoken.CreateUserFactory().ParseToken(token[1]); err == nil { key := variable.ConfigYml.GetString("Token.BindContextKeyName") // token验证通过,同时绑定在请求上下文 context.Set(key, customToken) // 在自动刷新token的中间件中,将请求的认证键、值,原路返回,与后续刷新逻辑格式保持一致 context.Header("Refresh-Token", "") context.Header("Access-Control-Expose-Headers", "Refresh-Token") } context.Next() } else { // 判断token是否满足刷新条件 if userstoken.CreateUserFactory().TokenIsMeetRefreshCondition(token[1]) { // 刷新token if newToken, ok := userstoken.CreateUserFactory().RefreshToken(token[1]); ok { if customToken, err := userstoken.CreateUserFactory().ParseToken(newToken); err == nil { key := variable.ConfigYml.GetString("Token.BindContextKeyName") // token刷新成功,同时绑定在请求上下文 context.Set(key, customToken) } // 新token放入header返回 context.Header("Refresh-Token", newToken) context.Header("Access-Control-Expose-Headers", "Refresh-Token") context.Next() } else { response.ErrorTokenRefreshFail(context) } } else { response.ErrorTokenRefreshFail(context) } } } else { response.ErrorTokenBaseInfo(context) } } } // RefreshTokenConditionCheck 刷新token条件检查中间件,针对已经过期的token,要求是token格式以及携带的信息满足配置参数即可 func RefreshTokenConditionCheck() gin.HandlerFunc { return func(context *gin.Context) { headerParams := HeaderParams{} if err := context.ShouldBindHeader(&headerParams); err != nil { response.TokenErrorParam(context, consts.JwtTokenMustValid+err.Error()) return } token := strings.Split(headerParams.Authorization, " ") if len(token) == 2 && len(token[1]) >= 20 { // 判断token是否满足刷新条件 if userstoken.CreateUserFactory().TokenIsMeetRefreshCondition(token[1]) { context.Next() } else { response.ErrorTokenRefreshFail(context) } } else { response.ErrorTokenBaseInfo(context) } } } // CheckCasbinAuth casbin检查用户对应的角色权限是否允许访问接口 func CheckCasbinAuth() gin.HandlerFunc { return func(c *gin.Context) { requstUrl := c.Request.URL.Path method := c.Request.Method // 模拟请求参数转换后的角色(roleId=2) // 主线版本没有深度集成casbin的使用逻辑 // GinSkeleton-Admin 系统则深度集成了casbin接口权限管控 // 详细实现参考地址:https://gitee.com/daitougege/gin-skeleton-admin-backend/blob/master/app/http/middleware/authorization/auth.go role := "2" // 这里模拟某个用户的roleId=2 // 这里将用户的id解析为所拥有的的角色,判断是否具有某个权限即可 isPass, err := variable.Enforcer.Enforce(role, requstUrl, method) if err != nil { response.ErrorCasbinAuthFail(c, err.Error()) return } else if !isPass { response.ErrorCasbinAuthFail(c, "") return } else { c.Next() } } } // CheckCaptchaAuth 验证码中间件 func CheckCaptchaAuth() gin.HandlerFunc { return func(c *gin.Context) { captchaIdKey := variable.ConfigYml.GetString("Captcha.captchaId") captchaValueKey := variable.ConfigYml.GetString("Captcha.captchaValue") captchaId := c.PostForm(captchaIdKey) value := c.PostForm(captchaValueKey) if captchaId == "" || value == "" { response.Fail(c, consts.CaptchaCheckParamsInvalidCode, consts.CaptchaCheckParamsInvalidMsg, "") return } if captcha.VerifyString(captchaId, value) { c.Next() } else { response.Fail(c, consts.CaptchaCheckFailCode, consts.CaptchaCheckFailMsg, "") } } }