93 lines
2.8 KiB
Go
93 lines
2.8 KiB
Go
// Package authsvc 是后台登录与当前用户信息的业务逻辑。
|
|
package authsvc
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"time"
|
|
|
|
"portal-mini-go/internal/middleware"
|
|
"portal-mini-go/internal/model/admin"
|
|
"portal-mini-go/internal/pkg/auth"
|
|
"portal-mini-go/internal/pkg/errors"
|
|
"portal-mini-go/internal/pkg/token"
|
|
)
|
|
|
|
// userRepo 是登录与信息所需的用户仓储最小接口(由 repository/admin 实现)。
|
|
type userRepo interface {
|
|
GetByUsername(ctx context.Context, username string) (*admin.User, error)
|
|
GetByID(ctx context.Context, id uint64) (*admin.User, error)
|
|
}
|
|
|
|
// Service 后台认证业务:登录签发 JWT、当前用户信息聚合。
|
|
type Service struct {
|
|
userRepo userRepo
|
|
provider middleware.PermissionProvider
|
|
jwtSecret string
|
|
tokenTTL time.Duration
|
|
}
|
|
|
|
func New(userRepo userRepo, provider middleware.PermissionProvider, jwtSecret string, tokenTTL time.Duration) *Service {
|
|
return &Service{userRepo: userRepo, provider: provider, jwtSecret: jwtSecret, tokenTTL: tokenTTL}
|
|
}
|
|
|
|
// LoginReq 登录请求。
|
|
type LoginReq struct {
|
|
Username string `json:"username" binding:"required"`
|
|
Password string `json:"password" binding:"required"`
|
|
}
|
|
|
|
// Login 校验账号密码,成功返回 JWT。账号不存在 / 密码错误 / 禁用均返回未授权,
|
|
// 避免泄露账号是否存在。
|
|
func (s *Service) Login(ctx context.Context, req LoginReq) (string, error) {
|
|
u, err := s.userRepo.GetByUsername(ctx, req.Username)
|
|
if err != nil {
|
|
return "", errors.ErrUnauthorized
|
|
}
|
|
if u.Status != admin.UserStatusEnabled {
|
|
return "", errors.ErrUnauthorized
|
|
}
|
|
if !auth.VerifyPassword(req.Password, u.PasswordHash) {
|
|
return "", errors.ErrUnauthorized
|
|
}
|
|
return token.Generate(s.jwtSecret, strconv.FormatUint(u.ID, 10), s.tokenTTL)
|
|
}
|
|
|
|
// Info 是当前管理员聚合信息,供前端渲染与鉴权。
|
|
type Info struct {
|
|
ID string `json:"id"`
|
|
Username string `json:"username"`
|
|
Nickname string `json:"nickname"`
|
|
Roles []string `json:"roles"`
|
|
Permissions []string `json:"permissions"`
|
|
Menus []admin.MenuNode `json:"menus"`
|
|
}
|
|
|
|
// Info 返回当前管理员的角色、权限与可见菜单树。
|
|
func (s *Service) Info(ctx context.Context, adminID uint64) (*Info, error) {
|
|
u, err := s.userRepo.GetByID(ctx, adminID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
roles, err := s.provider.RolesOf(ctx, adminID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
perms, err := s.provider.PermissionsOf(ctx, adminID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
menus, err := s.provider.MenuTree(ctx, adminID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &Info{
|
|
ID: strconv.FormatUint(u.ID, 10),
|
|
Username: u.Username,
|
|
Nickname: u.Nickname,
|
|
Roles: roles,
|
|
Permissions: perms,
|
|
Menus: menus,
|
|
}, nil
|
|
}
|