批量优化
This commit is contained in:
1 parent
e3db229f41
commit
aa92ca40a2
79 files changed
+7495
-1104
No files matched your search
@@ -0,0 +1,97 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"server/models"
|
||||
)
|
||||
|
||||
// =============================================================
|
||||
// 移动端免登录票据
|
||||
//
|
||||
// 背景:移动端用「密码直连」拿到的是 client_id=yz-uniapp、user_type=app 的令牌,
|
||||
// Web 端(管理后台)只认自己 localStorage 里 client_id=yz-backend 的令牌,
|
||||
// 两者登录态不共享,导致移动端打开 webview 时又要走一遍统一认证登录。
|
||||
//
|
||||
// 方案:移动端令牌 → 一次性票据 → Web 端令牌。
|
||||
// 票据本身是一次性的短时效凭证,即使泄露也无法二次使用。
|
||||
// =============================================================
|
||||
|
||||
// AppTicketTTL 票据有效期。移动端拿到后应立即跳转,不需要长时效。
|
||||
const AppTicketTTL = 60 * time.Second
|
||||
|
||||
var (
|
||||
ErrAppTicketInvalid = errors.New("登录票据无效")
|
||||
ErrAppTicketUsed = errors.New("登录票据已被使用")
|
||||
ErrAppTicketExpired = errors.New("登录票据已过期")
|
||||
)
|
||||
|
||||
// CreateAppTicket 签发一次性票据
|
||||
func CreateAppTicket(identityID, tid uint64, clientID string) (string, error) {
|
||||
if identityID == 0 {
|
||||
return "", errors.New("身份无效")
|
||||
}
|
||||
b := make([]byte, 32)
|
||||
if _, err := rand.Read(b); err != nil {
|
||||
return "", err
|
||||
}
|
||||
ticket := hex.EncodeToString(b)
|
||||
if clientID == "" {
|
||||
clientID = "yz-backend"
|
||||
}
|
||||
row := &models.AuthAppLoginTicket{
|
||||
Ticket: ticket,
|
||||
IdentityID: identityID,
|
||||
Tid: tid,
|
||||
ClientID: clientID,
|
||||
ExpireAt: time.Now().Add(AppTicketTTL),
|
||||
}
|
||||
if _, err := models.Orm.Insert(row); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return ticket, nil
|
||||
}
|
||||
|
||||
// ConsumeAppTicket 核销一次性票据(CAS 防重放),返回票据携带的身份与租户。
|
||||
func ConsumeAppTicket(ticket string) (*models.AuthAppLoginTicket, error) {
|
||||
ticket = strings.TrimSpace(ticket)
|
||||
if ticket == "" {
|
||||
return nil, ErrAppTicketInvalid
|
||||
}
|
||||
var row models.AuthAppLoginTicket
|
||||
if err := models.Orm.QueryTable(new(models.AuthAppLoginTicket)).
|
||||
Filter("ticket", ticket).One(&row); err != nil {
|
||||
return nil, ErrAppTicketInvalid
|
||||
}
|
||||
if row.UsedAt != nil {
|
||||
return nil, ErrAppTicketUsed
|
||||
}
|
||||
if row.ExpireAt.Before(time.Now()) {
|
||||
return nil, ErrAppTicketExpired
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
affected, err := models.Orm.QueryTable(new(models.AuthAppLoginTicket)).
|
||||
Filter("id", row.ID).
|
||||
Filter("used_at__isnull", true).
|
||||
Update(map[string]interface{}{"used_at": now})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if affected == 0 {
|
||||
return nil, ErrAppTicketUsed
|
||||
}
|
||||
row.UsedAt = &now
|
||||
return &row, nil
|
||||
}
|
||||
|
||||
// PurgeExpiredAppTickets 清理过期票据(防止表无限增长,由调用方定期触发)
|
||||
func PurgeExpiredAppTickets() (int64, error) {
|
||||
return models.Orm.QueryTable(new(models.AuthAppLoginTicket)).
|
||||
Filter("expire_at__lt", time.Now().Add(-24*time.Hour)).
|
||||
Delete()
|
||||
}
|
||||
@@ -70,7 +70,7 @@ func IssueTokens(opt TokenIssue) (*TokenPair, error) {
|
||||
userType := opt.UserType
|
||||
if userType == "" {
|
||||
userType = "backend"
|
||||
if opt.ClientID == "yz-uniapp" {
|
||||
if opt.ClientID == "yz-uniapp" || opt.ClientID == "yz-miniapp" {
|
||||
userType = "app"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user