feat(auth): 添加JWT与Casbin权限认证功能
This commit is contained in:
1 parent
fe86c081f4
commit
16a9f64109
9 files changed
+236
-27
No files matched your search
@@ -11,6 +11,7 @@ type Config struct {
|
||||
Server ServerConfig `mapstructure:"server" yaml:"server"`
|
||||
Database DatabaseConfig `mapstructure:"database" yaml:"database"`
|
||||
Logger LoggerConfig `mapstructure:"logger" yaml:"logger"`
|
||||
Jwt JwtConfig `mapstructure:"logger" yaml:"jwt"`
|
||||
}
|
||||
|
||||
// LoadConfig 读取并解析配置文件
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package conf
|
||||
|
||||
type JwtConfig struct {
|
||||
AccessExpire int `mapstructure:"access_expire" yaml:"access_expire"`
|
||||
RefreshExpire int `mapstructure:"refresh_expire" yaml:"refresh_expire"`
|
||||
AccessSecret string `mapstructure:"access_secret" yaml:"access_secret"`
|
||||
RefreshSecret string `mapstructure:"refresh_secret" yaml:"refresh_secret"`
|
||||
Issuer string `mapstructure:"issuer" yaml:"issuer"`
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"EnGin/internal/global"
|
||||
"fmt"
|
||||
|
||||
"github.com/casbin/casbin/v3"
|
||||
entadapter "github.com/casbin/ent-adapter"
|
||||
)
|
||||
|
||||
// GlobalEnforcer 全局的 Casbin 权限强制执行器
|
||||
var GlobalEnforcer *casbin.Enforcer
|
||||
|
||||
// InitCasbin 初始化 Casbin 并绑定数据库适配器
|
||||
func InitCasbin() error {
|
||||
// 初始化 ent-adapter,它会自动使用您配置的数据库并在库中生成 casbin_rule 表
|
||||
adapter, err := entadapter.NewAdapter(global.Config.Database.Driver, global.Config.Database.Dsn())
|
||||
if err != nil {
|
||||
return fmt.Errorf("初始化 Casbin 数据库适配器失败: %w", err)
|
||||
}
|
||||
|
||||
// 加载本地的配置文件和数据库适配器
|
||||
enforcer, err := casbin.NewEnforcer("configs/casbin.conf", adapter)
|
||||
if err != nil {
|
||||
return fmt.Errorf("创建 Casbin Enforcer 失败: %w", err)
|
||||
}
|
||||
|
||||
// 从数据库加载权限规则
|
||||
if err := enforcer.LoadPolicy(); err != nil {
|
||||
return fmt.Errorf("加载 Casbin 策略失败: %w", err)
|
||||
}
|
||||
|
||||
GlobalEnforcer = enforcer
|
||||
global.Log.Info("Casbin 初始化成功")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package jwts
|
||||
|
||||
import (
|
||||
"EnGin/internal/global"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
type Claims struct {
|
||||
UserID uint `json:"user_id"`
|
||||
Roles []uint `json:"roles"`
|
||||
Nickname string `json:"nickname"`
|
||||
Avatar string `json:"avatar"`
|
||||
Email string `json:"email"`
|
||||
}
|
||||
|
||||
type RefreshClaims struct {
|
||||
UserID uint `json:"user_id"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
type MyClaims struct {
|
||||
Claims
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// GenAccessToken 生成Access Token
|
||||
func GenAccessToken(data Claims) (string, error) {
|
||||
claims := MyClaims{
|
||||
Claims: data,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(global.Config.Jwt.AccessExpire) * time.Hour)),
|
||||
Issuer: global.Config.Jwt.Issuer,
|
||||
},
|
||||
}
|
||||
|
||||
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(global.Config.Jwt.AccessSecret))
|
||||
}
|
||||
|
||||
// GenRefreshToken 生成Refresh Token
|
||||
func GenRefreshToken(userID uint) (string, error) {
|
||||
claims := RefreshClaims{
|
||||
UserID: userID,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(global.Config.Jwt.RefreshExpire) * time.Hour)),
|
||||
Issuer: global.Config.Jwt.Issuer + "_refresh",
|
||||
},
|
||||
}
|
||||
|
||||
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(global.Config.Jwt.RefreshSecret))
|
||||
}
|
||||
|
||||
// CheckAccessToken 验证访问令牌
|
||||
func CheckAccessToken(token string) (*MyClaims, error) {
|
||||
claims, err := parseToken(token, global.Config.Jwt.AccessSecret, &MyClaims{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return claims.(*MyClaims), nil
|
||||
}
|
||||
|
||||
// CheckRefreshToken 验证刷新令牌
|
||||
func CheckRefreshToken(token string) (*RefreshClaims, error) {
|
||||
claims, err := parseToken(token, global.Config.Jwt.RefreshSecret, &RefreshClaims{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return claims.(*RefreshClaims), nil
|
||||
}
|
||||
|
||||
// parseToken 通用token解析函数
|
||||
func parseToken(token, secret string, claims jwt.Claims) (jwt.Claims, error) {
|
||||
tokenObj, err := jwt.ParseWithClaims(token, claims, func(t *jwt.Token) (interface{}, error) {
|
||||
return []byte(secret), nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if tokenObj.Valid {
|
||||
return tokenObj.Claims, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("token无效")
|
||||
}
|
||||
Reference in new issue
Block a user