186 lines
4.9 KiB
Go
186 lines
4.9 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"log/slog"
|
|
"platform/pkg/u"
|
|
"platform/web/core"
|
|
m "platform/web/models"
|
|
q "platform/web/queries"
|
|
s "platform/web/services"
|
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
func authClient(clientId string, clientSecrets ...string) (*m.Client, error) {
|
|
|
|
// 获取客户端信息
|
|
client, err := q.Client.
|
|
Preload(q.Client.Permissions).
|
|
Where(
|
|
q.Client.ClientID.Eq(clientId),
|
|
q.Client.Status.Eq(1)).
|
|
Take()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 检查客户端密钥
|
|
if client.Spec == m.ClientSpecWeb || client.Spec == m.ClientSpecAPI {
|
|
if len(clientSecrets) == 0 {
|
|
return nil, errors.New("客户端密钥错误")
|
|
}
|
|
clientSecret := clientSecrets[0]
|
|
if bcrypt.CompareHashAndPassword([]byte(client.ClientSecret), []byte(clientSecret)) != nil {
|
|
return nil, errors.New("客户端密钥错误")
|
|
}
|
|
}
|
|
|
|
// 组织授权信息(一次性请求)
|
|
return client, nil
|
|
}
|
|
|
|
func authUser(loginType PwdLoginType, username, password string) (user *m.User, err error) {
|
|
switch loginType {
|
|
case PwdLoginByPhone:
|
|
user, err = authUserBySms(q.Q, username, password)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if user == nil {
|
|
user = &m.User{
|
|
Phone: username,
|
|
Username: u.P(username),
|
|
Status: m.UserStatusEnabled,
|
|
}
|
|
}
|
|
case PwdLoginByEmail:
|
|
user, err = authUserByEmail(q.Q, username, password)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
case PwdLoginByPassword:
|
|
user, err = authUserByPassword(q.Q, username, password)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
default:
|
|
return nil, ErrAuthorizeInvalidRequest
|
|
}
|
|
|
|
// 账户状态
|
|
if user.Status == m.UserStatusDisabled {
|
|
return nil, core.NewBizErr("账号已禁用")
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
func authUserBySms(tx *q.Query, username, code string) (*m.User, error) {
|
|
// 验证验证码
|
|
err := s.Verifier.VerifySms(context.Background(), username, code)
|
|
if err != nil {
|
|
return nil, core.NewBizErr("短信认证失败", err)
|
|
}
|
|
|
|
// 查找用户
|
|
return tx.User.Where(tx.User.Phone.Eq(username)).Take()
|
|
}
|
|
|
|
func authUserByEmail(tx *q.Query, username, code string) (*m.User, error) {
|
|
return nil, core.NewServErr("邮箱登录不可用")
|
|
}
|
|
|
|
func authUserByPassword(tx *q.Query, username, password string) (*m.User, error) {
|
|
user, err := tx.User.
|
|
Where(tx.User.Phone.Eq(username)).
|
|
Or(tx.User.Email.Eq(username)).
|
|
Or(tx.User.Username.Eq(username)).
|
|
Take()
|
|
if err != nil {
|
|
slog.Debug("查找用户失败", "error", err)
|
|
return nil, core.NewBizErr("用户不存在或密码错误")
|
|
}
|
|
|
|
// 验证密码
|
|
if user.Password == nil || *user.Password == "" {
|
|
slog.Debug("用户未设置密码", "username", username)
|
|
return nil, core.NewBizErr("用户不存在或密码错误")
|
|
}
|
|
if bcrypt.CompareHashAndPassword([]byte(*user.Password), []byte(password)) != nil {
|
|
slog.Debug("密码验证失败", "username", username)
|
|
return nil, core.NewBizErr("用户不存在或密码错误")
|
|
}
|
|
|
|
return user, nil
|
|
}
|
|
|
|
func authAdmin(loginType PwdLoginType, username, password string) (admin *m.Admin, err error) {
|
|
switch loginType {
|
|
case PwdLoginByPhone, PwdLoginByEmail:
|
|
return nil, core.NewServErr("不支持的登录方式:" + string(loginType))
|
|
case PwdLoginByPassword:
|
|
admin, err = authAdminByPassword(q.Q, username, password)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
default:
|
|
return nil, ErrAuthorizeInvalidRequest
|
|
}
|
|
|
|
// 账户状态
|
|
if admin.Status == m.AdminStatusDisabled {
|
|
return nil, core.NewBizErr("账号已禁用")
|
|
}
|
|
|
|
return admin, nil
|
|
}
|
|
|
|
func authAdminByPassword(tx *q.Query, username, password string) (*m.Admin, error) {
|
|
admin, err := tx.Admin.Where(tx.Admin.Username.Eq(username)).Take()
|
|
if err != nil {
|
|
return nil, core.NewBizErr("账号不存在或密码错误")
|
|
}
|
|
|
|
// 验证密码
|
|
if admin.Password == "" {
|
|
return nil, core.NewBizErr("账号不存在或密码错误")
|
|
}
|
|
if bcrypt.CompareHashAndPassword([]byte(admin.Password), []byte(password)) != nil {
|
|
return nil, core.NewBizErr("账号不存在或密码错误")
|
|
}
|
|
|
|
return admin, nil
|
|
}
|
|
|
|
func adminScopes(admin *m.Admin) ([]string, error) {
|
|
count, err := q.Admin.
|
|
LeftJoin(q.LinkAdminRole, q.LinkAdminRole.AdminID.EqCol(q.Admin.ID)).
|
|
LeftJoin(q.LinkAdminRolePermission, q.LinkAdminRolePermission.RoleID.EqCol(q.LinkAdminRole.RoleID)).
|
|
LeftJoin(q.Permission, q.Permission.ID.EqCol(q.LinkAdminRolePermission.PermissionID)).
|
|
Where(q.Admin.ID.Eq(admin.ID)).
|
|
Select(q.Permission.Name).
|
|
Count()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if count == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
scopes := make([]string, 0, count)
|
|
err = q.Admin.
|
|
LeftJoin(q.LinkAdminRole, q.LinkAdminRole.AdminID.EqCol(q.Admin.ID)).
|
|
LeftJoin(q.LinkAdminRolePermission, q.LinkAdminRolePermission.RoleID.EqCol(q.LinkAdminRole.RoleID)).
|
|
LeftJoin(q.Permission, q.Permission.ID.EqCol(q.LinkAdminRolePermission.PermissionID)).
|
|
Where(q.Admin.ID.Eq(admin.ID)).
|
|
Select(q.Permission.Name).
|
|
Scan(&scopes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return scopes, nil
|
|
}
|