181 lines
4.6 KiB
Go
181 lines
4.6 KiB
Go
package services
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
auth2 "platform/web/auth"
|
|
client2 "platform/web/domains/client"
|
|
"platform/web/globals/orm"
|
|
m "platform/web/models"
|
|
q "platform/web/queries"
|
|
"time"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
var Auth = &authService{}
|
|
|
|
type authService struct{}
|
|
|
|
// OauthAuthorizationCode 验证授权码
|
|
func (s *authService) OauthAuthorizationCode(ctx context.Context, client *m.Client, code, redirectURI, codeVerifier string) (*auth2.TokenDetails, error) {
|
|
return nil, errors.New("TODO")
|
|
}
|
|
|
|
// OauthClientCredentials 验证客户端凭证
|
|
func (s *authService) OauthClientCredentials(ctx context.Context, client *m.Client, scope ...string) (*auth2.TokenDetails, error) {
|
|
|
|
var clientType = auth2.PayloadTypeFromClientSpec(client2.Spec(client.Spec))
|
|
|
|
var permissions = make(map[string]struct{}, len(scope))
|
|
for _, item := range scope {
|
|
permissions[item] = struct{}{}
|
|
}
|
|
|
|
// 保存会话并返回令牌
|
|
authCtx := auth2.Context{
|
|
Permissions: permissions,
|
|
Payload: auth2.Payload{
|
|
Id: client.ID,
|
|
Type: clientType,
|
|
Name: client.Name,
|
|
},
|
|
}
|
|
|
|
token, err := auth2.CreateSession(ctx, &authCtx, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return token, nil
|
|
}
|
|
|
|
// OauthRefreshToken 验证刷新令牌
|
|
func (s *authService) OauthRefreshToken(ctx context.Context, _ *m.Client, refreshToken string, scope ...[]string) (*auth2.TokenDetails, error) {
|
|
details, err := auth2.RefreshSession(ctx, refreshToken, true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return details, nil
|
|
}
|
|
|
|
// OauthPassword 验证密码
|
|
func (s *authService) OauthPassword(ctx context.Context, _ *m.Client, data *GrantPasswordData, ip, agent string) (*auth2.TokenDetails, error) {
|
|
var user *m.User
|
|
err := q.Q.Transaction(func(tx *q.Query) error {
|
|
|
|
switch data.LoginType {
|
|
case auth2.GrantPasswordPhone:
|
|
// 验证验证码
|
|
err := Verifier.VerifySms(ctx, data.Username, data.Password)
|
|
if err != nil {
|
|
if errors.Is(err, ErrVerifierServiceInvalid) {
|
|
return ErrOauthInvalidRequest
|
|
}
|
|
return err
|
|
}
|
|
|
|
// 查找用户
|
|
user, err =
|
|
tx.User.Where(tx.User.Phone.Eq(data.Username)).Take()
|
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return err
|
|
}
|
|
case auth2.GrantPasswordEmail:
|
|
var err error
|
|
user, err = tx.User.Where(tx.User.Email.Eq(data.Username)).Take()
|
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return err
|
|
}
|
|
case auth2.GrantPasswordSecret:
|
|
var err error
|
|
user, err = tx.User.
|
|
Where(tx.User.Or(
|
|
tx.User.Phone.Eq(data.Username),
|
|
tx.User.Email.Eq(data.Username),
|
|
tx.User.Username.Eq(data.Username),
|
|
)).
|
|
Take()
|
|
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return err
|
|
}
|
|
default:
|
|
return ErrOauthInvalidRequest
|
|
}
|
|
|
|
// 如果用户不存在,初始化用户 todo 初始化默认权限信息
|
|
if user == nil {
|
|
user = &m.User{
|
|
Phone: data.Username,
|
|
Username: data.Username,
|
|
}
|
|
}
|
|
|
|
// 更新用户的登录时间
|
|
user.LastLogin = orm.LocalDateTime(time.Now())
|
|
user.LastLoginHost = ip
|
|
user.LastLoginAgent = agent
|
|
if err := tx.User.Omit(q.User.AdminID).Save(user); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 保存到会话
|
|
authCtx := auth2.Context{
|
|
Payload: auth2.Payload{
|
|
Id: user.ID,
|
|
Type: auth2.PayloadUser,
|
|
Name: user.Name,
|
|
Avatar: user.Avatar,
|
|
},
|
|
}
|
|
|
|
token, err := auth2.CreateSession(ctx, &authCtx, data.Remember)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return token, nil
|
|
}
|
|
|
|
type GrantCodeData struct {
|
|
Code string `json:"code" form:"code"`
|
|
RedirectURI string `json:"redirect_uri" form:"redirect_uri"`
|
|
CodeVerifier string `json:"code_verifier" form:"code_verifier"`
|
|
}
|
|
|
|
type GrantClientData struct {
|
|
}
|
|
|
|
type GrantRefreshData struct {
|
|
RefreshToken string `json:"refresh_token" form:"refresh_token"`
|
|
}
|
|
|
|
type GrantPasswordData struct {
|
|
LoginType auth2.PasswordGrantType `json:"login_type" form:"login_type"`
|
|
Username string `json:"username" form:"username"`
|
|
Password string `json:"password" form:"password"`
|
|
Remember bool `json:"remember" form:"remember"`
|
|
}
|
|
|
|
type AuthServiceError string
|
|
|
|
func (e AuthServiceError) Error() string {
|
|
return string(e)
|
|
}
|
|
|
|
const (
|
|
ErrOauthInvalidRequest = AuthServiceError("invalid_request")
|
|
ErrOauthInvalidClient = AuthServiceError("invalid_client")
|
|
ErrOauthInvalidGrant = AuthServiceError("invalid_grant")
|
|
ErrOauthInvalidScope = AuthServiceError("invalid_scope")
|
|
ErrOauthUnauthorizedClient = AuthServiceError("unauthorized_client")
|
|
ErrOauthUnsupportedGrantType = AuthServiceError("unsupported_grant_type")
|
|
)
|