mirror of
https://github.com/skyle1995/NetworkAuth.git
synced 2026-05-25 02:24:05 +08:00
调整 修改认证方式为 OAuth2 鉴权
This commit is contained in:
@@ -47,6 +47,16 @@ func cleanupLogs() {
|
||||
logrus.WithError(err).Error("清理操作日志失败")
|
||||
}
|
||||
|
||||
// 清理刷新令牌(已过期的记录,包括已撤销的旧记录)
|
||||
refreshTokenDays := getSettingInt("refresh_token_cleanup_days", 7)
|
||||
if refreshTokenDays > 0 {
|
||||
if err := GetRefreshTokenService().CleanupExpired(refreshTokenDays); err != nil {
|
||||
logrus.WithError(err).Error("清理刷新令牌失败")
|
||||
} else {
|
||||
logrus.Debugf("清理刷新令牌完成 (保留 %d 天)", refreshTokenDays)
|
||||
}
|
||||
}
|
||||
|
||||
logrus.Debug("日志清理任务执行完成")
|
||||
}
|
||||
|
||||
|
||||
121
services/refresh_token.go
Normal file
121
services/refresh_token.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"NetworkAuth/database"
|
||||
"NetworkAuth/models"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// RefreshTokenService 提供 refreshToken 的持久化、轮换、撤销等业务能力
|
||||
type RefreshTokenService struct{}
|
||||
|
||||
var refreshTokenService = &RefreshTokenService{}
|
||||
|
||||
// GetRefreshTokenService 单例获取
|
||||
func GetRefreshTokenService() *RefreshTokenService {
|
||||
return refreshTokenService
|
||||
}
|
||||
|
||||
// NewJTI 生成新的 jti
|
||||
func (s *RefreshTokenService) NewJTI() string {
|
||||
return uuid.New().String()
|
||||
}
|
||||
|
||||
// NewFamilyID 生成新的 family_id(每次登录都新建)
|
||||
func (s *RefreshTokenService) NewFamilyID() string {
|
||||
return uuid.New().String()
|
||||
}
|
||||
|
||||
// Create 持久化一条 refreshToken 记录
|
||||
// - 登录场景:传入新的 familyID + absolute(now + 绝对过期天数)
|
||||
// - 刷新场景:复用旧 familyID 与旧 absolute,保证滑动续期不能突破上限
|
||||
func (s *RefreshTokenService) Create(jti, familyID, userUUID, userType string,
|
||||
expiresAt, absoluteExpiresAt time.Time, ua, ip string) error {
|
||||
db, err := database.GetDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rec := models.RefreshToken{
|
||||
JTI: jti,
|
||||
FamilyID: familyID,
|
||||
UserUUID: userUUID,
|
||||
UserType: userType,
|
||||
IssuedAt: time.Now(),
|
||||
ExpiresAt: expiresAt,
|
||||
AbsoluteExpiresAt: absoluteExpiresAt,
|
||||
UserAgent: ua,
|
||||
IP: ip,
|
||||
}
|
||||
return db.Create(&rec).Error
|
||||
}
|
||||
|
||||
// FindByJTI 根据 jti 查询
|
||||
func (s *RefreshTokenService) FindByJTI(jti string) (*models.RefreshToken, error) {
|
||||
db, err := database.GetDB()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var rec models.RefreshToken
|
||||
if err := db.Where("jti = ?", jti).First(&rec).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &rec, nil
|
||||
}
|
||||
|
||||
// RevokeFamily 撤销整个 family 下所有未撤销的 refreshToken(用于重用检测/登出)
|
||||
func (s *RefreshTokenService) RevokeFamily(familyID string) error {
|
||||
db, err := database.GetDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return db.Model(&models.RefreshToken{}).
|
||||
Where("family_id = ? AND revoked = ?", familyID, false).
|
||||
Update("revoked", true).Error
|
||||
}
|
||||
|
||||
// RevokeByJTI 撤销单条 refreshToken(一般在轮换时使用 Rotate)
|
||||
func (s *RefreshTokenService) RevokeByJTI(jti string) error {
|
||||
db, err := database.GetDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return db.Model(&models.RefreshToken{}).
|
||||
Where("jti = ?", jti).
|
||||
Update("revoked", true).Error
|
||||
}
|
||||
|
||||
// Rotate 标记旧 jti 为已撤销,并记录被替换为新 jti
|
||||
func (s *RefreshTokenService) Rotate(oldJTI, newJTI string) error {
|
||||
db, err := database.GetDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return db.Model(&models.RefreshToken{}).
|
||||
Where("jti = ?", oldJTI).
|
||||
Updates(map[string]interface{}{
|
||||
"revoked": true,
|
||||
"replaced_by": newJTI,
|
||||
}).Error
|
||||
}
|
||||
|
||||
// CleanupExpired 清理过期且过期时间早于 retentionDays 天前的记录
|
||||
func (s *RefreshTokenService) CleanupExpired(retentionDays int) error {
|
||||
db, err := database.GetDB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cutoff := time.Now().AddDate(0, 0, -retentionDays)
|
||||
return db.Where("expires_at < ?", cutoff).Delete(&models.RefreshToken{}).Error
|
||||
}
|
||||
|
||||
// ErrRefreshNotFound refreshToken 不存在
|
||||
var ErrRefreshNotFound = errors.New("refresh token not found")
|
||||
|
||||
// IsNotFound 判断是否为记录未找到错误
|
||||
func IsNotFound(err error) bool {
|
||||
return errors.Is(err, gorm.ErrRecordNotFound)
|
||||
}
|
||||
@@ -144,11 +144,6 @@ func (s *SettingsService) RefreshCache() {
|
||||
s.loadAllSettings()
|
||||
}
|
||||
|
||||
// GetSessionTimeout 获取会话超时时间(秒)
|
||||
func (s *SettingsService) GetSessionTimeout() int {
|
||||
return s.GetInt("session_timeout", 3600) // 默认1小时
|
||||
}
|
||||
|
||||
// IsMaintenanceMode 检查是否开启维护模式
|
||||
func (s *SettingsService) IsMaintenanceMode() bool {
|
||||
return s.GetBool("maintenance_mode", false)
|
||||
@@ -164,14 +159,36 @@ func (s *SettingsService) GetEncryptionKey() string {
|
||||
return s.GetString("encryption_key", "")
|
||||
}
|
||||
|
||||
// GetJWTRefresh 获取JWT刷新时间(小时)
|
||||
// GetJWTRefresh 已废弃,请使用 GetRefreshTokenExpireDays
|
||||
func (s *SettingsService) GetJWTRefresh() int {
|
||||
return s.GetInt("jwt_refresh", 6)
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetJWTExpire 获取JWT有效期(小时)
|
||||
// GetJWTExpire 获取 accessToken 有效期(小时)
|
||||
func (s *SettingsService) GetJWTExpire() int {
|
||||
return s.GetInt("jwt_expire", 24)
|
||||
v := s.GetInt("jwt_expire", 2)
|
||||
if v <= 0 {
|
||||
return 2
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// GetRefreshTokenExpireDays 获取 refreshToken 有效期(天)
|
||||
func (s *SettingsService) GetRefreshTokenExpireDays() int {
|
||||
v := s.GetInt("refresh_token_expire_days", 7)
|
||||
if v <= 0 {
|
||||
return 7
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// GetSessionAbsoluteExpireDays 获取会话绝对过期上限(天)
|
||||
func (s *SettingsService) GetSessionAbsoluteExpireDays() int {
|
||||
v := s.GetInt("session_absolute_expire_days", 30)
|
||||
if v <= 0 {
|
||||
return 30
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// GetCookieConfig 获取Cookie配置
|
||||
|
||||
Reference in New Issue
Block a user