批量优化
This commit is contained in:
1 parent
e3db229f41
commit
aa92ca40a2
79 files changed
+7495
-1104
No files matched your search
@@ -0,0 +1,243 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"server/models"
|
||||
"server/pkg/jwtutil"
|
||||
authsvc "server/services/auth"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
// =============================================================
|
||||
// 移动端免登录票据(把移动端登录态桥接到 Web 端)
|
||||
//
|
||||
// POST /auth/app-ticket 移动端带 Bearer 令牌 → 签发一次性票据
|
||||
// POST /auth/app-ticket/exchange Web 端带票据 → 核销并换发 Web 端令牌
|
||||
//
|
||||
// 仅用于「移动端已登录 → 打开 Web 端功能页」这一条链路,
|
||||
// 票据一次性 + 60 秒有效,泄露也无法二次使用。
|
||||
// =============================================================
|
||||
|
||||
// AuthAppTicketController 移动端免登录票据
|
||||
type AuthAppTicketController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (c *AuthAppTicketController) serveJSON(data map[string]interface{}) {
|
||||
c.Data["json"] = data
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *AuthAppTicketController) fail(msg string) {
|
||||
c.Ctx.Output.SetStatus(400)
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": msg})
|
||||
}
|
||||
|
||||
// ticketClaims 解析 Bearer 令牌;移动端是 user_type=app,Web 端是 backend
|
||||
func (c *AuthAppTicketController) ticketClaims() (*jwtutil.Claims, error) {
|
||||
header := c.Ctx.Request.Header.Get("Authorization")
|
||||
if header == "" {
|
||||
return nil, fmt.Errorf("未登录")
|
||||
}
|
||||
parts := strings.SplitN(header, " ", 2)
|
||||
if len(parts) != 2 || parts[0] != "Bearer" {
|
||||
return nil, fmt.Errorf("认证信息格式错误")
|
||||
}
|
||||
claims, err := jwtutil.ParseToken(parts[1])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("无效的token")
|
||||
}
|
||||
if claims.UserType != "app" && claims.UserType != "backend" {
|
||||
return nil, fmt.Errorf("无权访问")
|
||||
}
|
||||
return claims, nil
|
||||
}
|
||||
|
||||
// Create POST /auth/app-ticket
|
||||
// 移动端用当前登录态换取一次性票据,Web 端拿票据换自己的令牌。
|
||||
func (c *AuthAppTicketController) Create() {
|
||||
claims, err := c.ticketClaims()
|
||||
if err != nil {
|
||||
c.Ctx.Output.SetStatus(401)
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
var req struct {
|
||||
ClientID string `json:"client_id"`
|
||||
}
|
||||
if body := c.Ctx.Input.RequestBody; len(body) > 0 {
|
||||
_ = json.Unmarshal(body, &req)
|
||||
}
|
||||
// 票据是给 Web 端兑换用的,默认按 Web 端应用签发
|
||||
clientID := strings.TrimSpace(req.ClientID)
|
||||
if clientID == "" {
|
||||
clientID = "yz-backend"
|
||||
}
|
||||
|
||||
tid := uint64(0)
|
||||
if claims.TenantId > 0 {
|
||||
tid = uint64(claims.TenantId)
|
||||
}
|
||||
|
||||
ticket, err := authsvc.CreateAppTicket(uint64(claims.UserID), tid, clientID)
|
||||
if err != nil {
|
||||
c.fail("签发票据失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": map[string]interface{}{
|
||||
"ticket": ticket,
|
||||
"expire_in": int(authsvc.AppTicketTTL / time.Second),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Exchange POST /auth/app-ticket/exchange
|
||||
// Web 端核销票据并换发本端令牌(无鉴权:票据本身即凭证,一次性 + 短时效)。
|
||||
func (c *AuthAppTicketController) Exchange() {
|
||||
body := c.Ctx.Input.RequestBody
|
||||
if len(body) == 0 {
|
||||
body, _ = io.ReadAll(c.Ctx.Request.Body)
|
||||
}
|
||||
var req struct {
|
||||
Ticket string `json:"ticket"`
|
||||
Token string `json:"token"` // 兼容 mp-login 的命名
|
||||
ClientID string `json:"client_id"`
|
||||
}
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
c.fail("参数错误")
|
||||
return
|
||||
}
|
||||
ticket := strings.TrimSpace(req.Ticket)
|
||||
if ticket == "" {
|
||||
ticket = strings.TrimSpace(req.Token)
|
||||
}
|
||||
|
||||
row, err := authsvc.ConsumeAppTicket(ticket)
|
||||
if err != nil {
|
||||
c.fail(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 身份校验:禁用/锁定的账号不签发
|
||||
var identity models.AuthIdentity
|
||||
if err := models.Orm.QueryTable(new(models.AuthIdentity)).
|
||||
Filter("id", row.IdentityID).
|
||||
Filter("delete_time__isnull", true).
|
||||
One(&identity); err != nil {
|
||||
c.fail("账号不存在或已注销")
|
||||
return
|
||||
}
|
||||
if identity.Status != models.AuthIdentityStatusEnabled {
|
||||
c.fail("账号已被禁用或锁定,无法登录")
|
||||
return
|
||||
}
|
||||
|
||||
username := "云泽用户"
|
||||
if identity.Nickname != nil && strings.TrimSpace(*identity.Nickname) != "" {
|
||||
username = strings.TrimSpace(*identity.Nickname)
|
||||
}
|
||||
|
||||
clientID := strings.TrimSpace(req.ClientID)
|
||||
if clientID == "" {
|
||||
clientID = row.ClientID
|
||||
}
|
||||
if clientID == "" {
|
||||
clientID = "yz-backend"
|
||||
}
|
||||
|
||||
// 未确定企业(多企业)时签发待选令牌,由 Web 端展示企业选择
|
||||
tid := row.Tid
|
||||
needChoose := false
|
||||
if tid == 0 {
|
||||
tenants, lerr := authsvc.ListTenantOptions(row.IdentityID)
|
||||
if lerr != nil || len(tenants) == 0 {
|
||||
c.fail("该账号未加入任何企业,无法登录")
|
||||
return
|
||||
}
|
||||
if len(tenants) == 1 {
|
||||
tid = tenants[0].Tid
|
||||
} else {
|
||||
tid = authsvc.PendingTenantID
|
||||
needChoose = true
|
||||
}
|
||||
}
|
||||
|
||||
tokens, terr := c.issueTicketTokens(row.IdentityID, tid, clientID, username, needChoose)
|
||||
if terr != nil {
|
||||
c.fail(terr.Error())
|
||||
return
|
||||
}
|
||||
|
||||
data := map[string]interface{}{
|
||||
"type": "backend",
|
||||
"tokens": tokens,
|
||||
"tid": tid,
|
||||
}
|
||||
if needChoose {
|
||||
tenants, _ := authsvc.ListTenantOptions(row.IdentityID)
|
||||
data["need_choose_tenant"] = true
|
||||
data["tenants"] = tenants
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{"code": 200, "msg": "登录成功", "data": data})
|
||||
}
|
||||
|
||||
// issueTicketTokens 建会话 + 签发令牌 + 登录日志(失败不影响主流程)
|
||||
func (c *AuthAppTicketController) issueTicketTokens(identityID, tid uint64, clientID, username string, needChoose bool) (*authsvc.TokenPair, error) {
|
||||
accessTTL := 0
|
||||
if needChoose {
|
||||
accessTTL = 600 // 待选状态令牌只够用户完成企业选择
|
||||
}
|
||||
sess, serr := authsvc.CreateSession(authsvc.SessionInfo{
|
||||
IdentityID: identityID,
|
||||
Tid: tid,
|
||||
ClientID: clientID,
|
||||
IP: c.Ctx.Input.IP(),
|
||||
UserAgent: c.Ctx.Request.UserAgent(),
|
||||
LoginType: "app_ticket",
|
||||
Amr: "app_ticket",
|
||||
})
|
||||
if serr != nil {
|
||||
return nil, fmt.Errorf("登录失败:%s", serr.Error())
|
||||
}
|
||||
tokens, terr := authsvc.IssueTokens(authsvc.TokenIssue{
|
||||
IdentityID: identityID,
|
||||
Tid: tid,
|
||||
ClientID: clientID,
|
||||
Sid: sess.Sid,
|
||||
Username: username,
|
||||
UserType: "backend", // Web 端业务接口普遍要求 backend
|
||||
Amr: "app_ticket",
|
||||
AccessTTL: accessTTL,
|
||||
})
|
||||
if terr != nil {
|
||||
return nil, fmt.Errorf("签发令牌失败:%s", terr.Error())
|
||||
}
|
||||
|
||||
identityIDCopy := identityID
|
||||
tidCopy := tid
|
||||
amr := "app_ticket"
|
||||
_, _ = models.Orm.Insert(&models.AuthLoginLog{
|
||||
Tid: &tidCopy,
|
||||
IdentityID: &identityIDCopy,
|
||||
UserName: username,
|
||||
ClientID: clientID,
|
||||
LoginType: "app_ticket",
|
||||
Amr: &amr,
|
||||
Status: 1,
|
||||
Message: "移动端票据免登录",
|
||||
IP: c.Ctx.Input.IP(),
|
||||
UserAgent: c.Ctx.Request.UserAgent(),
|
||||
})
|
||||
return tokens, nil
|
||||
}
|
||||
@@ -132,11 +132,14 @@ func (c *AuthLoginController) LoginSubmit() {
|
||||
setSessionCookieForCtx(c.Ctx, result.Tokens.Sid)
|
||||
|
||||
if result.NeedChooseTenant {
|
||||
// 待选令牌必须一并下发:APP / 小程序等无 Cookie 环境的客户端
|
||||
// 只能靠 Bearer 令牌调 /auth/switch-tenant,浏览器端则继续用 yz_sid Cookie。
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "请选择要进入的企业",
|
||||
"need_choose_tenant": true,
|
||||
"tenants": result.Tenants,
|
||||
"tokens": result.Tokens,
|
||||
"sid": result.Tokens.Sid,
|
||||
})
|
||||
return
|
||||
@@ -170,12 +173,16 @@ func (c *AuthLoginController) Tenants() {
|
||||
}
|
||||
|
||||
// SwitchTenant 免密切换企业
|
||||
// POST /auth/switch-tenant { tid, client_id, redirect }
|
||||
// POST /auth/switch-tenant { tid, client_id, redirect, sid }
|
||||
//
|
||||
// sid 来源优先级:yz_sid Cookie → Authorization Bearer 令牌中的 sid → 请求体 sid。
|
||||
// 请求体 sid 供无 Cookie 能力(且尚未拿到 Bearer 令牌)的客户端兜底。
|
||||
func (c *AuthLoginController) SwitchTenant() {
|
||||
var req struct {
|
||||
Tid uint64 `json:"tid"`
|
||||
ClientID string `json:"client_id"`
|
||||
Redirect string `json:"redirect"`
|
||||
Sid string `json:"sid"`
|
||||
}
|
||||
body := c.Ctx.Input.RequestBody
|
||||
if len(body) == 0 {
|
||||
@@ -189,6 +196,9 @@ func (c *AuthLoginController) SwitchTenant() {
|
||||
sid = claims.Sid
|
||||
}
|
||||
}
|
||||
if sid == "" {
|
||||
sid = strings.TrimSpace(req.Sid)
|
||||
}
|
||||
if sid == "" || req.Tid == 0 {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "参数错误"})
|
||||
return
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"server/models"
|
||||
authsvc "server/services/auth"
|
||||
"server/services/wechatmini"
|
||||
|
||||
"github.com/beego/beego/v2/client/orm"
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
"github.com/beego/beego/v2/core/logs"
|
||||
)
|
||||
|
||||
// 小程序登录失败原因(前端按此分支给出不同引导)
|
||||
const (
|
||||
MiniReasonNotConfigured = "not_configured" // 服务端未配置小程序
|
||||
MiniReasonIdentityNotFound = "identity_not_found" // 微信未匹配到云泽账号
|
||||
MiniReasonNoTenant = "no_tenant" // 账号未加入任何企业
|
||||
MiniReasonWechatAPI = "wechat_api_error" // 微信接口报错
|
||||
)
|
||||
|
||||
// idPWechatMini 第三方身份源标识(写入 yz_auth_identity_third.provider)
|
||||
const idPWechatMini = "wechat_mini"
|
||||
|
||||
// AuthWechatMiniController 微信小程序一键登录(统一认证中心)
|
||||
//
|
||||
// 与公众号确认链接登录(/api/wechat/mp/login)不同,小程序端由前端直接
|
||||
// 携带 wx.login 的 code 与 getPhoneNumber 的动态 code 兑换登录态:
|
||||
//
|
||||
// POST /auth/wechat/miniapp/login
|
||||
// { "code": "wx.login的code", "phone_code": "getPhoneNumber的动态code", "client_id": "yz-miniapp" }
|
||||
//
|
||||
// 返回结构与 POST /auth/login 完全一致(tokens / need_choose_tenant / tenants 均在顶层),
|
||||
// 前端可复用同一套「写入令牌 → 选企业 → switch-tenant」流程。
|
||||
type AuthWechatMiniController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (c *AuthWechatMiniController) serveJSON(data map[string]interface{}) {
|
||||
c.Data["json"] = data
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *AuthWechatMiniController) fail(reason string, bizCode int, msg string) {
|
||||
c.Ctx.Output.SetStatus(400)
|
||||
c.serveJSON(map[string]interface{}{"code": bizCode, "msg": msg, "reason": reason})
|
||||
}
|
||||
|
||||
// Config 小程序登录是否可用
|
||||
// GET /auth/wechat/miniapp/config
|
||||
func (c *AuthWechatMiniController) Config() {
|
||||
cfg, err := wechatmini.LoadEnabledConfig()
|
||||
if err != nil {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"data": map[string]interface{}{"enabled": false, "auto_bind": false},
|
||||
})
|
||||
return
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"data": map[string]interface{}{"enabled": true, "auto_bind": cfg.AutoBind},
|
||||
})
|
||||
}
|
||||
|
||||
// Login 小程序一键登录
|
||||
func (c *AuthWechatMiniController) Login() {
|
||||
var req struct {
|
||||
Code string `json:"code"`
|
||||
PhoneCode string `json:"phone_code"`
|
||||
ClientID string `json:"client_id"`
|
||||
}
|
||||
body := c.Ctx.Input.RequestBody
|
||||
if len(body) == 0 {
|
||||
body, _ = io.ReadAll(c.Ctx.Request.Body)
|
||||
}
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
c.fail("", 400, "参数错误")
|
||||
return
|
||||
}
|
||||
req.Code = strings.TrimSpace(req.Code)
|
||||
req.PhoneCode = strings.TrimSpace(req.PhoneCode)
|
||||
req.ClientID = strings.TrimSpace(req.ClientID)
|
||||
if req.ClientID == "" {
|
||||
req.ClientID = "yz-miniapp"
|
||||
}
|
||||
if req.Code == "" {
|
||||
c.fail("", 400, "缺少登录凭证,请重新进入小程序")
|
||||
return
|
||||
}
|
||||
|
||||
cfg, err := wechatmini.LoadEnabledConfig()
|
||||
if err != nil {
|
||||
c.fail(MiniReasonNotConfigured, 400, "小程序登录未开通,请使用账号密码登录")
|
||||
return
|
||||
}
|
||||
|
||||
// code → openid / unionid
|
||||
session, err := wechatmini.Code2Session(cfg, req.Code)
|
||||
if err != nil {
|
||||
msg := err.Error()
|
||||
if hint, ok := wechatmini.ExplainError(err); ok {
|
||||
msg = hint
|
||||
}
|
||||
logs.Warn("[wechat-mini] code 换取 openid 失败: %v", err)
|
||||
c.fail(MiniReasonWechatAPI, 400, msg)
|
||||
return
|
||||
}
|
||||
|
||||
// 定位云泽身份:手机号优先(已通过微信验证),其次查已绑定的小程序 openid
|
||||
var mobile string
|
||||
if req.PhoneCode != "" {
|
||||
phone, perr := wechatmini.GetPhoneNumber(cfg, req.PhoneCode)
|
||||
if perr != nil {
|
||||
// 手机号能力未开通 / code 失效时不阻断:仍尝试按已绑定 openid 登录
|
||||
logs.Warn("[wechat-mini] 获取手机号失败: %v", perr)
|
||||
} else {
|
||||
mobile = strings.TrimSpace(phone.PurePhoneNumber)
|
||||
if mobile == "" {
|
||||
mobile = strings.TrimSpace(phone.PhoneNumber)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
identity, err := c.resolveIdentity(cfg, mobile, session)
|
||||
if err != nil {
|
||||
c.fail(MiniReasonIdentityNotFound, 404, "该微信未绑定云泽账号,请使用手机号一键登录或先注册")
|
||||
return
|
||||
}
|
||||
if identity.Status != models.AuthIdentityStatusEnabled {
|
||||
c.fail("", 403, "账号已被禁用或锁定,无法登录")
|
||||
return
|
||||
}
|
||||
|
||||
// 企业选择:单企业直接进入,多企业签发待选令牌由前端展示选择界面
|
||||
tenants, lerr := authsvc.ListTenantOptions(identity.ID)
|
||||
if lerr != nil || len(tenants) == 0 {
|
||||
c.fail(MiniReasonNoTenant, 403, "该账号未加入任何企业,请联系管理员")
|
||||
return
|
||||
}
|
||||
tid := uint64(0)
|
||||
needChoose := false
|
||||
if len(tenants) == 1 {
|
||||
tid = tenants[0].Tid
|
||||
} else {
|
||||
tid = authsvc.PendingTenantID
|
||||
needChoose = true
|
||||
}
|
||||
|
||||
username := "微信用户"
|
||||
if identity.Nickname != nil && strings.TrimSpace(*identity.Nickname) != "" {
|
||||
username = strings.TrimSpace(*identity.Nickname)
|
||||
} else if identity.Mobile != nil && *identity.Mobile != "" {
|
||||
username = *identity.Mobile
|
||||
}
|
||||
|
||||
tokens, terr := c.issueTokens(identity.ID, tid, req.ClientID, username, needChoose)
|
||||
if terr != nil {
|
||||
c.fail("", 400, terr.Error())
|
||||
return
|
||||
}
|
||||
|
||||
resp := map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "登录成功",
|
||||
"tokens": tokens,
|
||||
"tenants": tenants,
|
||||
"identity": map[string]interface{}{"id": identity.ID, "nickname": username, "mobile": mobileOr(identity)},
|
||||
}
|
||||
if needChoose {
|
||||
resp["need_choose_tenant"] = true
|
||||
resp["sid"] = tokens.Sid
|
||||
}
|
||||
c.serveJSON(resp)
|
||||
}
|
||||
|
||||
// resolveIdentity 定位身份并维护小程序绑定关系。
|
||||
// mobile 非空表示本次已通过微信手机号验证,是可信的强证据,优先采用。
|
||||
func (c *AuthWechatMiniController) resolveIdentity(cfg *wechatmini.Config, mobile string, session *wechatmini.Session) (*models.AuthIdentity, error) {
|
||||
// 1) 手机号命中身份(手机号已由微信验证,属于当前用户的强凭证)
|
||||
if mobile != "" {
|
||||
if identity, err := authsvc.FindIdentityByAccount(mobile); err == nil {
|
||||
c.syncBinding(cfg, identity.ID, session, true)
|
||||
return identity, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 2) 已绑定过该小程序 openid / unionid
|
||||
bind := findMiniBinding(session.OpenID, session.UnionID)
|
||||
if bind == nil {
|
||||
return nil, orm.ErrNoRows
|
||||
}
|
||||
var identity models.AuthIdentity
|
||||
if err := models.Orm.QueryTable(new(models.AuthIdentity)).
|
||||
Filter("id", bind.IdentityID).
|
||||
Filter("delete_time__isnull", true).
|
||||
One(&identity); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &identity, nil
|
||||
}
|
||||
|
||||
// syncBinding 把当前小程序 openid 绑定到该身份。
|
||||
// verified 表示本次带通过了微信手机号验证:此时手机号即身份凭证,
|
||||
// 允许覆盖历史绑定(用户换绑手机号 / 换微信号场景);
|
||||
// 未验证时只允许「新增绑定」,不抢占已绑定到其他身份的 openid。
|
||||
func (c *AuthWechatMiniController) syncBinding(cfg *wechatmini.Config, identityID uint64, session *wechatmini.Session, verified bool) {
|
||||
bind := findMiniBinding(session.OpenID, session.UnionID)
|
||||
if bind != nil && bind.IdentityID == identityID {
|
||||
return
|
||||
}
|
||||
if bind != nil {
|
||||
if !verified {
|
||||
return
|
||||
}
|
||||
_, _ = models.Orm.QueryTable(new(models.AuthIdentityThird)).Filter("id", bind.ID).Delete()
|
||||
}
|
||||
if !verified && !cfg.AutoBind {
|
||||
return
|
||||
}
|
||||
item := &models.AuthIdentityThird{
|
||||
IdentityID: identityID,
|
||||
Provider: idPWechatMini,
|
||||
OpenID: session.OpenID,
|
||||
}
|
||||
if session.UnionID != "" {
|
||||
uid := session.UnionID
|
||||
item.UnionID = &uid
|
||||
}
|
||||
_, _ = models.Orm.Insert(item)
|
||||
}
|
||||
|
||||
// findMiniBinding 按 openid 查绑定,其次按 unionid 查
|
||||
func findMiniBinding(openID, unionID string) *models.AuthIdentityThird {
|
||||
qs := models.Orm.QueryTable(new(models.AuthIdentityThird)).Filter("provider", idPWechatMini)
|
||||
if openID != "" {
|
||||
var bind models.AuthIdentityThird
|
||||
if err := qs.Filter("open_id", openID).One(&bind); err == nil {
|
||||
return &bind
|
||||
}
|
||||
}
|
||||
if unionID != "" {
|
||||
var bind models.AuthIdentityThird
|
||||
if err := qs.Filter("union_id", unionID).One(&bind); err == nil {
|
||||
return &bind
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// issueTokens 建会话并签发 UAC 令牌(含登录日志,失败不影响主流程)
|
||||
func (c *AuthWechatMiniController) issueTokens(identityID, tid uint64, clientID, username string, needChoose bool) (*authsvc.TokenPair, error) {
|
||||
accessTTL := 0
|
||||
if needChoose {
|
||||
accessTTL = 600 // 待选状态令牌只够用户完成企业选择
|
||||
}
|
||||
sess, serr := authsvc.CreateSession(authsvc.SessionInfo{
|
||||
IdentityID: identityID,
|
||||
Tid: tid,
|
||||
ClientID: clientID,
|
||||
IP: c.Ctx.Input.IP(),
|
||||
UserAgent: c.Ctx.Request.UserAgent(),
|
||||
LoginType: "wechat_mini",
|
||||
Amr: "wechat_mini",
|
||||
})
|
||||
if serr != nil {
|
||||
return nil, serr
|
||||
}
|
||||
tokens, terr := authsvc.IssueTokens(authsvc.TokenIssue{
|
||||
IdentityID: identityID,
|
||||
Tid: tid,
|
||||
ClientID: clientID,
|
||||
Sid: sess.Sid,
|
||||
Username: username,
|
||||
UserType: "app",
|
||||
Amr: "wechat_mini",
|
||||
AccessTTL: accessTTL,
|
||||
})
|
||||
if terr != nil {
|
||||
return nil, terr
|
||||
}
|
||||
|
||||
identityIDCopy := identityID
|
||||
tidCopy := tid
|
||||
amr := "wechat_mini"
|
||||
_, _ = models.Orm.Insert(&models.AuthLoginLog{
|
||||
Tid: &tidCopy,
|
||||
IdentityID: &identityIDCopy,
|
||||
UserName: username,
|
||||
ClientID: clientID,
|
||||
LoginType: "wechat_mini",
|
||||
Amr: &amr,
|
||||
Status: 1,
|
||||
Message: "微信小程序一键登录成功",
|
||||
IP: c.Ctx.Input.IP(),
|
||||
UserAgent: c.Ctx.Request.UserAgent(),
|
||||
})
|
||||
return tokens, nil
|
||||
}
|
||||
|
||||
func mobileOr(identity *models.AuthIdentity) string {
|
||||
if identity != nil && identity.Mobile != nil {
|
||||
return *identity.Mobile
|
||||
}
|
||||
return ""
|
||||
}
|
||||
Reference in new issue
Block a user