🐛 fix the casbin invalidation bug/adjust routing strategy

This commit is contained in:
landaiqing
2024-09-04 18:58:13 +08:00
parent b6dafddce1
commit 2eb9c3ac68
24 changed files with 243 additions and 113 deletions

View File

@@ -2,6 +2,7 @@ package api
import ( import (
"schisandra-cloud-album/api/captcha_api" "schisandra-cloud-album/api/captcha_api"
"schisandra-cloud-album/api/client_api"
"schisandra-cloud-album/api/oauth_api" "schisandra-cloud-album/api/oauth_api"
"schisandra-cloud-album/api/permission_api" "schisandra-cloud-album/api/permission_api"
"schisandra-cloud-album/api/role_api" "schisandra-cloud-album/api/role_api"
@@ -19,6 +20,7 @@ type Apis struct {
WebsocketApi websocket_api.WebsocketAPI WebsocketApi websocket_api.WebsocketAPI
RoleApi role_api.RoleAPI RoleApi role_api.RoleAPI
PermissionApi permission_api.PermissionAPI PermissionApi permission_api.PermissionAPI
ClientApi client_api.ClientAPI
} }
// Api new函数实例化实例化完成后会返回结构体地指针类型 // Api new函数实例化实例化完成后会返回结构体地指针类型

7
api/client_api/client.go Normal file
View File

@@ -0,0 +1,7 @@
package client_api
import "sync"
type ClientAPI struct{}
var mu sync.Mutex

View File

@@ -0,0 +1,42 @@
package client_api
import (
"github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
"schisandra-cloud-album/common/constant"
"schisandra-cloud-album/common/redis"
"schisandra-cloud-album/common/result"
"schisandra-cloud-album/global"
"schisandra-cloud-album/utils"
)
// GenerateClientId 生成客户端ID
// @Summary 生成客户端ID
// @Description 生成客户端ID
// @Tags 微信公众号
// @Produce json
// @Router /api/oauth/generate_client_id [get]
func (ClientAPI) GenerateClientId(c *gin.Context) {
// 获取客户端IP
ip := utils.GetClientIP(c)
// 加锁
mu.Lock()
defer mu.Unlock()
// 从Redis获取客户端ID
clientId := redis.Get(constant.UserLoginClientRedisKey + ip).Val()
if clientId != "" {
result.OkWithData(clientId, c)
return
}
// 生成新的客户端ID
v1 := uuid.NewV1()
err := redis.Set(constant.UserLoginClientRedisKey+ip, v1.String(), 0).Err()
if err != nil {
global.LOG.Error(err)
return
}
result.OkWithData(v1.String(), c)
return
}

View File

@@ -150,7 +150,6 @@ func (OAuthAPI) GetUserLoginDevice(c *gin.Context) {
os := ua.OS() os := ua.OS()
mobile := ua.Mobile() mobile := ua.Mobile()
mozilla := ua.Mozilla() mozilla := ua.Mozilla()
m := ua.Model()
platform := ua.Platform() platform := ua.Platform()
engine, engineVersion := ua.Engine() engine, engineVersion := ua.Engine()
device := model.ScaAuthUserDevice{ device := model.ScaAuthUserDevice{
@@ -164,7 +163,6 @@ func (OAuthAPI) GetUserLoginDevice(c *gin.Context) {
Mobile: &mobile, Mobile: &mobile,
Bot: &isBot, Bot: &isBot,
Mozilla: &mozilla, Mozilla: &mozilla,
Model: &m,
Platform: &platform, Platform: &platform,
EngineName: &engine, EngineName: &engine,
EngineVersion: &engineVersion, EngineVersion: &engineVersion,

View File

@@ -12,7 +12,6 @@ import (
"github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount/server/handlers/models" "github.com/ArtisanCloud/PowerWeChat/v3/src/officialAccount/server/handlers/models"
ginI18n "github.com/gin-contrib/i18n" ginI18n "github.com/gin-contrib/i18n"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
uuid "github.com/satori/go.uuid"
"github.com/yitter/idgenerator-go/idgen" "github.com/yitter/idgenerator-go/idgen"
"gorm.io/gorm" "gorm.io/gorm"
"schisandra-cloud-album/api/user_api/dto" "schisandra-cloud-album/api/user_api/dto"
@@ -29,36 +28,6 @@ import (
"time" "time"
) )
// GenerateClientId 生成客户端ID
// @Summary 生成客户端ID
// @Description 生成客户端ID
// @Tags 微信公众号
// @Produce json
// @Router /api/oauth/generate_client_id [get]
func (OAuthAPI) GenerateClientId(c *gin.Context) {
// 获取客户端IP
ip := utils.GetClientIP(c)
// 加锁
mu.Lock()
defer mu.Unlock()
// 从Redis获取客户端ID
clientId := redis.Get(constant.UserLoginClientRedisKey + ip).Val()
if clientId != "" {
result.OkWithData(clientId, c)
return
}
// 生成新的客户端ID
v1 := uuid.NewV1()
err := redis.Set(constant.UserLoginClientRedisKey+ip, v1.String(), 0).Err()
if err != nil {
global.LOG.Error(err)
return
}
result.OkWithData(v1.String(), c)
}
// CallbackNotify 微信回调 // CallbackNotify 微信回调
// @Summary 微信回调 // @Summary 微信回调
// @Tags 微信公众号 // @Tags 微信公众号

View File

@@ -68,3 +68,18 @@ func (PermissionAPI) AssignPermissionsToRole(c *gin.Context) {
result.OkWithMessage(ginI18n.MustGetMessage(c, "AssignSuccess"), c) result.OkWithMessage(ginI18n.MustGetMessage(c, "AssignSuccess"), c)
return return
} }
// GetUserPermissions 获取服用权限
func (PermissionAPI) GetUserPermissions(c *gin.Context) {
userId := c.Query("user_id")
if userId == "" {
result.FailWithMessage(ginI18n.MustGetMessage(c, "GetUserFailed"), c)
return
}
data, err := global.Casbin.GetImplicitRolesForUser(userId)
if err != nil {
return
}
result.OkWithData(data, c)
return
}

View File

@@ -154,13 +154,14 @@ func (UserAPI) AccountLogin(c *gin.Context) {
// @Router /api/user/phone_login [post] // @Router /api/user/phone_login [post]
func (UserAPI) PhoneLogin(c *gin.Context) { func (UserAPI) PhoneLogin(c *gin.Context) {
request := dto.PhoneLoginRequest{} request := dto.PhoneLoginRequest{}
err := c.ShouldBindJSON(&request) err := c.ShouldBind(&request)
if err != nil { if err != nil {
result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "ParamsError"), c)
return return
} }
phone := request.Phone phone := request.Phone
captcha := request.Captcha captcha := request.Captcha
autoLogin := request.AutoLogin
if phone == "" || captcha == "" { if phone == "" || captcha == "" {
result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneAndCaptchaNotEmpty"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "PhoneAndCaptchaNotEmpty"), c)
return return
@@ -213,7 +214,7 @@ func (UserAPI) PhoneLogin(c *gin.Context) {
if err != nil { if err != nil {
return err return err
} }
handelUserLogin(addUser, request.AutoLogin, c) handelUserLogin(addUser, autoLogin, c)
return nil return nil
}) })
errChan <- err errChan <- err
@@ -227,24 +228,24 @@ func (UserAPI) PhoneLogin(c *gin.Context) {
return return
} }
} else { } else {
codeChan := make(chan *string) codeChan := make(chan string)
go func() { go func() {
code := redis.Get(constant.UserLoginSmsRedisKey + phone).Val() code := redis.Get(constant.UserLoginSmsRedisKey + phone).Val()
codeChan <- &code codeChan <- code
}() }()
code := <-codeChan code := <-codeChan
close(codeChan) close(codeChan)
if code == nil { if code == "" {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaExpired"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaExpired"), c)
return return
} }
if &captcha != code { if captcha != code {
result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaError"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "CaptchaError"), c)
return return
} }
handelUserLogin(user, request.AutoLogin, c) handelUserLogin(user, autoLogin, c)
} }
} }
@@ -316,7 +317,7 @@ func handelUserLogin(user model.ScaAuthUser, autoLogin bool, c *gin.Context) {
if autoLogin { if autoLogin {
days = 7 * 24 * time.Hour days = 7 * 24 * time.Hour
} else { } else {
days = 24 * time.Hour days = time.Minute * 30
} }
refreshToken, expiresAt := utils.GenerateRefreshToken(utils.RefreshJWTPayload{UserID: user.UID}, days) refreshToken, expiresAt := utils.GenerateRefreshToken(utils.RefreshJWTPayload{UserID: user.UID}, days)
@@ -455,7 +456,6 @@ func getUserLoginDevice(user model.ScaAuthUser, c *gin.Context) bool {
os := ua.OS() os := ua.OS()
mobile := ua.Mobile() mobile := ua.Mobile()
mozilla := ua.Mozilla() mozilla := ua.Mozilla()
m := ua.Model()
platform := ua.Platform() platform := ua.Platform()
engine, engineVersion := ua.Engine() engine, engineVersion := ua.Engine()
@@ -470,7 +470,6 @@ func getUserLoginDevice(user model.ScaAuthUser, c *gin.Context) bool {
Mobile: &mobile, Mobile: &mobile,
Bot: &isBot, Bot: &isBot,
Mozilla: &mozilla, Mozilla: &mozilla,
Model: &m,
Platform: &platform, Platform: &platform,
EngineName: &engine, EngineName: &engine,
EngineVersion: &engineVersion, EngineVersion: &engineVersion,

View File

@@ -8,7 +8,7 @@ p = sub, obj, act
g = _, _ g = _, _
[policy_effect] [policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny)) e = some(where (p.eft == allow))
[matchers] [matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act

View File

@@ -5,37 +5,31 @@ import (
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
gormadapter "github.com/casbin/gorm-adapter/v3" gormadapter "github.com/casbin/gorm-adapter/v3"
"schisandra-cloud-album/global" "schisandra-cloud-album/global"
"sync"
)
var (
once sync.Once
) )
func InitCasbin() { func InitCasbin() {
once.Do(func() { adapter, err := gormadapter.NewAdapterByDBUseTableName(global.DB, global.CONFIG.Casbin.TablePrefix, global.CONFIG.Casbin.TableName)
adapter, err := gormadapter.NewAdapterByDBUseTableName(global.DB, global.CONFIG.Casbin.TablePrefix, global.CONFIG.Casbin.TableName) if err != nil {
if err != nil { global.LOG.Error(err.Error())
global.LOG.Error(err.Error()) panic(err)
panic(err) }
} m, err := model.NewModelFromFile(global.CONFIG.Casbin.ModelPath)
m, err := model.NewModelFromFile(global.CONFIG.Casbin.ModelPath) if err != nil {
if err != nil { global.LOG.Error(err.Error())
global.LOG.Error(err.Error()) panic(err)
panic(err) }
} e, err := casbin.NewCachedEnforcer(m, adapter)
e, err := casbin.NewCachedEnforcer(m, adapter) if err != nil {
if err != nil { global.LOG.Error(err.Error())
global.LOG.Error(err.Error()) panic(err)
panic(err) }
} e.EnableCache(true)
e.EnableCache(true) e.SetExpireTime(60 * 60)
e.SetExpireTime(60 * 60) err = e.LoadPolicy()
err = e.LoadPolicy() if err != nil {
if err != nil { global.LOG.Error(err.Error())
global.LOG.Error(err.Error()) panic(err)
panic(err) }
} global.Casbin = e
global.Casbin = e
})
} }

View File

@@ -56,3 +56,5 @@ InternalError = "internal error!"
RequestError = "request error!" RequestError = "request error!"
AssignFailed = "assign failed!" AssignFailed = "assign failed!"
AssignSuccess = "assign successfully!" AssignSuccess = "assign successfully!"
DuplicateLogin = "duplicate login!"
PermissionDenied = "permission denied!"

View File

@@ -56,4 +56,6 @@ InternalError = "内部错误!"
RequestError = "请求错误!" RequestError = "请求错误!"
AssignFailed = "分配失败!" AssignFailed = "分配失败!"
AssignSuccess = "分配成功!" AssignSuccess = "分配成功!"
DuplicateLogin = "重复登录!"
PermissionDenied = "权限不足!"

View File

@@ -1,27 +1,40 @@
package middleware package middleware
import ( import (
ginI18n "github.com/gin-contrib/i18n"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"schisandra-cloud-album/common/result"
"schisandra-cloud-album/global" "schisandra-cloud-album/global"
) )
func CasbinMiddleware() gin.HandlerFunc { func CasbinMiddleware() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
userId, ok := c.Get("userId") userIdAny, exists := c.Get("userId")
if !ok { if !exists {
global.LOG.Error("casbin middleware: userId not found") global.LOG.Error("casbin middleware: userId not found")
result.FailWithMessage(ginI18n.MustGetMessage(c, "PermissionDenied"), c)
c.Abort() c.Abort()
return return
} }
userId, ok := userIdAny.(*string)
if !ok {
result.FailWithMessage(ginI18n.MustGetMessage(c, "PermissionDenied"), c)
global.LOG.Error("casbin middleware: userId is not string")
c.Abort()
return
}
userIdStr := *userId
method := c.Request.Method method := c.Request.Method
path := c.Request.URL.Path path := c.Request.URL.Path
ok, err := global.Casbin.Enforce(userId.(string), path, method) correct, err := global.Casbin.Enforce(userIdStr, path, method)
if err != nil { if err != nil {
result.FailWithMessage(ginI18n.MustGetMessage(c, "PermissionDenied"), c)
global.LOG.Error("casbin middleware: ", err) global.LOG.Error("casbin middleware: ", err)
c.Abort() c.Abort()
return return
} }
if !ok { if !correct {
result.FailWithMessage(ginI18n.MustGetMessage(c, "PermissionDenied"), c)
c.Abort() c.Abort()
return return
} }

View File

@@ -0,0 +1,31 @@
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()
}
}

View File

@@ -1,35 +1,60 @@
package middleware package middleware
import ( import (
"encoding/json"
ginI18n "github.com/gin-contrib/i18n" ginI18n "github.com/gin-contrib/i18n"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"schisandra-cloud-album/common/constant"
"schisandra-cloud-album/common/redis"
"schisandra-cloud-album/common/result" "schisandra-cloud-album/common/result"
"schisandra-cloud-album/global" "schisandra-cloud-album/global"
"schisandra-cloud-album/utils" "schisandra-cloud-album/utils"
"strings" "strings"
) )
type TokenData struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
ExpiresAt int64 `json:"expires_at"`
UID *string `json:"uid"`
}
func JWTAuthMiddleware() gin.HandlerFunc { func JWTAuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
// 默认双Token放在请求头Authorization的Bearer中并以空格隔开 // 默认双Token放在请求头Authorization的Bearer中并以空格隔开
authHeader := c.GetHeader(global.CONFIG.JWT.HeaderKey) authHeader := c.GetHeader(global.CONFIG.JWT.HeaderKey)
if authHeader == "" { if authHeader == "" {
c.Abort()
result.FailWithMessage(ginI18n.MustGetMessage(c, "AuthVerifyFailed"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "AuthVerifyFailed"), c)
c.Abort()
return return
} }
headerPrefix := global.CONFIG.JWT.HeaderPrefix headerPrefix := global.CONFIG.JWT.HeaderPrefix
accessToken := strings.TrimPrefix(authHeader, headerPrefix+" ") accessToken := strings.TrimPrefix(authHeader, headerPrefix+" ")
if accessToken == "" { if accessToken == "" {
c.Abort()
result.FailWithMessage(ginI18n.MustGetMessage(c, "AuthVerifyFailed"), c) result.FailWithMessage(ginI18n.MustGetMessage(c, "AuthVerifyFailed"), c)
c.Abort()
return return
} }
parseToken, isUpd, err := utils.ParseAccessToken(accessToken) parseToken, isUpd, err := utils.ParseAccessToken(accessToken)
if err != nil || !isUpd { if err != nil || !isUpd {
c.Abort()
result.FailWithCodeAndMessage(401, ginI18n.MustGetMessage(c, "AuthVerifyExpired"), c) result.FailWithCodeAndMessage(401, ginI18n.MustGetMessage(c, "AuthVerifyExpired"), c)
c.Abort()
return
}
token := redis.Get(constant.UserLoginTokenRedisKey + *parseToken.UserID).Val()
tokenResult := TokenData{}
err = json.Unmarshal([]byte(token), &tokenResult)
if err != nil {
result.FailWithMessage(ginI18n.MustGetMessage(c, "AuthVerifyExpired"), c)
c.Abort()
return
}
if tokenResult.AccessToken != accessToken {
result.FailWithCodeAndMessage(403, ginI18n.MustGetMessage(c, "DuplicateLogin"), c)
c.Abort()
return return
} }
c.Set("userId", parseToken.UserID) c.Set("userId", parseToken.UserID)

View File

@@ -22,7 +22,6 @@ type ScaAuthUserDevice struct {
Mobile *bool `gorm:"column:mobile;type:int(11);comment:是否为手机" json:"mobile"` // 是否为手机 Mobile *bool `gorm:"column:mobile;type:int(11);comment:是否为手机" json:"mobile"` // 是否为手机
Bot *bool `gorm:"column:bot;type:int(11);comment:是否为机器人" json:"bot"` // 是否为机器人 Bot *bool `gorm:"column:bot;type:int(11);comment:是否为机器人" json:"bot"` // 是否为机器人
Mozilla *string `gorm:"column:mozilla;type:varchar(10);comment:火狐版本" json:"mozilla"` // 火狐版本 Mozilla *string `gorm:"column:mozilla;type:varchar(10);comment:火狐版本" json:"mozilla"` // 火狐版本
Model *string `gorm:"column:model;type:varchar(20);comment:设备型号" json:"model"` // 设备型号
Platform *string `gorm:"column:platform;type:varchar(20);comment:平台" json:"platform"` // 平台 Platform *string `gorm:"column:platform;type:varchar(20);comment:平台" json:"platform"` // 平台
EngineName *string `gorm:"column:engine_name;type:varchar(20);comment:引擎名称" json:"engine_name"` // 引擎名称 EngineName *string `gorm:"column:engine_name;type:varchar(20);comment:引擎名称" json:"engine_name"` // 引擎名称
EngineVersion *string `gorm:"column:engine_version;type:varchar(20);comment:引擎版本" json:"engine_version"` // 引擎版本 EngineVersion *string `gorm:"column:engine_version;type:varchar(20);comment:引擎版本" json:"engine_version"` // 引擎版本

View File

@@ -0,0 +1,12 @@
package modules
import (
"github.com/gin-gonic/gin"
"schisandra-cloud-album/api"
)
var clientApi = api.Api.ClientApi
func ClientRouter(router *gin.RouterGroup) {
router.GET("/client/generate_client_id", clientApi.GenerateClientId)
}

View File

@@ -12,7 +12,6 @@ func OauthRouter(router *gin.RouterGroup) {
{ {
wechatRouter := group.Group("/wechat") wechatRouter := group.Group("/wechat")
{ {
wechatRouter.GET("/generate_client_id", oauth.GenerateClientId)
wechatRouter.GET("/get_temp_qrcode", oauth.GetTempQrCode) wechatRouter.GET("/get_temp_qrcode", oauth.GetTempQrCode)
//wechatRouter.GET("/callback", oauth.CallbackVerify) //wechatRouter.GET("/callback", oauth.CallbackVerify)
wechatRouter.POST("/callback", oauth.CallbackNotify) wechatRouter.POST("/callback", oauth.CallbackNotify)
@@ -34,5 +33,4 @@ func OauthRouter(router *gin.RouterGroup) {
} }
group.GET("/get_device", oauth.GetUserLoginDevice) group.GET("/get_device", oauth.GetUserLoginDevice)
} }
} }

View File

@@ -9,6 +9,8 @@ var permissionApi = api.Api.PermissionApi
func PermissionRouter(router *gin.RouterGroup) { func PermissionRouter(router *gin.RouterGroup) {
group := router.Group("/auth/permission") group := router.Group("/auth/permission")
//group.Use(middleware.JWTAuthMiddleware()) {
group.POST("/add", permissionApi.AddPermissions) group.POST("/add", permissionApi.AddPermissions)
group.GET("/get_user_permissions", permissionApi.GetUserPermissions)
}
} }

View File

@@ -3,14 +3,15 @@ package modules
import ( import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"schisandra-cloud-album/api" "schisandra-cloud-album/api"
"schisandra-cloud-album/middleware"
) )
var roleApi = api.Api.RoleApi var roleApi = api.Api.RoleApi
func RoleRouter(router *gin.RouterGroup) { func RoleRouter(router *gin.RouterGroup) {
group := router.Group("/auth") group := router.Group("/auth")
group.Use(middleware.JWTAuthMiddleware()) {
group.POST("/role/create", roleApi.CreateRole) group.POST("/role/create", roleApi.CreateRole)
group.POST("/role/add_role_to_user", roleApi.AddRoleToUser) group.POST("/role/add_role_to_user", roleApi.AddRoleToUser)
}
} }

