You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OneAuth/api/auth/me.go

157 lines
4.4 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

//
// Copyright (C) 2024 veypi <i@veypi.com>
// 2025-03-04 16:08:06
// Distributed under terms of the MIT license.
//
package auth
import (
baseAuth "github.com/veypi/vbase/auth"
"github.com/veypi/vbase/cfg"
"github.com/veypi/vbase/libs/crypto"
"github.com/veypi/vbase/models"
"github.com/veypi/vigo"
)
// UserPermissionInfo 用户权限信息
type UserPermissionInfo struct {
PermissionID string `json:"permission_id"`
ResourceID string `json:"resource_id"`
}
// UserInfoWithPerms 带权限的用户信息
type UserInfoWithPerms struct {
ID string `json:"id"`
Username string `json:"username"`
Nickname string `json:"nickname"`
Email *string `json:"email"`
Avatar string `json:"avatar"`
Permissions []UserPermissionInfo `json:"permissions"`
Roles []string `json:"roles"`
}
// me 获取当前用户信息
func me(x *vigo.X) (*UserInfoWithPerms, error) {
userID := baseAuth.VBaseAuth.UserID(x)
if userID == "" {
return nil, vigo.ErrUnauthorized
}
var user models.User
if err := cfg.DB().First(&user, "id = ?", userID).Error; err != nil {
return nil, vigo.ErrNotFound
}
orgID := baseAuth.VBaseAuth.OrgID(x)
// 获取用户权限列表
perms, err := baseAuth.VBaseAuth.ListUserPermissions(x.Context(), userID, orgID)
if err != nil {
return nil, vigo.ErrInternalServer.WithError(err)
}
// 转换权限格式 (Vigo 接口返回 vigoauth.UserPermission需要转换回 PermissionID 格式)
userPerms := make([]UserPermissionInfo, 0, len(perms))
for _, p := range perms {
// 从 Resource 构造 PermissionID格式为 vb:resource:*
permissionID := "vb:" + p.Resource + ":*"
userPerms = append(userPerms, UserPermissionInfo{
PermissionID: permissionID,
ResourceID: p.ResourceID,
})
}
// 获取用户角色 (仅全局角色)
roles := make([]string, 0)
cfg.DB().Model(&models.UserRole{}).
Joins("JOIN roles ON user_roles.role_id = roles.id").
Where("user_roles.user_id = ? AND user_roles.org_id IS NULL", userID).
Pluck("roles.code", &roles)
return &UserInfoWithPerms{
ID: user.ID,
Username: user.Username,
Nickname: user.Nickname,
Email: user.Email,
Avatar: user.Avatar,
Permissions: userPerms,
Roles: roles,
}, nil
}
// UpdateMeRequest 更新自己请求
type UpdateMeRequest struct {
Nickname *string `json:"nickname,omitempty" src:"json" desc:"昵称"`
Avatar *string `json:"avatar,omitempty" src:"json" desc:"头像"`
Email *string `json:"email,omitempty" src:"json" desc:"邮箱"`
}
// updateMe 更新当前用户信息
func updateMe(x *vigo.X, req *UpdateMeRequest) (*UserInfoWithPerms, error) {
userID := baseAuth.VBaseAuth.UserID(x)
if userID == "" {
return nil, vigo.ErrUnauthorized
}
updates := make(map[string]any)
if req.Nickname != nil {
updates["nickname"] = *req.Nickname
}
if req.Avatar != nil {
updates["avatar"] = *req.Avatar
}
if req.Email != nil {
// 检查邮箱是否被其他用户使用
var count int64
cfg.DB().Model(&models.User{}).Where("email = ? AND id != ?", *req.Email, userID).Count(&count)
if count > 0 {
return nil, vigo.ErrInvalidArg.WithString("email already exists")
}
updates["email"] = *req.Email
}
if err := cfg.DB().Model(&models.User{}).Where("id = ?", userID).Updates(updates).Error; err != nil {
return nil, vigo.ErrInternalServer.WithError(err)
}
return me(x)
}
// ChangePasswordRequest 修改密码请求
type ChangePasswordRequest struct {
OldPassword string `json:"old_password" src:"json" desc:"旧密码"`
NewPassword string `json:"new_password" src:"json" desc:"新密码"`
}
// changePassword 修改密码
func changePassword(x *vigo.X, req *ChangePasswordRequest) error {
userID := baseAuth.VBaseAuth.UserID(x)
if userID == "" {
return vigo.ErrUnauthorized
}
var user models.User
if err := cfg.DB().First(&user, "id = ?", userID).Error; err != nil {
return vigo.ErrNotFound
}
// 验证旧密码
if !crypto.VerifyPassword(req.OldPassword, user.Password) {
return vigo.ErrInvalidArg.WithString("old password is incorrect")
}
// 哈希新密码
hashedPassword, err := crypto.HashPassword(req.NewPassword, 12)
if err != nil {
return vigo.ErrInternalServer.WithError(err)
}
// 更新密码
if err := cfg.DB().Model(&user).Update("password", hashedPassword).Error; err != nil {
return vigo.ErrInternalServer.WithError(err)
}
return nil
}