kra/internal/service/system/user.go

601 lines
16 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package system
import (
"context"
"encoding/json"
"fmt"
"kra/internal/biz/system"
"kra/internal/server/middleware"
"kra/pkg/jwt"
"github.com/go-kratos/kratos/v2/errors"
"github.com/go-kratos/kratos/v2/transport/http"
)
// UserService 用户服务
type UserService struct {
uc *system.UserUsecase
jwtPkg *jwt.JWT
}
// NewUserService 创建用户服务
func NewUserService(uc *system.UserUsecase, jwtPkg *jwt.JWT) *UserService {
return &UserService{uc: uc, jwtPkg: jwtPkg}
}
// LoginRequest 登录请求
type LoginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
Captcha string `json:"captcha"`
CaptchaId string `json:"captchaId"`
}
// LoginResponse 登录响应
type LoginResponse struct {
User *UserInfo `json:"user"`
Token string `json:"token"`
ExpiresAt int64 `json:"expiresAt"`
}
// UserInfo 用户信息
type UserInfo struct {
ID uint `json:"id"`
UUID string `json:"uuid"`
Username string `json:"username"`
NickName string `json:"nickName"`
SideMode string `json:"sideMode"`
HeaderImg string `json:"headerImg"`
BaseColor string `json:"baseColor"`
AuthorityId uint `json:"authorityId"`
Phone string `json:"phone"`
Email string `json:"email"`
Enable int `json:"enable"`
OriginSetting json.RawMessage `json:"originSetting,omitempty"`
Authority *AuthorityInfo `json:"authority,omitempty"`
Authorities []*AuthorityInfo `json:"authorities,omitempty"`
}
// AuthorityInfo 角色信息
type AuthorityInfo struct {
AuthorityId uint `json:"authorityId"`
AuthorityName string `json:"authorityName"`
ParentId *uint `json:"parentId,omitempty"`
DefaultRouter string `json:"defaultRouter"`
}
// Login 用户登录
func (s *UserService) Login(ctx context.Context, req *LoginRequest) (*LoginResponse, error) {
user, err := s.uc.Login(ctx, req.Username, req.Password)
if err != nil {
return nil, errors.Unauthorized("LOGIN_FAILED", err.Error())
}
if user.Enable != 1 {
return nil, errors.Forbidden("USER_DISABLED", "用户被禁止登录")
}
// 生成 JWT token
claims := s.jwtPkg.CreateClaims(jwt.BaseClaims{
UUID: user.UUID.String(),
ID: uint(user.ID),
Username: user.Username,
NickName: user.NickName,
AuthorityID: user.AuthorityId,
})
token, err := s.jwtPkg.CreateToken(claims.BaseClaims)
if err != nil {
return nil, errors.InternalServer("TOKEN_ERROR", "生成token失败")
}
return &LoginResponse{
User: toUserInfo(user),
Token: token,
ExpiresAt: claims.ExpiresAt.UnixMilli(),
}, nil
}
// RegisterRequest 注册请求
type RegisterRequest struct {
Username string `json:"username"`
Password string `json:"password"`
NickName string `json:"nickName"`
HeaderImg string `json:"headerImg"`
AuthorityId uint `json:"authorityId"`
AuthorityIds []uint `json:"authorityIds"`
Phone string `json:"phone"`
Email string `json:"email"`
Enable int `json:"enable"`
}
// Register 用户注册
func (s *UserService) Register(ctx context.Context, req *RegisterRequest) (*UserInfo, error) {
user := &system.User{
Username: req.Username,
Password: req.Password,
NickName: req.NickName,
HeaderImg: req.HeaderImg,
AuthorityId: req.AuthorityId,
Phone: req.Phone,
Email: req.Email,
Enable: req.Enable,
}
created, err := s.uc.Register(ctx, user)
if err != nil {
return nil, errors.BadRequest("REGISTER_FAILED", err.Error())
}
return toUserInfo(created), nil
}
// ChangePasswordRequest 修改密码请求
type ChangePasswordRequest struct {
Password string `json:"password"`
NewPassword string `json:"newPassword"`
}
// ChangePassword 修改密码
func (s *UserService) ChangePassword(ctx context.Context, userID uint, req *ChangePasswordRequest) error {
return s.uc.ChangePassword(ctx, userID, req.Password, req.NewPassword)
}
// ResetPasswordRequest 重置密码请求
type ResetPasswordRequest struct {
ID uint `json:"id"`
Password string `json:"password"`
}
// ResetPassword 重置密码
func (s *UserService) ResetPassword(ctx context.Context, req *ResetPasswordRequest) error {
return s.uc.ResetPassword(ctx, req.ID, req.Password)
}
// GetUserInfo 获取用户信息
func (s *UserService) GetUserInfo(ctx context.Context, uuid string) (*UserInfo, error) {
user, err := s.uc.GetUserInfo(ctx, uuid)
if err != nil {
return nil, errors.NotFound("USER_NOT_FOUND", err.Error())
}
return toUserInfo(user), nil
}
// GetUserListRequest 获取用户列表请求
type GetUserListRequest struct {
Page int `json:"page"`
PageSize int `json:"pageSize"`
Username string `json:"username"`
NickName string `json:"nickName"`
Phone string `json:"phone"`
Email string `json:"email"`
}
// GetUserListResponse 获取用户列表响应
type GetUserListResponse struct {
List []*UserInfo `json:"list"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"pageSize"`
}
// GetUserList 获取用户列表
func (s *UserService) GetUserList(ctx context.Context, req *GetUserListRequest) (*GetUserListResponse, error) {
filters := make(map[string]string)
if req.Username != "" {
filters["username"] = req.Username
}
if req.NickName != "" {
filters["nick_name"] = req.NickName
}
if req.Phone != "" {
filters["phone"] = req.Phone
}
if req.Email != "" {
filters["email"] = req.Email
}
users, total, err := s.uc.GetUserList(ctx, req.Page, req.PageSize, filters)
if err != nil {
return nil, errors.InternalServer("LIST_ERROR", err.Error())
}
list := make([]*UserInfo, len(users))
for i, u := range users {
list[i] = toUserInfo(u)
}
return &GetUserListResponse{
List: list,
Total: total,
Page: req.Page,
PageSize: req.PageSize,
}, nil
}
// SetUserInfoRequest 设置用户信息请求(管理员用)
type SetUserInfoRequest struct {
ID uint `json:"id"`
NickName string `json:"nickName"`
HeaderImg string `json:"headerImg"`
Phone string `json:"phone"`
Email string `json:"email"`
Enable int `json:"enable"`
AuthorityIds []uint `json:"authorityIds"`
}
// SetUserInfo 设置用户信息
func (s *UserService) SetUserInfo(ctx context.Context, adminAuthorityID uint, req *SetUserInfoRequest) error {
// 如果提供了AuthorityIds先设置用户角色与GVA保持一致
if len(req.AuthorityIds) > 0 {
if err := s.uc.SetUserAuthorities(ctx, adminAuthorityID, req.ID, req.AuthorityIds); err != nil {
return err
}
}
user := &system.User{
ID: req.ID,
NickName: req.NickName,
HeaderImg: req.HeaderImg,
Phone: req.Phone,
Email: req.Email,
Enable: req.Enable,
}
return s.uc.SetUserInfo(ctx, user)
}
// SetSelfInfoRequest 设置自己信息请求(用户用)
type SetSelfInfoRequest struct {
NickName string `json:"nickName"`
HeaderImg string `json:"headerImg"`
Phone string `json:"phone"`
Email string `json:"email"`
SideMode string `json:"sideMode"`
BaseColor string `json:"baseColor"`
}
// SetSelfInfo 设置自己的信息
func (s *UserService) SetSelfInfo(ctx context.Context, userID uint, req *SetSelfInfoRequest) error {
user := &system.User{
ID: userID,
NickName: req.NickName,
HeaderImg: req.HeaderImg,
Phone: req.Phone,
Email: req.Email,
SideMode: req.SideMode,
BaseColor: req.BaseColor,
}
return s.uc.SetSelfInfo(ctx, user)
}
// SetSelfSetting 设置自己的配置
func (s *UserService) SetSelfSetting(ctx context.Context, userID uint, setting json.RawMessage) error {
return s.uc.SetSelfSetting(ctx, userID, setting)
}
// DeleteUser 删除用户
func (s *UserService) DeleteUser(ctx context.Context, id uint) error {
return s.uc.DeleteUser(ctx, id)
}
// SetUserAuthorityRequest 设置用户角色请求
type SetUserAuthorityRequest struct {
AuthorityId uint `json:"authorityId"`
}
// SetUserAuthorityResponse 设置用户角色响应
type SetUserAuthorityResponse struct {
Token string `json:"token"`
ExpiresAt int64 `json:"expiresAt"`
}
// SetUserAuthority 设置用户角色(切换角色)- 返回新token
func (s *UserService) SetUserAuthority(ctx context.Context, userID uint, uuid string, username string, nickName string, req *SetUserAuthorityRequest) (*SetUserAuthorityResponse, error) {
if err := s.uc.SetUserAuthority(ctx, userID, req.AuthorityId); err != nil {
return nil, err
}
// 生成新的JWT token与GVA保持一致
claims := s.jwtPkg.CreateClaims(jwt.BaseClaims{
UUID: uuid,
ID: userID,
Username: username,
NickName: nickName,
AuthorityID: req.AuthorityId,
})
token, err := s.jwtPkg.CreateToken(claims.BaseClaims)
if err != nil {
return nil, errors.InternalServer("TOKEN_ERROR", "生成token失败")
}
return &SetUserAuthorityResponse{
Token: token,
ExpiresAt: claims.ExpiresAt.UnixMilli(),
}, nil
}
// SetUserAuthoritiesRequest 设置用户多角色请求
type SetUserAuthoritiesRequest struct {
ID uint `json:"id"`
AuthorityIds []uint `json:"authorityIds"`
}
// SetUserAuthorities 设置用户多角色
func (s *UserService) SetUserAuthorities(ctx context.Context, adminAuthorityID uint, req *SetUserAuthoritiesRequest) error {
return s.uc.SetUserAuthorities(ctx, adminAuthorityID, req.ID, req.AuthorityIds)
}
// 转换函数
func toUserInfo(u *system.User) *UserInfo {
info := &UserInfo{
ID: u.ID,
UUID: u.UUID.String(),
Username: u.Username,
NickName: u.NickName,
SideMode: u.SideMode,
HeaderImg: u.HeaderImg,
BaseColor: u.BaseColor,
AuthorityId: u.AuthorityId,
Phone: u.Phone,
Email: u.Email,
Enable: u.Enable,
OriginSetting: u.OriginSetting,
}
if u.Authority != nil {
info.Authority = &AuthorityInfo{
AuthorityId: u.Authority.AuthorityId,
AuthorityName: u.Authority.AuthorityName,
ParentId: u.Authority.ParentId,
DefaultRouter: u.Authority.DefaultRouter,
}
}
if len(u.Authorities) > 0 {
info.Authorities = make([]*AuthorityInfo, len(u.Authorities))
for i, a := range u.Authorities {
info.Authorities[i] = &AuthorityInfo{
AuthorityId: a.AuthorityId,
AuthorityName: a.AuthorityName,
ParentId: a.ParentId,
DefaultRouter: a.DefaultRouter,
}
}
}
return info
}
// RegisterRoutes 注册路由
func (s *UserService) RegisterRoutes(srv *http.Server) {
r := srv.Route("/")
// 公开接口
r.POST("/base/login", s.handleLogin)
// 需要认证的接口
r.POST("/user/register", s.handleRegister)
r.POST("/user/changePassword", s.handleChangePassword)
r.POST("/user/resetPassword", s.handleResetPassword)
r.GET("/user/getUserInfo", s.handleGetUserInfo)
r.POST("/user/getUserList", s.handleGetUserList)
r.PUT("/user/setUserInfo", s.handleSetUserInfo)
r.PUT("/user/setSelfInfo", s.handleSetSelfInfo)
r.PUT("/user/setSelfSetting", s.handleSetSelfSetting)
r.DELETE("/user/deleteUser", s.handleDeleteUser)
r.POST("/user/setUserAuthority", s.handleSetUserAuthority)
r.POST("/user/setUserAuthorities", s.handleSetUserAuthorities)
}
// HTTP Handlers
func (s *UserService) handleLogin(ctx http.Context) error {
var req LoginRequest
if err := ctx.Bind(&req); err != nil {
return err
}
resp, err := s.Login(ctx, &req)
if err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "登录成功",
"data": resp,
})
}
func (s *UserService) handleRegister(ctx http.Context) error {
var req RegisterRequest
if err := ctx.Bind(&req); err != nil {
return err
}
resp, err := s.Register(ctx, &req)
if err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "注册成功",
"data": resp,
})
}
func (s *UserService) handleChangePassword(ctx http.Context) error {
var req ChangePasswordRequest
if err := ctx.Bind(&req); err != nil {
return err
}
userID := middleware.GetUserID(ctx)
if userID == 0 {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
if err := s.ChangePassword(ctx, userID, &req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "修改成功",
})
}
func (s *UserService) handleResetPassword(ctx http.Context) error {
var req ResetPasswordRequest
if err := ctx.Bind(&req); err != nil {
return err
}
if err := s.ResetPassword(ctx, &req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "重置成功",
})
}
func (s *UserService) handleGetUserInfo(ctx http.Context) error {
claims, ok := middleware.GetClaims(ctx)
if !ok {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
resp, err := s.GetUserInfo(ctx, claims.UUID)
if err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "获取成功",
"data": map[string]any{"userInfo": resp},
})
}
func (s *UserService) handleGetUserList(ctx http.Context) error {
var req GetUserListRequest
if err := ctx.Bind(&req); err != nil {
return err
}
resp, err := s.GetUserList(ctx, &req)
if err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "获取成功",
"data": resp,
})
}
func (s *UserService) handleSetUserInfo(ctx http.Context) error {
var req SetUserInfoRequest
if err := ctx.Bind(&req); err != nil {
return err
}
adminAuthorityID := middleware.GetAuthorityID(ctx)
if adminAuthorityID == 0 {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
if err := s.SetUserInfo(ctx, adminAuthorityID, &req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "设置成功",
})
}
func (s *UserService) handleSetSelfInfo(ctx http.Context) error {
var req SetSelfInfoRequest
if err := ctx.Bind(&req); err != nil {
return err
}
userID := middleware.GetUserID(ctx)
if userID == 0 {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
if err := s.SetSelfInfo(ctx, userID, &req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "设置成功",
})
}
func (s *UserService) handleSetSelfSetting(ctx http.Context) error {
var req json.RawMessage
if err := ctx.Bind(&req); err != nil {
return err
}
userID := middleware.GetUserID(ctx)
if userID == 0 {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
if err := s.SetSelfSetting(ctx, userID, req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "设置成功",
})
}
func (s *UserService) handleDeleteUser(ctx http.Context) error {
var req struct {
ID uint `json:"id"`
}
if err := ctx.Bind(&req); err != nil {
return err
}
// 不能删除自己
userID := middleware.GetUserID(ctx)
if userID == req.ID {
return errors.BadRequest("DELETE_SELF", "删除失败, 无法删除自己")
}
if err := s.DeleteUser(ctx, req.ID); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "删除成功",
})
}
func (s *UserService) handleSetUserAuthority(ctx http.Context) error {
var req SetUserAuthorityRequest
if err := ctx.Bind(&req); err != nil {
return err
}
claims, ok := middleware.GetClaims(ctx)
if !ok {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
resp, err := s.SetUserAuthority(ctx, claims.BaseClaims.ID, claims.UUID, claims.Username, claims.NickName, &req)
if err != nil {
return err
}
// 设置响应头与GVA保持一致
ctx.Response().Header().Set("new-token", resp.Token)
ctx.Response().Header().Set("new-expires-at", fmt.Sprintf("%d", resp.ExpiresAt/1000))
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "修改成功",
})
}
func (s *UserService) handleSetUserAuthorities(ctx http.Context) error {
var req SetUserAuthoritiesRequest
if err := ctx.Bind(&req); err != nil {
return err
}
adminAuthorityID := middleware.GetAuthorityID(ctx)
if adminAuthorityID == 0 {
return errors.Unauthorized("UNAUTHORIZED", "请先登录")
}
if err := s.SetUserAuthorities(ctx, adminAuthorityID, &req); err != nil {
return err
}
return ctx.Result(200, map[string]any{
"code": 0,
"msg": "修改成功",
})
}