From 01305c2fa719bc3410628fce143d2b7fca44a40d Mon Sep 17 00:00:00 2001 From: landaiqing <3517283258@qq.com> Date: Thu, 5 Sep 2024 17:06:10 +0800 Subject: [PATCH] :bug: resolve interface validation issues --- api/client_api/client_api.go | 4 +-- api/oauth_api/wechat_api.go | 3 +-- api/permission_api/permission_api.go | 3 ++- api/user_api/user_api.go | 32 ++++++++++++++++++++++++ i18n/language/en.toml | 2 ++ i18n/language/zh.toml | 3 ++- middleware/check_client.go | 31 ----------------------- middleware/cors.go | 26 ------------------- middleware/jwt.go | 16 +++++++----- router/router.go | 37 +++++++++++++--------------- 10 files changed, 68 insertions(+), 89 deletions(-) delete mode 100644 middleware/check_client.go delete mode 100644 middleware/cors.go diff --git a/api/client_api/client_api.go b/api/client_api/client_api.go index 01de11e..e503a12 100644 --- a/api/client_api/client_api.go +++ b/api/client_api/client_api.go @@ -8,6 +8,7 @@ import ( "schisandra-cloud-album/common/result" "schisandra-cloud-album/global" "schisandra-cloud-album/utils" + "time" ) // GenerateClientId 生成客户端ID @@ -29,10 +30,9 @@ func (ClientAPI) GenerateClientId(c *gin.Context) { result.OkWithData(clientId, c) return } - // 生成新的客户端ID v1 := uuid.NewV1() - err := redis.Set(constant.UserLoginClientRedisKey+ip, v1.String(), 0).Err() + err := redis.Set(constant.UserLoginClientRedisKey+ip, v1.String(), time.Hour*24*30).Err() if err != nil { global.LOG.Error(err) return diff --git a/api/oauth_api/wechat_api.go b/api/oauth_api/wechat_api.go index 514522d..25e051e 100644 --- a/api/oauth_api/wechat_api.go +++ b/api/oauth_api/wechat_api.go @@ -125,9 +125,8 @@ func (OAuthAPI) GetTempQrCode(c *gin.Context) { result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c) return } - ip := utils.GetClientIP(c) // 使用工具函数获取客户端IP - key := constant.UserLoginQrcodeRedisKey + ip + ":" + clientId + key := constant.UserLoginQrcodeRedisKey + ip // 从Redis获取二维码数据 qrcode := redis.Get(key).Val() diff --git a/api/permission_api/permission_api.go b/api/permission_api/permission_api.go index 1a5e5a2..c9dc807 100644 --- a/api/permission_api/permission_api.go +++ b/api/permission_api/permission_api.go @@ -69,7 +69,7 @@ func (PermissionAPI) AssignPermissionsToRole(c *gin.Context) { return } -// GetUserPermissions 获取服用权限 +// GetUserPermissions 获取用户角色权限 func (PermissionAPI) GetUserPermissions(c *gin.Context) { userId := c.Query("user_id") if userId == "" { @@ -78,6 +78,7 @@ func (PermissionAPI) GetUserPermissions(c *gin.Context) { } data, err := global.Casbin.GetImplicitRolesForUser(userId) if err != nil { + result.FailWithMessage(ginI18n.MustGetMessage(c, "GetUserFailed"), c) return } result.OkWithData(data, c) diff --git a/api/user_api/user_api.go b/api/user_api/user_api.go index bfff5e0..80d451e 100644 --- a/api/user_api/user_api.go +++ b/api/user_api/user_api.go @@ -498,3 +498,35 @@ func getUserLoginDevice(user model.ScaAuthUser, c *gin.Context) bool { return true } + +// Logout 退出登录 +// @Summary 退出登录 +// @Tags 用户模块 +// @Success 200 {string} json +// @Router /api/auth/user/logout [post] +func (UserAPI) Logout(c *gin.Context) { + userId := c.Query("user_id") + if userId == "" { + global.LOG.Errorln("userId is empty") + result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c) + return + } + + tokenKey := constant.UserLoginTokenRedisKey + userId + del := redis.Del(tokenKey) + + if del.Err() != nil { + global.LOG.Errorln(del.Err()) + result.FailWithMessage(ginI18n.MustGetMessage(c, "LogoutFailed"), c) + return + } + ip := utils.GetClientIP(c) + key := constant.UserLoginClientRedisKey + ip + del = redis.Del(key) + if del.Err() != nil { + global.LOG.Errorln(del.Err()) + result.FailWithMessage(ginI18n.MustGetMessage(c, "LogoutFailed"), c) + return + } + result.OkWithMessage(ginI18n.MustGetMessage(c, "LogoutSuccess"), c) +} diff --git a/i18n/language/en.toml b/i18n/language/en.toml index 9e3bd51..e6a38ff 100644 --- a/i18n/language/en.toml +++ b/i18n/language/en.toml @@ -58,3 +58,5 @@ AssignFailed = "assign failed!" AssignSuccess = "assign successfully!" DuplicateLogin = "duplicate login!" PermissionDenied = "permission denied!" +LogoutFailed = "logout failed!" +LogoutSuccess = "logout successfully!" diff --git a/i18n/language/zh.toml b/i18n/language/zh.toml index 2802e42..fee72e2 100644 --- a/i18n/language/zh.toml +++ b/i18n/language/zh.toml @@ -58,4 +58,5 @@ AssignFailed = "分配失败!" AssignSuccess = "分配成功!" DuplicateLogin = "重复登录!" PermissionDenied = "权限不足!" - +LogoutFailed = "登出失败!" +LogoutSuccess = "登出成功!" diff --git a/middleware/check_client.go b/middleware/check_client.go deleted file mode 100644 index a0afd75..0000000 --- a/middleware/check_client.go +++ /dev/null @@ -1,31 +0,0 @@ -package middleware - -import ( - ginI18n "github.com/gin-contrib/i18n" - "github.com/gin-gonic/gin" - "schisandra-cloud-album/common/constant" - "schisandra-cloud-album/common/redis" - "schisandra-cloud-album/common/result" - "schisandra-cloud-album/utils" -) - -// CheckClientMiddleware 检查客户端请求是否合法 -func CheckClientMiddleware() gin.HandlerFunc { - return func(c *gin.Context) { - id := c.GetHeader("X-Request-Id") - if id == "" { - result.FailWithMessage(ginI18n.MustGetMessage(c, "AuthVerifyFailed"), c) - c.Abort() - return - } - - ip := utils.GetClientIP(c) - clientId := redis.Get(constant.UserLoginClientRedisKey + ip).Val() - if clientId == "" || clientId != id { - result.FailWithMessage(ginI18n.MustGetMessage(c, "AuthVerifyFailed"), c) - c.Abort() - return - } - c.Next() - } -} diff --git a/middleware/cors.go b/middleware/cors.go deleted file mode 100644 index 82165d5..0000000 --- a/middleware/cors.go +++ /dev/null @@ -1,26 +0,0 @@ -package middleware - -import ( - "github.com/gin-gonic/gin" - "net/http" -) - -// Cors 自定义跨域中间件 -func Cors() gin.HandlerFunc { - return func(c *gin.Context) { - method := c.Request.Method - origin := c.Request.Header.Get("Origin") - if origin != "" { - c.Header("Access-Control-Allow-Origin", "*") - c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE") - c.Header("Access-Control-Allow-Headers", "Content-Type,AccessToken,X-CSRF-Token, Authorization") - c.Header("Access-Control-Allow-Credentials", "true") - c.Set("content-type", "application/json") - } - //放行所有OPTIONS方法 - if method == "OPTIONS" { - c.AbortWithStatus(http.StatusNoContent) - } - c.Next() - } -} diff --git a/middleware/jwt.go b/middleware/jwt.go index 05ec5ca..5e779cc 100644 --- a/middleware/jwt.go +++ b/middleware/jwt.go @@ -24,8 +24,7 @@ func JWTAuthMiddleware() gin.HandlerFunc { // 默认双Token放在请求头Authorization的Bearer中,并以空格隔开 authHeader := c.GetHeader(global.CONFIG.JWT.HeaderKey) if authHeader == "" { - - result.FailWithMessage(ginI18n.MustGetMessage(c, "AuthVerifyFailed"), c) + result.FailWithCodeAndMessage(403, ginI18n.MustGetMessage(c, "AuthVerifyExpired"), c) c.Abort() return } @@ -33,11 +32,11 @@ func JWTAuthMiddleware() gin.HandlerFunc { accessToken := strings.TrimPrefix(authHeader, headerPrefix+" ") if accessToken == "" { - - result.FailWithMessage(ginI18n.MustGetMessage(c, "AuthVerifyFailed"), c) + result.FailWithCodeAndMessage(403, ginI18n.MustGetMessage(c, "AuthVerifyExpired"), c) c.Abort() return } + parseToken, isUpd, err := utils.ParseAccessToken(accessToken) if err != nil || !isUpd { result.FailWithCodeAndMessage(401, ginI18n.MustGetMessage(c, "AuthVerifyExpired"), c) @@ -45,15 +44,20 @@ func JWTAuthMiddleware() gin.HandlerFunc { return } token := redis.Get(constant.UserLoginTokenRedisKey + *parseToken.UserID).Val() + if token == "" { + result.FailWithCodeAndMessage(403, ginI18n.MustGetMessage(c, "AuthVerifyExpired"), c) + c.Abort() + return + } tokenResult := TokenData{} err = json.Unmarshal([]byte(token), &tokenResult) if err != nil { - result.FailWithMessage(ginI18n.MustGetMessage(c, "AuthVerifyExpired"), c) + result.FailWithCodeAndMessage(403, ginI18n.MustGetMessage(c, "AuthVerifyExpired"), c) c.Abort() return } if tokenResult.AccessToken != accessToken { - result.FailWithCodeAndMessage(403, ginI18n.MustGetMessage(c, "DuplicateLogin"), c) + result.FailWithCodeAndMessage(403, ginI18n.MustGetMessage(c, "AuthVerifyExpired"), c) c.Abort() return } diff --git a/router/router.go b/router/router.go index ce63fe8..c05b2fe 100644 --- a/router/router.go +++ b/router/router.go @@ -25,7 +25,7 @@ func InitRouter() *gin.Engine { router.Use(cors.New(cors.Config{ AllowOrigins: []string{global.CONFIG.System.Web}, AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"}, - AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization", "X-CSRF-Token", "Accept-Language", "X-Request-Id"}, + AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization", "Accept-Language"}, AllowCredentials: true, MaxAge: 12 * time.Hour, })) @@ -33,28 +33,25 @@ func InitRouter() *gin.Engine { router.Use(middleware.I18n()) publicGroup := router.Group("api") // 不需要鉴权的路由组 - authGroup := router.Group("api") // 需要鉴权的路由组 + { + modules.ClientRouter(publicGroup) // 注册客户端路由 + modules.SwaggerRouter(publicGroup) // 注册swagger路由 + modules.WebsocketRouter(publicGroup) // 注册websocket路由 + modules.OauthRouter(publicGroup) + modules.CaptchaRouter(publicGroup) // 注册验证码路由 + modules.SmsRouter(publicGroup) // 注册短信验证码路由 + modules.UserRouter(publicGroup) // 注册鉴权路由 + } + authGroup := router.Group("api") // 需要鉴权的路由组 authGroup.Use( middleware.JWTAuthMiddleware(), middleware.CasbinMiddleware(), - middleware.CheckClientMiddleware()) - - checkClientGroup := router.Group("api") // 需要检查客户端的路由组 - - checkClientGroup.Use(middleware.CheckClientMiddleware()) - - modules.ClientRouter(publicGroup) // 注册客户端路由 - modules.SwaggerRouter(publicGroup) // 注册swagger路由 - modules.WebsocketRouter(publicGroup) // 注册websocket路由 - - modules.CaptchaRouter(checkClientGroup) // 注册验证码路由 - modules.SmsRouter(checkClientGroup) // 注册短信验证码路由 - modules.OauthRouter(checkClientGroup) // 注册oauth路由 - modules.UserRouter(checkClientGroup) // 注册鉴权路由 - - modules.UserRouterAuth(authGroup) // 注册鉴权路由 - modules.RoleRouter(authGroup) // 注册角色路由 - modules.PermissionRouter(authGroup) // 注册权限路由 + ) + { + modules.UserRouterAuth(authGroup) // 注册鉴权路由 + modules.RoleRouter(authGroup) // 注册角色路由 + modules.PermissionRouter(authGroup) // 注册权限路由 + } return router }