View File

@@ -8,10 +8,10 @@ import (
"schisandra-cloud-album/global" "schisandra-cloud-album/global"
) )
func SwaggerRouter(router *gin.Engine) { func SwaggerRouter(router *gin.RouterGroup) {
docs.SwaggerInfo.BasePath = "" docs.SwaggerInfo.BasePath = ""
docs.SwaggerInfo.Description = global.CONFIG.Swagger.Description docs.SwaggerInfo.Description = global.CONFIG.Swagger.Description
router.GET("/api/doc/*any", gin.BasicAuth(gin.Accounts{ router.GET("/doc/*any", gin.BasicAuth(gin.Accounts{
global.CONFIG.Swagger.User: global.CONFIG.Swagger.Password, global.CONFIG.Swagger.User: global.CONFIG.Swagger.Password,
}), ginSwagger.WrapHandler(swaggerFiles.Handler, func(config *ginSwagger.Config) { }), ginSwagger.WrapHandler(swaggerFiles.Handler, func(config *ginSwagger.Config) {
config.Title = global.CONFIG.Swagger.Title config.Title = global.CONFIG.Swagger.Title

View File

@@ -3,7 +3,6 @@ package modules
import ( import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"schisandra-cloud-album/api" "schisandra-cloud-album/api"
"schisandra-cloud-album/middleware"
) )
var userApi = api.Api.UserApi var userApi = api.Api.UserApi
@@ -16,15 +15,18 @@ func UserRouter(router *gin.RouterGroup) {
userGroup.POST("/phone_login", userApi.PhoneLogin) userGroup.POST("/phone_login", userApi.PhoneLogin)
userGroup.POST("/reset_password", userApi.ResetPassword) userGroup.POST("/reset_password", userApi.ResetPassword)
} }
authGroup := router.Group("auth").Use(middleware.JWTAuthMiddleware()).Use(middleware.CasbinMiddleware())
{
authGroup.GET("/user/list", userApi.GetUserList)
authGroup.GET("/user/query_by_uuid", userApi.QueryUserByUuid)
}
tokenGroup := router.Group("token") tokenGroup := router.Group("token")
{ {
tokenGroup.POST("/refresh", userApi.RefreshHandler) tokenGroup.POST("/refresh", userApi.RefreshHandler)
} }
}
// UserRouterAuth 用户相关路由 有auth接口组需要token验证
func UserRouterAuth(router *gin.RouterGroup) {
authGroup := router.Group("auth")
{
authGroup.GET("/user/list", userApi.GetUserList)
authGroup.GET("/user/query_by_uuid", userApi.QueryUserByUuid)
}
} }

View File

@@ -3,12 +3,15 @@ package router
import ( import (
"github.com/gin-contrib/cors" "github.com/gin-contrib/cors"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"schisandra-cloud-album/api"
"schisandra-cloud-album/global" "schisandra-cloud-album/global"
"schisandra-cloud-album/middleware" "schisandra-cloud-album/middleware"
"schisandra-cloud-album/router/modules" "schisandra-cloud-album/router/modules"
"time" "time"
) )
var oauth = api.Api.OAuthApi
func InitRouter() *gin.Engine { func InitRouter() *gin.Engine {
gin.SetMode(global.CONFIG.System.Env) gin.SetMode(global.CONFIG.System.Env)
router := gin.Default() router := gin.Default()
@@ -18,25 +21,40 @@ func InitRouter() *gin.Engine {
return nil return nil
} }
router.Use(middleware.RateLimitMiddleware(time.Millisecond*100, 20)) // 限流中间件 router.Use(middleware.RateLimitMiddleware(time.Millisecond*100, 20)) // 限流中间件
publicGroup := router.Group("api")
// 跨域设置 // 跨域设置
publicGroup.Use(cors.New(cors.Config{ router.Use(cors.New(cors.Config{
AllowOrigins: []string{global.CONFIG.System.Web}, AllowOrigins: []string{global.CONFIG.System.Web},
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"}, AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"},
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization", "X-CSRF-Token", "Accept-Language"}, AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization", "X-CSRF-Token", "Accept-Language", "X-Request-Id"},
AllowCredentials: true, AllowCredentials: true,
MaxAge: 12 * time.Hour, MaxAge: 12 * time.Hour,
})) }))
// 国际化设置 // 国际化设置
publicGroup.Use(middleware.I18n()) router.Use(middleware.I18n())
publicGroup := router.Group("api") // 不需要鉴权的路由组
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.SwaggerRouter(router) // 注册swagger路由
modules.UserRouter(publicGroup) // 注册鉴权路由
modules.CaptchaRouter(publicGroup) // 注册验证码路由
modules.SmsRouter(publicGroup) // 注册短信验证码路由
modules.OauthRouter(publicGroup) // 注册oauth路由
modules.WebsocketRouter(publicGroup) // 注册websocket路由
modules.RoleRouter(publicGroup) // 注册角色路由
modules.PermissionRouter(publicGroup) // 注册权限路由
return router return router
} }

View File

@@ -34,7 +34,6 @@ func (UserDeviceService) UpdateUserDevice(id int64, userDevice *model.ScaAuthUse
Mobile: userDevice.Mobile, Mobile: userDevice.Mobile,
Bot: userDevice.Bot, Bot: userDevice.Bot,
Mozilla: userDevice.Mozilla, Mozilla: userDevice.Mozilla,
Model: userDevice.Model,
Platform: userDevice.Platform, Platform: userDevice.Platform,
EngineName: userDevice.EngineName, EngineName: userDevice.EngineName,
EngineVersion: userDevice.EngineVersion, EngineVersion: userDevice.EngineVersion,

View File

@@ -33,7 +33,7 @@ func GenerateAccessToken(payload AccessJWTPayload) (string, error) {
claims := AccessJWTClaims{ claims := AccessJWTClaims{
AccessJWTPayload: payload, AccessJWTPayload: payload,
RegisteredClaims: jwt.RegisteredClaims{ RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 2)), ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Minute * 30)),
IssuedAt: jwt.NewNumericDate(time.Now()), IssuedAt: jwt.NewNumericDate(time.Now()),
NotBefore: jwt.NewNumericDate(time.Now()), NotBefore: jwt.NewNumericDate(time.Now()),
}, },