feat(auth): 添加JWT与Casbin权限认证功能

This commit is contained in:
unclesam committed 2026-07-07 20:24:30 +08:00
1 parent fe86c081f4
commit 16a9f64109
9 files changed
+236 -27

No files matched your search

+1
View File
@@ -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 读取并解析配置文件
+9
View File
@@ -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"`
}
+37
View File
@@ -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
}
+90
View File
@@ -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无效")
}