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/user/login.go

115 lines
3.0 KiB
Go

//
// login.go
// Copyright (C) 2025 veypi <i@veypi.com>
// 2025-05-12 17:35
// Distributed under terms of the MIT license.
//
package user
import (
"encoding/base64"
"time"
"github.com/golang-jwt/jwt/v5"
3 weeks ago
"github.com/veypi/vbase/api/sms"
"github.com/veypi/vbase/cfg"
"github.com/veypi/vbase/libs/auth"
"github.com/veypi/vbase/libs/utils"
"github.com/veypi/vbase/models"
"github.com/veypi/vigo"
"github.com/veypi/vigo/contrib/limiter"
"github.com/veypi/vigo/logv"
)
6 months ago
var publicLimits = limiter.NewAdvancedRequestLimiter(time.Minute*5, 20, time.Second*3, nil).Limit
var _ = Router.Post("/login", "用户登录",
vigo.SkipBefore, publicLimits,
userLogin)
type loginOpts struct {
3 weeks ago
UserName *string `json:"username" src:"json" desc:"用户名"`
Code *string `json:"code" src:"json" desc:"密码/授权码"`
6 months ago
3 weeks ago
VerifyCode *string `json:"verify_code" src:"json" desc:"验证码"`
Region *string `json:"region" src:"json" desc:"区域"`
Phone *string `json:"phone" src:"json" desc:"手机号"`
6 months ago
3 weeks ago
Email *string `json:"email" src:"json" desc:"邮箱"`
Type *string `json:"type" src:"json" desc:"登录类型"`
AppID *string `json:"app_id" src:"json" desc:"应用ID"`
Device *string `json:"device" src:"json" desc:"设备信息"`
}
func userLogin(x *vigo.X, opts *loginOpts) (string, error) {
// Implement login logic here
// For example, validate user credentials and return a token
user := &models.User{}
query := cfg.DB()
typ := ""
if opts.Type != nil {
typ = *opts.Type
}
switch typ {
case "phone":
3 weeks ago
query = query.Where("phone = ?", *opts.Region+*opts.Phone)
case "email":
3 weeks ago
query = query.Where("email = ?", *opts.Email)
default:
3 weeks ago
query = query.Where("username = ?", *opts.UserName)
}
err := query.First(user).Error
if err != nil {
return "", vigo.ErrNotFound
}
logv.Info().Str("user", user.ID).Msg("login")
3 weeks ago
if opts.VerifyCode != nil {
err = sms.VerifyCode(*opts.Phone, *opts.VerifyCode, *opts.Region, "signin")
6 months ago
if err != nil {
logv.Warn().Msgf("verify code: %v", err)
return "", vigo.ErrNotAuthorized.WithError(err)
6 months ago
}
} else {
3 weeks ago
code, err := base64.URLEncoding.DecodeString(*opts.Code)
6 months ago
if err != nil {
return "", vigo.ErrArgInvalid.WithArgs("code")
6 months ago
}
6 months ago
ncode, err := utils.AesDecrypt([]byte(user.Code), utils.PKCS7Padding(code, 32), []byte(user.Salt))
if err != nil || string(ncode) != user.ID {
return "", vigo.ErrNotAuthorized
6 months ago
}
}
aid := cfg.Config.ID
if opts.AppID != nil && *opts.AppID != "" {
aid = *opts.AppID
}
data := &models.Token{}
data.UserID = user.ID
data.AppID = aid
data.ExpiredAt = time.Now().Add(time.Hour * 72)
if opts.Device != nil {
data.Device = *opts.Device
}
err = cfg.DB().Create(data).Error
if err != nil {
return "", err
}
claim := &auth.Claims{}
claim.ID = data.ID
claim.UID = user.ID
claim.AID = aid
claim.Name = user.Username
claim.Icon = user.Icon
claim.ExpiresAt = jwt.NewNumericDate(data.ExpiredAt)
claim.IssuedAt = jwt.NewNumericDate(time.Now())
claim.Issuer = cfg.Config.ID
return auth.GenJwt(claim)
}