提交
This commit is contained in:
@@ -3,6 +3,7 @@ package service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"seeyon-filesystem/config"
|
||||
"seeyon-filesystem/dto"
|
||||
@@ -13,6 +14,8 @@ import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
const maxSessionsPerUser = 3 // 每用户最大同时登录数
|
||||
|
||||
// AuthService 认证服务
|
||||
type AuthService struct {
|
||||
userRepo *repository.UserRepository
|
||||
@@ -46,7 +49,11 @@ func (s *AuthService) Login(req *dto.LoginRequest) (*dto.LoginResponse, error) {
|
||||
return nil, errors.New("用户名或密码错误")
|
||||
}
|
||||
|
||||
// 生成JWT Token
|
||||
return s.generateLoginResponse(user, "", "")
|
||||
}
|
||||
|
||||
// generateLoginResponse 生成登录响应(统一处理Token生成和会话创建)
|
||||
func (s *AuthService) generateLoginResponse(user *model.User, device, ip string) (*dto.LoginResponse, error) {
|
||||
token, err := utils.GenerateToken(
|
||||
user.ID,
|
||||
user.Username,
|
||||
@@ -58,6 +65,9 @@ func (s *AuthService) Login(req *dto.LoginRequest) (*dto.LoginResponse, error) {
|
||||
return nil, errors.New("生成Token失败")
|
||||
}
|
||||
|
||||
// 创建会话(限制最大同时登录数)
|
||||
s.createSession(user.ID, token, device, ip)
|
||||
|
||||
return &dto.LoginResponse{
|
||||
Token: token,
|
||||
Username: user.Username,
|
||||
@@ -67,6 +77,59 @@ func (s *AuthService) Login(req *dto.LoginRequest) (*dto.LoginResponse, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Logout 退出登录, 删除当前会话
|
||||
func (s *AuthService) Logout(userID uint64, token string) {
|
||||
config.DB.Where("user_id = ? AND token = ?", userID, token).Delete(&model.UserSession{})
|
||||
}
|
||||
|
||||
// GetSessions 获取用户的活跃会话列表
|
||||
func (s *AuthService) GetSessions(userID uint64) []map[string]interface{} {
|
||||
var sessions []model.UserSession
|
||||
config.DB.Where("user_id = ? AND expires_at > ?", userID, time.Now()).
|
||||
Order("created_at DESC").Find(&sessions)
|
||||
|
||||
result := make([]map[string]interface{}, 0, len(sessions))
|
||||
for _, sess := range sessions {
|
||||
result = append(result, map[string]interface{}{
|
||||
"id": sess.ID,
|
||||
"device": sess.Device,
|
||||
"ip": sess.IP,
|
||||
"created_at": sess.CreatedAt.Format("2006-01-02 15:04:05"),
|
||||
"expires_at": sess.ExpiresAt.Format("2006-01-02 15:04:05"),
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// createSession 创建登录会话, 超过上限时踢掉最旧的
|
||||
func (s *AuthService) createSession(userID uint64, token, device, ip string) {
|
||||
// 清理该用户过期的会话
|
||||
config.DB.Where("user_id = ? AND expires_at < ?", userID, time.Now()).Delete(&model.UserSession{})
|
||||
|
||||
// 统计当前活跃会话数
|
||||
var count int64
|
||||
config.DB.Model(&model.UserSession{}).Where("user_id = ?", userID).Count(&count)
|
||||
|
||||
// 超过上限, 删除最旧的会话
|
||||
if count >= maxSessionsPerUser {
|
||||
var oldest model.UserSession
|
||||
config.DB.Where("user_id = ?", userID).Order("created_at ASC").First(&oldest)
|
||||
if oldest.ID > 0 {
|
||||
config.DB.Delete(&oldest)
|
||||
}
|
||||
}
|
||||
|
||||
// 创建新会话
|
||||
expiresAt := time.Now().Add(time.Duration(config.AppConfig.JWT.Expiration) * time.Hour)
|
||||
config.DB.Create(&model.UserSession{
|
||||
UserID: userID,
|
||||
Token: token,
|
||||
Device: device,
|
||||
IP: ip,
|
||||
ExpiresAt: expiresAt,
|
||||
})
|
||||
}
|
||||
|
||||
// validateAppLogin 校验 appId 登录
|
||||
func (s *AuthService) validateAppLogin(appID string, userID uint64) error {
|
||||
// 1. appId 是否存在且启用
|
||||
@@ -104,25 +167,7 @@ func (s *AuthService) AppLogin(req *dto.AppLoginRequest) (*dto.LoginResponse, er
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 生成JWT Token
|
||||
token, err := utils.GenerateToken(
|
||||
user.ID,
|
||||
user.Username,
|
||||
user.Role,
|
||||
config.AppConfig.JWT.Secret,
|
||||
config.AppConfig.JWT.Expiration,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.New("生成Token失败")
|
||||
}
|
||||
|
||||
return &dto.LoginResponse{
|
||||
Token: token,
|
||||
Username: user.Username,
|
||||
Nickname: user.Nickname,
|
||||
Role: user.Role,
|
||||
MustChangePwd: user.MustChangePwd == 1,
|
||||
}, nil
|
||||
return s.generateLoginResponse(user, "", "")
|
||||
}
|
||||
|
||||
// Register 用户注册
|
||||
@@ -138,6 +183,7 @@ func (s *AuthService) Register(req *dto.RegisterRequest) error {
|
||||
}
|
||||
|
||||
user := &model.User{
|
||||
ID: utils.GenID(),
|
||||
Username: req.Username,
|
||||
Password: hashedPassword,
|
||||
Email: req.Email,
|
||||
|
||||
Reference in New Issue
Block a user