更新
This commit is contained in:
1 parent
5718a00e31
commit
1850ac640e
226 files changed
+37772
-12071
No files matched your search
+422
-448
@@ -1,448 +1,422 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"server/models"
|
||||
"server/pkg/jwtutil"
|
||||
"server/services"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
type backendAuthLoginRequest struct {
|
||||
TenantName string `json:"tenant_name"`
|
||||
Account string `json:"account"`
|
||||
Password string `json:"password"`
|
||||
Code string `json:"code"`
|
||||
// 极验4验证参数
|
||||
CaptchaID string `json:"captcha_id"`
|
||||
LotNumber string `json:"lot_number"`
|
||||
PassToken string `json:"pass_token"`
|
||||
GenTime string `json:"gen_time"`
|
||||
CaptchaOutput string `json:"captcha_output"`
|
||||
}
|
||||
|
||||
// BackendAuthController backend 端认证控制器
|
||||
type BackendAuthController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (c *BackendAuthController) serveJSON(data map[string]interface{}) {
|
||||
c.Data["json"] = data
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// recordLoginLog 记录登录日志(成功/失败均记录,失败不影响登录流程)
|
||||
func (c *BackendAuthController) recordLoginLog(tid *uint64, userID uint64, account, userName, tenantName, loginType string, status int8, message string) {
|
||||
ip := c.Ctx.Input.IP()
|
||||
userAgent := c.Ctx.Request.UserAgent()
|
||||
RecordLoginLog(tid, userID, account, userName, tenantName, loginType, status, message, ip, userAgent)
|
||||
}
|
||||
|
||||
// LoginBackend backend 登录(需要租户)
|
||||
func (c *BackendAuthController) LoginBackend() {
|
||||
var req backendAuthLoginRequest
|
||||
|
||||
body := c.Ctx.Input.RequestBody
|
||||
if len(body) == 0 {
|
||||
var err error
|
||||
body, err = io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "参数错误"})
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(body) == 0 {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "参数错误"})
|
||||
return
|
||||
}
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "参数错误"})
|
||||
return
|
||||
}
|
||||
|
||||
req.TenantName = strings.TrimSpace(req.TenantName)
|
||||
req.Account = strings.TrimSpace(req.Account)
|
||||
req.Password = strings.TrimSpace(req.Password)
|
||||
if req.TenantName == "" || req.Account == "" || req.Password == "" {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "租户名称、用户名或密码不能为空"})
|
||||
return
|
||||
}
|
||||
|
||||
cfg, _ := models.GetPlatformLoginVerify()
|
||||
if cfg.OpenVerifyEnabled == 1 {
|
||||
if cfg.VerifyType == "geetest4" || cfg.VerifyType == "geetest" {
|
||||
if req.LotNumber == "" || req.PassToken == "" || req.GenTime == "" || req.CaptchaOutput == "" {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "请完成人机验证"})
|
||||
return
|
||||
}
|
||||
// TODO: 集成极验4服务端 SDK 后在这里进行二次校验
|
||||
} else if cfg.VerifyType == "geetest3" {
|
||||
if req.CaptchaOutput == "" {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "请完成人机验证"})
|
||||
return
|
||||
}
|
||||
// TODO: 集成极验3服务端 SDK 后在这里进行二次校验
|
||||
} else if cfg.VerifyType == "sms" || cfg.VerifyType == "email" {
|
||||
if strings.TrimSpace(req.Code) == "" {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "请输入验证码"})
|
||||
return
|
||||
}
|
||||
if err := services.VerifyBackendLoginCode(req.TenantName, req.Account, cfg.VerifyType, req.Code); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
token, loginUser, err := services.BackendLogin(req.TenantName, req.Account, req.Password)
|
||||
if err != nil {
|
||||
c.recordLoginLog(nil, 0, req.Account, "", req.TenantName, "password", 0, err.Error())
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
tid := loginUser.Tid
|
||||
c.recordLoginLog(&tid, loginUser.ID, loginUser.Account, loginUser.Name, req.TenantName, "password", 1, "登录成功")
|
||||
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "登录成功",
|
||||
"data": map[string]interface{}{
|
||||
"token": token,
|
||||
"user": map[string]interface{}{
|
||||
"id": loginUser.ID,
|
||||
"account": loginUser.Account,
|
||||
"name": loginUser.Name,
|
||||
"tid": loginUser.Tid,
|
||||
"tenant_name": loginUser.TenantName,
|
||||
"rid": loginUser.Rid,
|
||||
"avatar": loginUser.Avatar,
|
||||
"role_name": loginUser.RoleName,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// GetCurrentUser 当前登录 backend 用户信息,需 Bearer Token
|
||||
func (c *BackendAuthController) GetCurrentUser() {
|
||||
authHeader := c.Ctx.Request.Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "未登录"})
|
||||
return
|
||||
}
|
||||
authParts := strings.SplitN(authHeader, " ", 2)
|
||||
if len(authParts) != 2 || authParts[0] != "Bearer" {
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "认证信息格式错误"})
|
||||
return
|
||||
}
|
||||
claims, err := jwtutil.ParseToken(authParts[1])
|
||||
if err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "无效的token"})
|
||||
return
|
||||
}
|
||||
if claims.UserType != "backend" && claims.UserType != "app" {
|
||||
c.serveJSON(map[string]interface{}{"code": 403, "msg": "无权访问"})
|
||||
return
|
||||
}
|
||||
|
||||
// 令牌里的 user_id 是认证中心 identity_id,而老表 uid 不在 uid 迁移范围内,
|
||||
// 必须先换算成本租户的老 uid,否则会查不到(甚至按主键误命中他人记录)
|
||||
uid := services.ResolveTenantUID(uint64(claims.TenantId), uint64(claims.UserID))
|
||||
var tenantUser models.SystemTenantUser
|
||||
err = models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("uid", uid).
|
||||
Filter("tid", claims.TenantId).
|
||||
One(&tenantUser)
|
||||
if err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "用户不存在"})
|
||||
return
|
||||
}
|
||||
if tenantUser.Status == 0 {
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "账号已禁用"})
|
||||
return
|
||||
}
|
||||
|
||||
account := ""
|
||||
if tenantUser.Account != nil {
|
||||
account = strings.TrimSpace(*tenantUser.Account)
|
||||
}
|
||||
name := ""
|
||||
if tenantUser.Name != nil {
|
||||
name = strings.TrimSpace(*tenantUser.Name)
|
||||
}
|
||||
|
||||
// 查询当前租户名称
|
||||
tenantName := ""
|
||||
var tenant models.SystemTenant
|
||||
if err := models.Orm.QueryTable(new(models.SystemTenant)).Filter("id", claims.TenantId).One(&tenant); err == nil {
|
||||
tenantName = strings.TrimSpace(tenant.TenantName)
|
||||
}
|
||||
|
||||
// 头像:统一取认证中心身份头像(个人中心上传后写在这里,userinfo 同源)
|
||||
avatar := services.GetIdentityAvatar(tenantUser.Uid)
|
||||
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": map[string]interface{}{
|
||||
// id 统一为认证中心 identity_id,与 /auth/userinfo 保持一致,
|
||||
// 避免同一字段在不同来源(登录回跳 vs 本接口)含义不同
|
||||
"id": claims.UserID,
|
||||
// uid 为老表 yz_system_tenant_user.uid,仅少数按老 uid 存取的场景需要
|
||||
"uid": tenantUser.Uid,
|
||||
"account": account,
|
||||
"name": name,
|
||||
"tid": tenantUser.Tid,
|
||||
"tenant_name": tenantName,
|
||||
"rid": 0,
|
||||
"avatar": avatar,
|
||||
"role_name": "",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// GetCurrentUserProfile 当前登录用户的角色 / 部门 / 职位
|
||||
// GET /backend/getCurrentUserProfile
|
||||
// 返回 department / position(来自员工档案,按登录账号 + 租户匹配);
|
||||
// 若均无,则回退到角色名(role_name)。
|
||||
func (c *BackendAuthController) GetCurrentUserProfile() {
|
||||
authHeader := c.Ctx.Request.Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "未登录"})
|
||||
return
|
||||
}
|
||||
authParts := strings.SplitN(authHeader, " ", 2)
|
||||
if len(authParts) != 2 || authParts[0] != "Bearer" {
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "认证信息格式错误"})
|
||||
return
|
||||
}
|
||||
claims, err := jwtutil.ParseToken(authParts[1])
|
||||
if err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "无效的token"})
|
||||
return
|
||||
}
|
||||
if claims.UserType != "backend" && claims.UserType != "app" {
|
||||
c.serveJSON(map[string]interface{}{"code": 403, "msg": "无权访问"})
|
||||
return
|
||||
}
|
||||
|
||||
// 同上:令牌 user_id 是 identity_id,需换算成本租户的老 uid
|
||||
uid := services.ResolveTenantUID(uint64(claims.TenantId), uint64(claims.UserID))
|
||||
var tenantUser models.SystemTenantUser
|
||||
if err := models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("uid", uid).
|
||||
Filter("tid", claims.TenantId).
|
||||
One(&tenantUser); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "用户不存在"})
|
||||
return
|
||||
}
|
||||
|
||||
account := ""
|
||||
if tenantUser.Account != nil {
|
||||
account = strings.TrimSpace(*tenantUser.Account)
|
||||
}
|
||||
name := ""
|
||||
if tenantUser.Name != nil {
|
||||
name = strings.TrimSpace(*tenantUser.Name)
|
||||
}
|
||||
|
||||
// 角色名:按 group_id 查询本租户下的租户角色(cid=2)
|
||||
roleName := ""
|
||||
if tenantUser.GroupID > 0 {
|
||||
var role models.AdminRole
|
||||
if err := models.Orm.QueryTable(new(models.AdminRole)).
|
||||
Filter("id", tenantUser.GroupID).
|
||||
Filter("cid", 2).
|
||||
Filter("tenant_id", claims.TenantId).
|
||||
One(&role); err == nil {
|
||||
roleName = role.Name
|
||||
}
|
||||
}
|
||||
|
||||
// 部门 / 职位:来自员工档案,按账号 + 租户匹配
|
||||
department := ""
|
||||
position := ""
|
||||
if account != "" {
|
||||
var emp models.BackendEmployee
|
||||
qs := models.Orm.QueryTable(new(models.BackendEmployee)).Filter("account", account)
|
||||
if claims.TenantId > 0 {
|
||||
qs = qs.Filter("tid", int(claims.TenantId))
|
||||
}
|
||||
if err := qs.One(&emp); err == nil {
|
||||
if emp.Department != nil {
|
||||
department = strings.TrimSpace(*emp.Department)
|
||||
}
|
||||
if emp.Position != nil {
|
||||
position = strings.TrimSpace(*emp.Position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 员工档案的 department 字段存的是组织ID,需转换为组织名称展示
|
||||
if department != "" {
|
||||
orgNames := (&BackendEmployeeFileController{}).efOrgNameMap(int(claims.TenantId))
|
||||
department = efOrgNameByID(orgNames, department)
|
||||
}
|
||||
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": map[string]interface{}{
|
||||
"account": account,
|
||||
"name": name,
|
||||
"role_name": roleName,
|
||||
"department": department,
|
||||
"position": position,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// SendLoginCode 发送 backend 登录验证码
|
||||
func (c *BackendAuthController) SendLoginCode() {
|
||||
var req struct {
|
||||
Account string `json:"account"`
|
||||
TenantName string `json:"tenant_name"`
|
||||
Channel string `json:"channel"`
|
||||
}
|
||||
body := c.Ctx.Input.RequestBody
|
||||
if len(body) == 0 {
|
||||
var err error
|
||||
body, err = io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "参数错误"})
|
||||
return
|
||||
}
|
||||
}
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "参数错误"})
|
||||
return
|
||||
}
|
||||
|
||||
cfg, _ := models.GetPlatformLoginVerify()
|
||||
if cfg.OpenVerifyEnabled != 1 {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "当前未开启验证"})
|
||||
return
|
||||
}
|
||||
channel := strings.TrimSpace(req.Channel)
|
||||
if channel == "" {
|
||||
channel = cfg.VerifyType
|
||||
}
|
||||
if channel != "sms" && channel != "email" {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "仅支持短信/邮箱验证码"})
|
||||
return
|
||||
}
|
||||
if err := services.SendBackendLoginCode(req.TenantName, req.Account, channel); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": err.Error()})
|
||||
return
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{"code": 200, "msg": "验证码已发送"})
|
||||
}
|
||||
|
||||
// LoginBySms 手机号验证码登录(占位实现)
|
||||
func (c *BackendAuthController) LoginBySms() {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 501,
|
||||
"msg": "手机号验证码登录暂未实现",
|
||||
})
|
||||
}
|
||||
|
||||
// Logout backend 退出登录(当前为无状态直接返回成功)
|
||||
func (c *BackendAuthController) Logout() {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "退出成功",
|
||||
})
|
||||
}
|
||||
|
||||
// GetGeetest3Infos 获取 backend 极验3.0配置
|
||||
func (c *BackendAuthController) GetGeetest3Infos() {
|
||||
cfg, _ := models.GetPlatformLoginVerify()
|
||||
if cfg.Geetest3ID == nil || cfg.Geetest3Key == nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 404, "msg": "未配置极验3参数"})
|
||||
return
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": map[string]interface{}{
|
||||
"captcha_id": *cfg.Geetest3ID,
|
||||
"captcha_key": *cfg.Geetest3Key,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// GetGeetest4Infos 获取 backend 极验4.0配置
|
||||
func (c *BackendAuthController) GetGeetest4Infos() {
|
||||
cfg, _ := models.GetPlatformLoginVerify()
|
||||
if cfg.Geetest4ID == nil || cfg.Geetest4Key == nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 404, "msg": "未配置极验4参数"})
|
||||
return
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": map[string]interface{}{
|
||||
"captcha_id": *cfg.Geetest4ID,
|
||||
"captcha_key": *cfg.Geetest4Key,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// GetOpenVerify 判断是否开启 backend 登录验证
|
||||
func (c *BackendAuthController) GetOpenVerify() {
|
||||
cfg, _ := models.GetPlatformLoginVerify()
|
||||
openVerify := "0"
|
||||
if cfg.OpenVerifyEnabled == 1 {
|
||||
openVerify = "1"
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "ok",
|
||||
"data": []map[string]string{
|
||||
{
|
||||
"label": "openVerify",
|
||||
"value": openVerify,
|
||||
},
|
||||
{
|
||||
"label": "verifyType",
|
||||
"value": cfg.VerifyType,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Register 注册(占位实现)
|
||||
func (c *BackendAuthController) Register() {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 501,
|
||||
"msg": "注册暂未实现",
|
||||
})
|
||||
}
|
||||
|
||||
// SendRegisterCode 发送注册验证码(占位实现)
|
||||
func (c *BackendAuthController) SendRegisterCode() {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 501,
|
||||
"msg": "发送注册验证码暂未实现",
|
||||
})
|
||||
}
|
||||
|
||||
// ResetPassword 忘记密码重置(占位实现)
|
||||
func (c *BackendAuthController) ResetPassword() {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 501,
|
||||
"msg": "重置密码暂未实现",
|
||||
})
|
||||
}
|
||||
|
||||
// SendResetCode 发送找回密码验证码(占位实现)
|
||||
func (c *BackendAuthController) SendResetCode() {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 501,
|
||||
"msg": "发送找回密码验证码暂未实现",
|
||||
})
|
||||
}
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"server/models"
|
||||
"server/pkg/identity"
|
||||
"server/services"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
type backendAuthLoginRequest struct {
|
||||
TenantName string `json:"tenant_name"`
|
||||
Account string `json:"account"`
|
||||
Password string `json:"password"`
|
||||
Code string `json:"code"`
|
||||
// 极验4验证参数
|
||||
CaptchaID string `json:"captcha_id"`
|
||||
LotNumber string `json:"lot_number"`
|
||||
PassToken string `json:"pass_token"`
|
||||
GenTime string `json:"gen_time"`
|
||||
CaptchaOutput string `json:"captcha_output"`
|
||||
}
|
||||
|
||||
// BackendAuthController backend 端认证控制器
|
||||
type BackendAuthController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (c *BackendAuthController) serveJSON(data map[string]interface{}) {
|
||||
c.Data["json"] = data
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// recordLoginLog 记录登录日志(成功/失败均记录,失败不影响登录流程)
|
||||
func (c *BackendAuthController) recordLoginLog(tid *uint64, userID uint64, account, userName, tenantName, loginType string, status int8, message string) {
|
||||
ip := c.Ctx.Input.IP()
|
||||
userAgent := c.Ctx.Request.UserAgent()
|
||||
RecordLoginLog(tid, userID, account, userName, tenantName, loginType, status, message, ip, userAgent)
|
||||
}
|
||||
|
||||
// LoginBackend backend 登录(需要租户)
|
||||
func (c *BackendAuthController) LoginBackend() {
|
||||
var req backendAuthLoginRequest
|
||||
|
||||
body := c.Ctx.Input.RequestBody
|
||||
if len(body) == 0 {
|
||||
var err error
|
||||
body, err = io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "参数错误"})
|
||||
return
|
||||
}
|
||||
}
|
||||
if len(body) == 0 {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "参数错误"})
|
||||
return
|
||||
}
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "参数错误"})
|
||||
return
|
||||
}
|
||||
|
||||
req.TenantName = strings.TrimSpace(req.TenantName)
|
||||
req.Account = strings.TrimSpace(req.Account)
|
||||
req.Password = strings.TrimSpace(req.Password)
|
||||
if req.TenantName == "" || req.Account == "" || req.Password == "" {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "租户名称、用户名或密码不能为空"})
|
||||
return
|
||||
}
|
||||
|
||||
cfg, _ := models.GetPlatformLoginVerify()
|
||||
if cfg.OpenVerifyEnabled == 1 {
|
||||
if cfg.VerifyType == "geetest4" || cfg.VerifyType == "geetest" {
|
||||
if req.LotNumber == "" || req.PassToken == "" || req.GenTime == "" || req.CaptchaOutput == "" {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "请完成人机验证"})
|
||||
return
|
||||
}
|
||||
// TODO: 集成极验4服务端 SDK 后在这里进行二次校验
|
||||
} else if cfg.VerifyType == "geetest3" {
|
||||
if req.CaptchaOutput == "" {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "请完成人机验证"})
|
||||
return
|
||||
}
|
||||
// TODO: 集成极验3服务端 SDK 后在这里进行二次校验
|
||||
} else if cfg.VerifyType == "sms" || cfg.VerifyType == "email" {
|
||||
if strings.TrimSpace(req.Code) == "" {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "请输入验证码"})
|
||||
return
|
||||
}
|
||||
if err := services.VerifyBackendLoginCode(req.TenantName, req.Account, cfg.VerifyType, req.Code); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
token, loginUser, err := services.BackendLogin(req.TenantName, req.Account, req.Password)
|
||||
if err != nil {
|
||||
c.recordLoginLog(nil, 0, req.Account, "", req.TenantName, "password", 0, err.Error())
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
tid := loginUser.Tid
|
||||
c.recordLoginLog(&tid, loginUser.ID, loginUser.Account, loginUser.Name, req.TenantName, "password", 1, "登录成功")
|
||||
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "登录成功",
|
||||
"data": map[string]interface{}{
|
||||
"token": token,
|
||||
"user": map[string]interface{}{
|
||||
"id": loginUser.ID,
|
||||
"account": loginUser.Account,
|
||||
"name": loginUser.Name,
|
||||
"tid": loginUser.Tid,
|
||||
"tenant_name": loginUser.TenantName,
|
||||
"rid": loginUser.Rid,
|
||||
"avatar": loginUser.Avatar,
|
||||
"role_name": loginUser.RoleName,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// GetCurrentUser 当前登录 backend 用户信息,需 Bearer Token
|
||||
func (c *BackendAuthController) GetCurrentUser() {
|
||||
claims, err := identity.Claims(c.Ctx.Request.Header.Get("Authorization"), identity.EndBackend, identity.EndApp)
|
||||
if err != nil {
|
||||
code := identity.Status(err)
|
||||
c.serveJSON(map[string]interface{}{"code": code, "msg": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// 令牌里的 user_id 是认证中心 identity_id,而老表 uid 不在 uid 迁移范围内,
|
||||
// 必须先换算成本租户的老 uid,否则会查不到(甚至按主键误命中他人记录)
|
||||
uid := services.ResolveTenantUID(uint64(claims.TenantId), uint64(claims.UserID))
|
||||
var tenantUser models.SystemTenantUser
|
||||
err = models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("uid", uid).
|
||||
Filter("tid", claims.TenantId).
|
||||
One(&tenantUser)
|
||||
if err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "用户不存在"})
|
||||
return
|
||||
}
|
||||
if tenantUser.Status == 0 {
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "账号已禁用"})
|
||||
return
|
||||
}
|
||||
|
||||
account := ""
|
||||
if tenantUser.Account != nil {
|
||||
account = strings.TrimSpace(*tenantUser.Account)
|
||||
}
|
||||
name := ""
|
||||
if tenantUser.Name != nil {
|
||||
name = strings.TrimSpace(*tenantUser.Name)
|
||||
}
|
||||
|
||||
// 查询当前租户名称
|
||||
tenantName := ""
|
||||
var tenant models.SystemTenant
|
||||
if err := models.Orm.QueryTable(new(models.SystemTenant)).Filter("id", claims.TenantId).One(&tenant); err == nil {
|
||||
tenantName = strings.TrimSpace(tenant.TenantName)
|
||||
}
|
||||
|
||||
// 头像:统一取认证中心身份头像(个人中心上传后写在这里,userinfo 同源)
|
||||
avatar := services.GetIdentityAvatar(tenantUser.Uid)
|
||||
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": map[string]interface{}{
|
||||
// id 统一为认证中心 identity_id,与 /auth/userinfo 保持一致,
|
||||
// 避免同一字段在不同来源(登录回跳 vs 本接口)含义不同
|
||||
"id": claims.UserID,
|
||||
// uid 为老表 yz_system_tenant_user.uid,仅少数按老 uid 存取的场景需要
|
||||
"uid": tenantUser.Uid,
|
||||
"account": account,
|
||||
"name": name,
|
||||
"tid": tenantUser.Tid,
|
||||
"tenant_name": tenantName,
|
||||
"rid": 0,
|
||||
"avatar": avatar,
|
||||
"role_name": "",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// GetCurrentUserProfile 当前登录用户的角色 / 部门 / 职位
|
||||
// GET /backend/getCurrentUserProfile
|
||||
// 返回 department / position(来自员工档案,按登录账号 + 租户匹配);
|
||||
// 若均无,则回退到角色名(role_name)。
|
||||
func (c *BackendAuthController) GetCurrentUserProfile() {
|
||||
claims, err := identity.Claims(c.Ctx.Request.Header.Get("Authorization"), identity.EndBackend, identity.EndApp)
|
||||
if err != nil {
|
||||
code := identity.Status(err)
|
||||
c.serveJSON(map[string]interface{}{"code": code, "msg": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// 同上:令牌 user_id 是 identity_id,需换算成本租户的老 uid
|
||||
uid := services.ResolveTenantUID(uint64(claims.TenantId), uint64(claims.UserID))
|
||||
var tenantUser models.SystemTenantUser
|
||||
if err := models.Orm.QueryTable(new(models.SystemTenantUser)).
|
||||
Filter("uid", uid).
|
||||
Filter("tid", claims.TenantId).
|
||||
One(&tenantUser); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "用户不存在"})
|
||||
return
|
||||
}
|
||||
|
||||
account := ""
|
||||
if tenantUser.Account != nil {
|
||||
account = strings.TrimSpace(*tenantUser.Account)
|
||||
}
|
||||
name := ""
|
||||
if tenantUser.Name != nil {
|
||||
name = strings.TrimSpace(*tenantUser.Name)
|
||||
}
|
||||
|
||||
// 角色名:按 group_id 查询本租户下的租户角色(cid=2)
|
||||
roleName := ""
|
||||
if tenantUser.GroupID > 0 {
|
||||
var role models.AdminRole
|
||||
if err := models.Orm.QueryTable(new(models.AdminRole)).
|
||||
Filter("id", tenantUser.GroupID).
|
||||
Filter("cid", 2).
|
||||
Filter("tenant_id", claims.TenantId).
|
||||
One(&role); err == nil {
|
||||
roleName = role.Name
|
||||
}
|
||||
}
|
||||
|
||||
// 部门 / 职位:来自员工档案,按账号 + 租户匹配
|
||||
department := ""
|
||||
position := ""
|
||||
if account != "" {
|
||||
var emp models.BackendEmployee
|
||||
qs := models.Orm.QueryTable(new(models.BackendEmployee)).Filter("account", account)
|
||||
if claims.TenantId > 0 {
|
||||
qs = qs.Filter("tid", int(claims.TenantId))
|
||||
}
|
||||
if err := qs.One(&emp); err == nil {
|
||||
if emp.Department != nil {
|
||||
department = strings.TrimSpace(*emp.Department)
|
||||
}
|
||||
if emp.Position != nil {
|
||||
position = strings.TrimSpace(*emp.Position)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 员工档案的 department 字段存的是组织ID,需转换为组织名称展示
|
||||
if department != "" {
|
||||
orgNames := (&BackendEmployeeFileController{}).efOrgNameMap(int(claims.TenantId))
|
||||
department = efOrgNameByID(orgNames, department)
|
||||
}
|
||||
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": map[string]interface{}{
|
||||
"account": account,
|
||||
"name": name,
|
||||
"role_name": roleName,
|
||||
"department": department,
|
||||
"position": position,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// SendLoginCode 发送 backend 登录验证码
|
||||
func (c *BackendAuthController) SendLoginCode() {
|
||||
var req struct {
|
||||
Account string `json:"account"`
|
||||
TenantName string `json:"tenant_name"`
|
||||
Channel string `json:"channel"`
|
||||
}
|
||||
body := c.Ctx.Input.RequestBody
|
||||
if len(body) == 0 {
|
||||
var err error
|
||||
body, err = io.ReadAll(c.Ctx.Request.Body)
|
||||
if err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "参数错误"})
|
||||
return
|
||||
}
|
||||
}
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "参数错误"})
|
||||
return
|
||||
}
|
||||
|
||||
cfg, _ := models.GetPlatformLoginVerify()
|
||||
if cfg.OpenVerifyEnabled != 1 {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "当前未开启验证"})
|
||||
return
|
||||
}
|
||||
channel := strings.TrimSpace(req.Channel)
|
||||
if channel == "" {
|
||||
channel = cfg.VerifyType
|
||||
}
|
||||
if channel != "sms" && channel != "email" {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "仅支持短信/邮箱验证码"})
|
||||
return
|
||||
}
|
||||
if err := services.SendBackendLoginCode(req.TenantName, req.Account, channel); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": err.Error()})
|
||||
return
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{"code": 200, "msg": "验证码已发送"})
|
||||
}
|
||||
|
||||
// LoginBySms 手机号验证码登录(占位实现)
|
||||
func (c *BackendAuthController) LoginBySms() {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 501,
|
||||
"msg": "手机号验证码登录暂未实现",
|
||||
})
|
||||
}
|
||||
|
||||
// Logout backend 退出登录(当前为无状态直接返回成功)
|
||||
func (c *BackendAuthController) Logout() {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "退出成功",
|
||||
})
|
||||
}
|
||||
|
||||
// GetGeetest3Infos 获取 backend 极验3.0配置
|
||||
func (c *BackendAuthController) GetGeetest3Infos() {
|
||||
cfg, _ := models.GetPlatformLoginVerify()
|
||||
if cfg.Geetest3ID == nil || cfg.Geetest3Key == nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 404, "msg": "未配置极验3参数"})
|
||||
return
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": map[string]interface{}{
|
||||
"captcha_id": *cfg.Geetest3ID,
|
||||
"captcha_key": *cfg.Geetest3Key,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// GetGeetest4Infos 获取 backend 极验4.0配置
|
||||
func (c *BackendAuthController) GetGeetest4Infos() {
|
||||
cfg, _ := models.GetPlatformLoginVerify()
|
||||
if cfg.Geetest4ID == nil || cfg.Geetest4Key == nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 404, "msg": "未配置极验4参数"})
|
||||
return
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "success",
|
||||
"data": map[string]interface{}{
|
||||
"captcha_id": *cfg.Geetest4ID,
|
||||
"captcha_key": *cfg.Geetest4Key,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// GetOpenVerify 判断是否开启 backend 登录验证
|
||||
func (c *BackendAuthController) GetOpenVerify() {
|
||||
cfg, _ := models.GetPlatformLoginVerify()
|
||||
openVerify := "0"
|
||||
if cfg.OpenVerifyEnabled == 1 {
|
||||
openVerify = "1"
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"msg": "ok",
|
||||
"data": []map[string]string{
|
||||
{
|
||||
"label": "openVerify",
|
||||
"value": openVerify,
|
||||
},
|
||||
{
|
||||
"label": "verifyType",
|
||||
"value": cfg.VerifyType,
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Register 注册(占位实现)
|
||||
func (c *BackendAuthController) Register() {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 501,
|
||||
"msg": "注册暂未实现",
|
||||
})
|
||||
}
|
||||
|
||||
// SendRegisterCode 发送注册验证码(占位实现)
|
||||
func (c *BackendAuthController) SendRegisterCode() {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 501,
|
||||
"msg": "发送注册验证码暂未实现",
|
||||
})
|
||||
}
|
||||
|
||||
// ResetPassword 忘记密码重置(占位实现)
|
||||
func (c *BackendAuthController) ResetPassword() {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 501,
|
||||
"msg": "重置密码暂未实现",
|
||||
})
|
||||
}
|
||||
|
||||
// SendResetCode 发送找回密码验证码(占位实现)
|
||||
func (c *BackendAuthController) SendResetCode() {
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 501,
|
||||
"msg": "发送找回密码验证码暂未实现",
|
||||
})
|
||||
}
|
||||
Reference in new issue
Block a user