package auth import ( "errors" "time" "hyapp-admin-server/internal/config" "hyapp-admin-server/internal/model" "hyapp-admin-server/internal/modules/shared" "hyapp-admin-server/internal/repository" authcore "hyapp-admin-server/internal/service" "gorm.io/gorm" ) type AuthFlowService struct { store *repository.Store auth *authcore.AuthService cfg config.Config } type LoginInput struct { Username string Password string IP string UserAgent string } type LoginResult struct { AccessToken string RefreshToken string ExpiresAt time.Time User model.User Permissions []string } func NewService(store *repository.Store, auth *authcore.AuthService, cfg config.Config) *AuthFlowService { return &AuthFlowService{store: store, auth: auth, cfg: cfg} } func (s *AuthFlowService) Login(input LoginInput) (LoginResult, error) { user, err := s.store.FindUserByUsername(input.Username) if err != nil || !authcore.CheckPassword(user.PasswordHash, input.Password) { s.loginLog(input, nil, "failed", "用户名或密码错误") return LoginResult{}, errors.New("用户名或密码错误") } if user.Status != model.UserStatusActive { s.loginLog(input, &user.ID, "failed", "账号不可登录") return LoginResult{}, errors.New("账号不可登录") } permissions := repository.PermissionsForUser(*user) accessToken, expiresAt, err := s.auth.GenerateAccessToken(user.ID, user.Username, permissions) if err != nil { return LoginResult{}, err } refreshToken, refreshHash, err := authcore.NewRefreshToken() if err != nil { return LoginResult{}, err } if err := s.store.CreateRefreshToken(model.RefreshToken{ UserID: user.ID, TokenHash: refreshHash, UserAgent: input.UserAgent, IP: input.IP, ExpiresAt: time.Now().Add(s.cfg.RefreshTokenTTL), }); err != nil { return LoginResult{}, err } _ = s.store.TouchUserLogin(user.ID) s.loginLog(input, &user.ID, "success", "登录成功") return LoginResult{AccessToken: accessToken, RefreshToken: refreshToken, ExpiresAt: expiresAt, User: *user, Permissions: permissions}, nil } func (s *AuthFlowService) Logout(refreshToken string) error { if refreshToken == "" { return nil } return s.store.RevokeRefreshToken(authcore.HashToken(refreshToken)) } func (s *AuthFlowService) Refresh(refreshToken string) (LoginResult, error) { if refreshToken == "" { return LoginResult{}, errors.New("刷新会话不存在") } stored, err := s.store.FindRefreshToken(authcore.HashToken(refreshToken)) if err != nil { return LoginResult{}, errors.New("刷新会话已失效") } user, err := s.store.FindUserByID(stored.UserID) if err != nil || user.Status != model.UserStatusActive { return LoginResult{}, errors.New("账号不可登录") } permissions := repository.PermissionsForUser(*user) accessToken, expiresAt, err := s.auth.GenerateAccessToken(user.ID, user.Username, permissions) if err != nil { return LoginResult{}, err } return LoginResult{AccessToken: accessToken, ExpiresAt: expiresAt, User: *user, Permissions: permissions}, nil } func (s *AuthFlowService) Me(actor shared.Actor) (*model.User, []string, error) { user, err := s.store.FindUserByID(actor.UserID) if err != nil { return nil, nil, err } return user, repository.PermissionsForUser(*user), nil } func (s *AuthFlowService) ChangePassword(actor shared.Actor, oldPassword string, newPassword string) error { user, err := s.store.FindUserByID(actor.UserID) if errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("用户不存在") } if err != nil { return err } if !authcore.CheckPassword(user.PasswordHash, oldPassword) { return errors.New("旧密码不正确") } return s.store.ResetUserPassword(user.ID, newPassword) } func (s *AuthFlowService) loginLog(input LoginInput, userID *uint, status string, message string) { _ = s.store.CreateLoginLog(model.LoginLog{ Username: input.Username, UserID: userID, IP: input.IP, UserAgent: input.UserAgent, Status: status, Message: message, }) }