批量修复问题
This commit is contained in:
parent
4d6210ccf8
commit
d62872cc6c
@ -24,23 +24,72 @@ type menuPayload struct {
|
|||||||
Sort *int64 `json:"sort"`
|
Sort *int64 `json:"sort"`
|
||||||
Status *int8 `json:"status"`
|
Status *int8 `json:"status"`
|
||||||
IsVisible *int8 `json:"is_visible"`
|
IsVisible *int8 `json:"is_visible"`
|
||||||
IsPlatform *int8 `json:"is_platform"`
|
Views []int `json:"views"`
|
||||||
Type *int8 `json:"type"`
|
Type *int8 `json:"type"`
|
||||||
Permission *string `json:"permission"`
|
Permission *string `json:"permission"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseViews(raw *string) []int {
|
||||||
|
if raw == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
s := strings.TrimSpace(*raw)
|
||||||
|
if s == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var arr []int
|
||||||
|
if err := json.Unmarshal([]byte(s), &arr); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasView(arr []int, v int) bool {
|
||||||
|
for _, n := range arr {
|
||||||
|
if n == v {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func viewsJSON(views []int) string {
|
||||||
|
// 默认:平台端显示
|
||||||
|
if len(views) == 0 {
|
||||||
|
views = []int{1}
|
||||||
|
}
|
||||||
|
b, _ := json.Marshal(views)
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterMenusByView(menus []models.SystemMenu, v int) []models.SystemMenu {
|
||||||
|
out := make([]models.SystemMenu, 0, len(menus))
|
||||||
|
for _, m := range menus {
|
||||||
|
views := parseViews(m.Views)
|
||||||
|
// 兼容旧数据:views 为空时,平台端菜单默认可见(保持旧 is_platform=1 的常见默认体验)
|
||||||
|
// 租户端不做默认放行,避免把未迁移数据误暴露到租户端。
|
||||||
|
if v == 1 && len(views) == 0 {
|
||||||
|
out = append(out, m)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if hasView(views, v) {
|
||||||
|
out = append(out, m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// GetMenu 获取指定用户可见的菜单列表(简化版:当前先忽略用户权限,返回全部启用且平台端菜单)
|
// GetMenu 获取指定用户可见的菜单列表(简化版:当前先忽略用户权限,返回全部启用且平台端菜单)
|
||||||
// 路由示例:GET /platform/menu/1
|
// 路由示例:GET /platform/menu/1
|
||||||
func (c *AdminMenuController) GetMenu() {
|
func (c *AdminMenuController) GetMenu() {
|
||||||
// 从路由参数中解析用户 ID,占位保留,方便后续按用户权限过滤
|
// 从路由参数中解析用户 ID,占位保留,方便后续按用户权限过滤
|
||||||
_ = c.Ctx.Input.Param(":id")
|
_ = c.Ctx.Input.Param(":id")
|
||||||
|
|
||||||
// 查询所有启用且标记为平台端的菜单
|
// 查询所有启用菜单,再按 views 过滤平台端可见
|
||||||
var menus []models.SystemMenu
|
var menus []models.SystemMenu
|
||||||
qs := models.Orm.
|
qs := models.Orm.
|
||||||
QueryTable(new(models.SystemMenu)).
|
QueryTable(new(models.SystemMenu)).
|
||||||
Filter("status", 1).
|
Filter("status", 1)
|
||||||
Filter("is_platform", 1)
|
|
||||||
_, err := qs.All(&menus)
|
_, err := qs.All(&menus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Data["json"] = map[string]interface{}{
|
c.Data["json"] = map[string]interface{}{
|
||||||
@ -51,6 +100,7 @@ func (c *AdminMenuController) GetMenu() {
|
|||||||
_ = c.ServeJSON()
|
_ = c.ServeJSON()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
menus = filterMenusByView(menus, 1)
|
||||||
|
|
||||||
// 将平铺的菜单列表构建为树形结构
|
// 将平铺的菜单列表构建为树形结构
|
||||||
menuTree := buildMenuTree(menus, 0)
|
menuTree := buildMenuTree(menus, 0)
|
||||||
@ -72,8 +122,7 @@ func (c *AdminMenuController) GetBackendMenu() {
|
|||||||
var menus []models.SystemMenu
|
var menus []models.SystemMenu
|
||||||
qs := models.Orm.
|
qs := models.Orm.
|
||||||
QueryTable(new(models.SystemMenu)).
|
QueryTable(new(models.SystemMenu)).
|
||||||
Filter("status", 1).
|
Filter("status", 1)
|
||||||
Filter("is_platform", 0)
|
|
||||||
_, err := qs.All(&menus)
|
_, err := qs.All(&menus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Data["json"] = map[string]interface{}{
|
c.Data["json"] = map[string]interface{}{
|
||||||
@ -84,6 +133,7 @@ func (c *AdminMenuController) GetBackendMenu() {
|
|||||||
_ = c.ServeJSON()
|
_ = c.ServeJSON()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
menus = filterMenusByView(menus, 2)
|
||||||
|
|
||||||
menuTree := buildMenuTree(menus, 0)
|
menuTree := buildMenuTree(menus, 0)
|
||||||
c.Data["json"] = map[string]interface{}{
|
c.Data["json"] = map[string]interface{}{
|
||||||
@ -103,11 +153,6 @@ func (c *AdminMenuController) GetAllMenus() {
|
|||||||
qs := models.Orm.QueryTable(new(models.SystemMenu))
|
qs := models.Orm.QueryTable(new(models.SystemMenu))
|
||||||
// 菜单管理默认返回全量菜单;仅在明确传 cid 时按分类筛选
|
// 菜单管理默认返回全量菜单;仅在明确传 cid 时按分类筛选
|
||||||
// cid: 1平台角色 -> 平台菜单;2租户角色 -> 租户菜单
|
// cid: 1平台角色 -> 平台菜单;2租户角色 -> 租户菜单
|
||||||
if cid == 1 {
|
|
||||||
qs = qs.Filter("is_platform", 1)
|
|
||||||
} else if cid == 2 {
|
|
||||||
qs = qs.Filter("is_platform", 0)
|
|
||||||
}
|
|
||||||
_, err := qs.All(&menus)
|
_, err := qs.All(&menus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Data["json"] = map[string]interface{}{
|
c.Data["json"] = map[string]interface{}{
|
||||||
@ -118,6 +163,11 @@ func (c *AdminMenuController) GetAllMenus() {
|
|||||||
_ = c.ServeJSON()
|
_ = c.ServeJSON()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if cid == 1 {
|
||||||
|
menus = filterMenusByView(menus, 1)
|
||||||
|
} else if cid == 2 {
|
||||||
|
menus = filterMenusByView(menus, 2)
|
||||||
|
}
|
||||||
|
|
||||||
tree := buildMenuTree(menus, 0)
|
tree := buildMenuTree(menus, 0)
|
||||||
|
|
||||||
@ -134,7 +184,6 @@ func (c *AdminMenuController) GetAllMenus() {
|
|||||||
func (c *AdminMenuController) GetAllBackendMenus() {
|
func (c *AdminMenuController) GetAllBackendMenus() {
|
||||||
var menus []models.SystemMenu
|
var menus []models.SystemMenu
|
||||||
_, err := models.Orm.QueryTable(new(models.SystemMenu)).
|
_, err := models.Orm.QueryTable(new(models.SystemMenu)).
|
||||||
Filter("is_platform", 0).
|
|
||||||
All(&menus)
|
All(&menus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Data["json"] = map[string]interface{}{
|
c.Data["json"] = map[string]interface{}{
|
||||||
@ -145,6 +194,7 @@ func (c *AdminMenuController) GetAllBackendMenus() {
|
|||||||
_ = c.ServeJSON()
|
_ = c.ServeJSON()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
menus = filterMenusByView(menus, 2)
|
||||||
tree := buildMenuTree(menus, 0)
|
tree := buildMenuTree(menus, 0)
|
||||||
c.Data["json"] = map[string]interface{}{
|
c.Data["json"] = map[string]interface{}{
|
||||||
"code": 200,
|
"code": 200,
|
||||||
@ -165,7 +215,7 @@ type menuNode struct {
|
|||||||
Sort int64 `json:"sort"`
|
Sort int64 `json:"sort"`
|
||||||
Status int8 `json:"status"`
|
Status int8 `json:"status"`
|
||||||
IsVisible *int8 `json:"is_visible,omitempty"`
|
IsVisible *int8 `json:"is_visible,omitempty"`
|
||||||
IsPlatform *int8 `json:"is_platform,omitempty"`
|
Views []int `json:"views,omitempty"`
|
||||||
Type int8 `json:"type"`
|
Type int8 `json:"type"`
|
||||||
Permission string `json:"permission,omitempty"`
|
Permission string `json:"permission,omitempty"`
|
||||||
Children []*menuNode `json:"children,omitempty"`
|
Children []*menuNode `json:"children,omitempty"`
|
||||||
@ -183,7 +233,7 @@ func buildMenuTree(menus []models.SystemMenu, pid int64) []*menuNode {
|
|||||||
Sort: m.Sort,
|
Sort: m.Sort,
|
||||||
Status: m.Status,
|
Status: m.Status,
|
||||||
IsVisible: m.IsVisible,
|
IsVisible: m.IsVisible,
|
||||||
IsPlatform: m.IsPlatform,
|
Views: parseViews(m.Views),
|
||||||
Type: m.Type,
|
Type: m.Type,
|
||||||
}
|
}
|
||||||
if m.Path != nil {
|
if m.Path != nil {
|
||||||
@ -257,7 +307,7 @@ func (c *AdminMenuController) CreateMenu() {
|
|||||||
Sort: valueInt64(payload.Sort, 0),
|
Sort: valueInt64(payload.Sort, 0),
|
||||||
Status: valueInt8(payload.Status, 1),
|
Status: valueInt8(payload.Status, 1),
|
||||||
IsVisible: ptrInt8(valueInt8(payload.IsVisible, 1)),
|
IsVisible: ptrInt8(valueInt8(payload.IsVisible, 1)),
|
||||||
IsPlatform: ptrInt8(valueInt8(payload.IsPlatform, 1)),
|
Views: ptrString(viewsJSON(payload.Views)),
|
||||||
Type: valueInt8(payload.Type, 1),
|
Type: valueInt8(payload.Type, 1),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,7 +355,7 @@ func (c *AdminMenuController) UpdateMenu() {
|
|||||||
"sort": valueInt64(payload.Sort, 0),
|
"sort": valueInt64(payload.Sort, 0),
|
||||||
"status": valueInt8(payload.Status, 1),
|
"status": valueInt8(payload.Status, 1),
|
||||||
"is_visible": valueInt8(payload.IsVisible, 1),
|
"is_visible": valueInt8(payload.IsVisible, 1),
|
||||||
"is_platform": valueInt8(payload.IsPlatform, 1),
|
"views": viewsJSON(payload.Views),
|
||||||
"type": valueInt8(payload.Type, 1),
|
"type": valueInt8(payload.Type, 1),
|
||||||
"permission": valueString(payload.Permission, ""),
|
"permission": valueString(payload.Permission, ""),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"server/models"
|
||||||
"server/pkg/jwtutil"
|
"server/pkg/jwtutil"
|
||||||
"server/services"
|
"server/services"
|
||||||
|
|
||||||
@ -14,12 +15,14 @@ import (
|
|||||||
type platformLoginRequest struct {
|
type platformLoginRequest struct {
|
||||||
Account string `json:"account"`
|
Account string `json:"account"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
Code string `json:"code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type backendLoginRequest struct {
|
type backendLoginRequest struct {
|
||||||
TenantName string `json:"tenant_name"`
|
TenantName string `json:"tenant_name"`
|
||||||
Account string `json:"account"`
|
Account string `json:"account"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
|
Code string `json:"code"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PlatformAuthController 平台端认证控制器
|
// PlatformAuthController 平台端认证控制器
|
||||||
@ -59,6 +62,21 @@ func (c *PlatformAuthController) LoginPlatform() {
|
|||||||
_ = c.ServeJSON()
|
_ = c.ServeJSON()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cfg, _ := models.GetPlatformLoginVerify()
|
||||||
|
if cfg.OpenVerifyEnabled == 1 {
|
||||||
|
if cfg.VerifyType == "sms" || cfg.VerifyType == "email" {
|
||||||
|
if strings.TrimSpace(req.Code) == "" {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "请输入验证码"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := services.VerifyPlatformLoginCode(req.Account, cfg.VerifyType, req.Code); err != nil {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 400, "msg": err.Error()}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 控制器只做 HTTP 解析与响应编排,业务逻辑放 services 层
|
// 控制器只做 HTTP 解析与响应编排,业务逻辑放 services 层
|
||||||
token, loginUser, err := services.PlatformAdminLogin(req.Account, req.Password)
|
token, loginUser, err := services.PlatformAdminLogin(req.Account, req.Password)
|
||||||
@ -80,7 +98,6 @@ func (c *PlatformAuthController) LoginPlatform() {
|
|||||||
"id": loginUser.ID,
|
"id": loginUser.ID,
|
||||||
"account": loginUser.Account,
|
"account": loginUser.Account,
|
||||||
"name": loginUser.Name,
|
"name": loginUser.Name,
|
||||||
"tid": loginUser.Tid,
|
|
||||||
"rid": loginUser.Rid,
|
"rid": loginUser.Rid,
|
||||||
"avatar": loginUser.Avatar,
|
"avatar": loginUser.Avatar,
|
||||||
"role_name": loginUser.RoleName,
|
"role_name": loginUser.RoleName,
|
||||||
@ -110,6 +127,21 @@ func (c *PlatformAuthController) LoginBackend() {
|
|||||||
_ = c.ServeJSON()
|
_ = c.ServeJSON()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
cfg, _ := models.GetPlatformLoginVerify()
|
||||||
|
if cfg.OpenVerifyEnabled == 1 {
|
||||||
|
if cfg.VerifyType == "sms" || cfg.VerifyType == "email" {
|
||||||
|
if strings.TrimSpace(req.Code) == "" {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "请输入验证码"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := services.VerifyBackendLoginCode(req.TenantName, req.Account, cfg.VerifyType, req.Code); err != nil {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 400, "msg": err.Error()}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
token, loginUser, err := services.BackendLogin(req.TenantName, req.Account, req.Password)
|
token, loginUser, err := services.BackendLogin(req.TenantName, req.Account, req.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -185,10 +217,45 @@ func (c *PlatformAuthController) GetCurrentUser() {
|
|||||||
|
|
||||||
// SendLoginCode 发送登录验证码(占位实现)
|
// SendLoginCode 发送登录验证码(占位实现)
|
||||||
func (c *PlatformAuthController) SendLoginCode() {
|
func (c *PlatformAuthController) SendLoginCode() {
|
||||||
c.Data["json"] = map[string]interface{}{
|
var req struct {
|
||||||
"code": 501,
|
Account string `json:"account"`
|
||||||
"msg": "发送登录验证码暂未实现",
|
TenantName string `json:"tenant_name"`
|
||||||
|
Channel string `json:"channel"`
|
||||||
}
|
}
|
||||||
|
body, _ := io.ReadAll(c.Ctx.Request.Body)
|
||||||
|
if err := json.Unmarshal(body, &req); err != nil {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "参数错误"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
cfg, _ := models.GetPlatformLoginVerify()
|
||||||
|
if cfg.OpenVerifyEnabled != 1 {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "当前未开启验证"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
channel := strings.TrimSpace(req.Channel)
|
||||||
|
if channel == "" {
|
||||||
|
channel = cfg.VerifyType
|
||||||
|
}
|
||||||
|
if channel != "sms" && channel != "email" {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "仅支持短信/邮箱验证码"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
path := strings.ToLower(c.Ctx.Request.URL.Path)
|
||||||
|
var sendErr error
|
||||||
|
if strings.HasPrefix(path, "/backend/") {
|
||||||
|
sendErr = services.SendBackendLoginCode(req.TenantName, req.Account, channel)
|
||||||
|
} else {
|
||||||
|
sendErr = services.SendPlatformLoginCode(req.Account, channel)
|
||||||
|
}
|
||||||
|
if sendErr != nil {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 400, "msg": sendErr.Error()}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "验证码已发送"}
|
||||||
_ = c.ServeJSON()
|
_ = c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,32 +279,60 @@ func (c *PlatformAuthController) Logout() {
|
|||||||
|
|
||||||
// GetGeetest3Infos 获取极验3.0配置(占位实现)
|
// GetGeetest3Infos 获取极验3.0配置(占位实现)
|
||||||
func (c *PlatformAuthController) GetGeetest3Infos() {
|
func (c *PlatformAuthController) GetGeetest3Infos() {
|
||||||
|
cfg, _ := models.GetPlatformLoginVerify()
|
||||||
|
if cfg.Geetest3ID == nil || cfg.Geetest3Key == nil {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 404, "msg": "未配置极验3参数"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
c.Data["json"] = map[string]interface{}{
|
c.Data["json"] = map[string]interface{}{
|
||||||
"code": 501,
|
"code": 200,
|
||||||
"msg": "极验3.0暂未实现",
|
"msg": "success",
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"captcha_id": *cfg.Geetest3ID,
|
||||||
|
"captcha_key": *cfg.Geetest3Key,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
_ = c.ServeJSON()
|
_ = c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGeetest4Infos 获取极验4.0配置(占位实现)
|
// GetGeetest4Infos 获取极验4.0配置(占位实现)
|
||||||
func (c *PlatformAuthController) GetGeetest4Infos() {
|
func (c *PlatformAuthController) GetGeetest4Infos() {
|
||||||
|
cfg, _ := models.GetPlatformLoginVerify()
|
||||||
|
if cfg.Geetest4ID == nil || cfg.Geetest4Key == nil {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 404, "msg": "未配置极验4参数"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
c.Data["json"] = map[string]interface{}{
|
c.Data["json"] = map[string]interface{}{
|
||||||
"code": 501,
|
"code": 200,
|
||||||
"msg": "极验4.0暂未实现",
|
"msg": "success",
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"captcha_id": *cfg.Geetest4ID,
|
||||||
|
"captcha_key": *cfg.Geetest4Key,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
_ = c.ServeJSON()
|
_ = c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOpenVerify 判断是否开启登录验证(占位实现)
|
// GetOpenVerify 判断是否开启登录验证(占位实现)
|
||||||
func (c *PlatformAuthController) GetOpenVerify() {
|
func (c *PlatformAuthController) GetOpenVerify() {
|
||||||
|
cfg, _ := models.GetPlatformLoginVerify()
|
||||||
|
openVerify := "0"
|
||||||
|
if cfg.OpenVerifyEnabled == 1 {
|
||||||
|
openVerify = "1"
|
||||||
|
}
|
||||||
c.Data["json"] = map[string]interface{}{
|
c.Data["json"] = map[string]interface{}{
|
||||||
"code": 200,
|
"code": 200,
|
||||||
"msg": "ok",
|
"msg": "ok",
|
||||||
// data 为配置项数组,这里固定关闭验证:openVerify=0
|
|
||||||
"data": []map[string]string{
|
"data": []map[string]string{
|
||||||
{
|
{
|
||||||
"label": "openVerify",
|
"label": "openVerify",
|
||||||
"value": "0",
|
"value": openVerify,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "verifyType",
|
||||||
|
"value": cfg.VerifyType,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
124
controllers/platform_login_verify.go
Normal file
124
controllers/platform_login_verify.go
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"server/models"
|
||||||
|
|
||||||
|
beego "github.com/beego/beego/v2/server/web"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PlatformLoginVerifyController struct {
|
||||||
|
beego.Controller
|
||||||
|
}
|
||||||
|
|
||||||
|
type loginVerifyPayload struct {
|
||||||
|
OpenVerifyEnabled *int8 `json:"openVerify_enabled"`
|
||||||
|
VerifyType string `json:"use_geetest"`
|
||||||
|
Geetest3ID *string `json:"geetest3_id"`
|
||||||
|
Geetest3Key *string `json:"geetest3_key"`
|
||||||
|
Geetest4ID *string `json:"geetest4_id"`
|
||||||
|
Geetest4Key *string `json:"geetest4_key"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func normalizeVerifyType(v string) string {
|
||||||
|
switch strings.TrimSpace(v) {
|
||||||
|
case "sms", "geetest", "email", "captcha":
|
||||||
|
return strings.TrimSpace(v)
|
||||||
|
default:
|
||||||
|
return "captcha"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLoginVerifyInfos 获取登录验证配置
|
||||||
|
// GET /platform/loginVerifyInfos
|
||||||
|
func (c *PlatformLoginVerifyController) GetLoginVerifyInfos() {
|
||||||
|
cfg, err := models.GetPlatformLoginVerify()
|
||||||
|
if err != nil {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 500, "msg": "获取配置失败"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.Data["json"] = map[string]interface{}{
|
||||||
|
"code": 200,
|
||||||
|
"msg": "success",
|
||||||
|
"data": map[string]interface{}{
|
||||||
|
"openVerify_enabled": cfg.OpenVerifyEnabled,
|
||||||
|
"use_geetest": cfg.VerifyType,
|
||||||
|
"geetest3_id": cfg.Geetest3ID,
|
||||||
|
"geetest3_key": cfg.Geetest3Key,
|
||||||
|
"geetest4_id": cfg.Geetest4ID,
|
||||||
|
"geetest4_key": cfg.Geetest4Key,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SaveLoginVerifyInfos 保存登录验证配置
|
||||||
|
// POST /platform/saveloginVerifyInfos
|
||||||
|
func (c *PlatformLoginVerifyController) SaveLoginVerifyInfos() {
|
||||||
|
var p loginVerifyPayload
|
||||||
|
raw, _ := io.ReadAll(c.Ctx.Request.Body)
|
||||||
|
if err := json.Unmarshal(raw, &p); err != nil {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "参数错误"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyType := normalizeVerifyType(p.VerifyType)
|
||||||
|
openVerifyEnabled := int8(1)
|
||||||
|
if p.OpenVerifyEnabled != nil {
|
||||||
|
openVerifyEnabled = *p.OpenVerifyEnabled
|
||||||
|
}
|
||||||
|
if verifyType == "geetest" {
|
||||||
|
if p.Geetest4ID == nil || strings.TrimSpace(*p.Geetest4ID) == "" {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "geetest4_id 不能为空"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if p.Geetest4Key == nil || strings.TrimSpace(*p.Geetest4Key) == "" {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 400, "msg": "geetest4_key 不能为空"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var existed models.PlatformLoginVerify
|
||||||
|
err := models.Orm.QueryTable(new(models.PlatformLoginVerify)).OrderBy("-id").One(&existed)
|
||||||
|
if err == nil {
|
||||||
|
update := map[string]interface{}{
|
||||||
|
"open_verify_enabled": openVerifyEnabled,
|
||||||
|
"verify_type": verifyType,
|
||||||
|
"geetest3_id": p.Geetest3ID,
|
||||||
|
"geetest3_key": p.Geetest3Key,
|
||||||
|
"geetest4_id": p.Geetest4ID,
|
||||||
|
"geetest4_key": p.Geetest4Key,
|
||||||
|
}
|
||||||
|
_, err = models.Orm.QueryTable(new(models.PlatformLoginVerify)).Filter("id", existed.ID).Update(update)
|
||||||
|
if err != nil {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 500, "msg": "保存失败"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
row := &models.PlatformLoginVerify{
|
||||||
|
OpenVerifyEnabled: openVerifyEnabled,
|
||||||
|
VerifyType: verifyType,
|
||||||
|
Geetest3ID: p.Geetest3ID,
|
||||||
|
Geetest3Key: p.Geetest3Key,
|
||||||
|
Geetest4ID: p.Geetest4ID,
|
||||||
|
Geetest4Key: p.Geetest4Key,
|
||||||
|
}
|
||||||
|
if _, err := models.Orm.Insert(row); err != nil {
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 500, "msg": "保存失败"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Data["json"] = map[string]interface{}{"code": 200, "msg": "保存成功"}
|
||||||
|
_ = c.ServeJSON()
|
||||||
|
}
|
||||||
|
|
||||||
@ -19,7 +19,7 @@ type PlatformModulesController struct {
|
|||||||
beego.Controller
|
beego.Controller
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *PlatformModulesController) platformClaims() (*jwtutil.Claims, error) {
|
func (c *PlatformModulesController) modulesClaims() (*jwtutil.Claims, error) {
|
||||||
auth := c.Ctx.Request.Header.Get("Authorization")
|
auth := c.Ctx.Request.Header.Get("Authorization")
|
||||||
if auth == "" {
|
if auth == "" {
|
||||||
return nil, fmt.Errorf("未登录")
|
return nil, fmt.Errorf("未登录")
|
||||||
@ -32,8 +32,19 @@ func (c *PlatformModulesController) platformClaims() (*jwtutil.Claims, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("无效的token")
|
return nil, fmt.Errorf("无效的token")
|
||||||
}
|
}
|
||||||
if claims.UserType != "platform" {
|
// 语义更正:
|
||||||
return nil, fmt.Errorf("无权访问")
|
// - /platform/* 只能 platform 访问
|
||||||
|
// - /backend/* 只能 backend 访问
|
||||||
|
// 兼容:历史 token 可能缺少 user_type(按 user 处理),此时都拒绝访问以避免越权。
|
||||||
|
path := strings.ToLower(c.Ctx.Request.URL.Path)
|
||||||
|
if strings.HasPrefix(path, "/platform/") {
|
||||||
|
if claims.UserType != "platform" {
|
||||||
|
return nil, fmt.Errorf("无权访问")
|
||||||
|
}
|
||||||
|
} else if strings.HasPrefix(path, "/backend/") {
|
||||||
|
if claims.UserType != "backend" {
|
||||||
|
return nil, fmt.Errorf("无权访问")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return claims, nil
|
return claims, nil
|
||||||
}
|
}
|
||||||
@ -46,7 +57,7 @@ func (c *PlatformModulesController) jsonErr(httpStatus, bizCode int, msg string)
|
|||||||
|
|
||||||
// GetList GET /platform/modules/list
|
// GetList GET /platform/modules/list
|
||||||
func (c *PlatformModulesController) GetList() {
|
func (c *PlatformModulesController) GetList() {
|
||||||
if _, err := c.platformClaims(); err != nil {
|
if _, err := c.modulesClaims(); err != nil {
|
||||||
c.jsonErr(401, 401, err.Error())
|
c.jsonErr(401, 401, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -73,7 +84,7 @@ func (c *PlatformModulesController) GetList() {
|
|||||||
// GetTenantList GET /platform/modules/getTenantList
|
// GetTenantList GET /platform/modules/getTenantList
|
||||||
// 兼容旧接口命名:返回当前账号可见的模块。当前实现:返回 status=1 且 is_show=1 的全部模块。
|
// 兼容旧接口命名:返回当前账号可见的模块。当前实现:返回 status=1 且 is_show=1 的全部模块。
|
||||||
func (c *PlatformModulesController) GetTenantList() {
|
func (c *PlatformModulesController) GetTenantList() {
|
||||||
if _, err := c.platformClaims(); err != nil {
|
if _, err := c.modulesClaims(); err != nil {
|
||||||
c.jsonErr(401, 401, err.Error())
|
c.jsonErr(401, 401, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -101,7 +112,7 @@ func (c *PlatformModulesController) GetTenantList() {
|
|||||||
|
|
||||||
// GetDetail GET /platform/modules/:id
|
// GetDetail GET /platform/modules/:id
|
||||||
func (c *PlatformModulesController) GetDetail() {
|
func (c *PlatformModulesController) GetDetail() {
|
||||||
if _, err := c.platformClaims(); err != nil {
|
if _, err := c.modulesClaims(); err != nil {
|
||||||
c.jsonErr(401, 401, err.Error())
|
c.jsonErr(401, 401, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -139,7 +150,7 @@ type modulePayload struct {
|
|||||||
|
|
||||||
// Add POST /platform/modules
|
// Add POST /platform/modules
|
||||||
func (c *PlatformModulesController) Add() {
|
func (c *PlatformModulesController) Add() {
|
||||||
if _, err := c.platformClaims(); err != nil {
|
if _, err := c.modulesClaims(); err != nil {
|
||||||
c.jsonErr(401, 401, err.Error())
|
c.jsonErr(401, 401, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -194,7 +205,7 @@ func (c *PlatformModulesController) Add() {
|
|||||||
|
|
||||||
// Edit PUT /platform/modules/:id
|
// Edit PUT /platform/modules/:id
|
||||||
func (c *PlatformModulesController) Edit() {
|
func (c *PlatformModulesController) Edit() {
|
||||||
if _, err := c.platformClaims(); err != nil {
|
if _, err := c.modulesClaims(); err != nil {
|
||||||
c.jsonErr(401, 401, err.Error())
|
c.jsonErr(401, 401, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -262,7 +273,7 @@ func (c *PlatformModulesController) Edit() {
|
|||||||
|
|
||||||
// Delete DELETE /platform/modules/:id(软删)
|
// Delete DELETE /platform/modules/:id(软删)
|
||||||
func (c *PlatformModulesController) Delete() {
|
func (c *PlatformModulesController) Delete() {
|
||||||
if _, err := c.platformClaims(); err != nil {
|
if _, err := c.modulesClaims(); err != nil {
|
||||||
c.jsonErr(401, 401, err.Error())
|
c.jsonErr(401, 401, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -291,7 +302,7 @@ func (c *PlatformModulesController) Delete() {
|
|||||||
|
|
||||||
// BatchDelete POST /platform/modules/batchDelete body:{ids:[]}
|
// BatchDelete POST /platform/modules/batchDelete body:{ids:[]}
|
||||||
func (c *PlatformModulesController) BatchDelete() {
|
func (c *PlatformModulesController) BatchDelete() {
|
||||||
if _, err := c.platformClaims(); err != nil {
|
if _, err := c.modulesClaims(); err != nil {
|
||||||
c.jsonErr(401, 401, err.Error())
|
c.jsonErr(401, 401, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -323,7 +334,7 @@ func (c *PlatformModulesController) BatchDelete() {
|
|||||||
// ChangeStatus POST /platform/modules/status body:{id,status}
|
// ChangeStatus POST /platform/modules/status body:{id,status}
|
||||||
// 兼容前端:这里的 status 实际用于切换 is_show(显示开关)。
|
// 兼容前端:这里的 status 实际用于切换 is_show(显示开关)。
|
||||||
func (c *PlatformModulesController) ChangeStatus() {
|
func (c *PlatformModulesController) ChangeStatus() {
|
||||||
if _, err := c.platformClaims(); err != nil {
|
if _, err := c.modulesClaims(); err != nil {
|
||||||
c.jsonErr(401, 401, err.Error())
|
c.jsonErr(401, 401, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -362,7 +373,7 @@ func (c *PlatformModulesController) ChangeStatus() {
|
|||||||
|
|
||||||
// GetSelectList GET /platform/modules/select/list
|
// GetSelectList GET /platform/modules/select/list
|
||||||
func (c *PlatformModulesController) GetSelectList() {
|
func (c *PlatformModulesController) GetSelectList() {
|
||||||
if _, err := c.platformClaims(); err != nil {
|
if _, err := c.modulesClaims(); err != nil {
|
||||||
c.jsonErr(401, 401, err.Error())
|
c.jsonErr(401, 401, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,6 +47,7 @@ func Init(_ string) {
|
|||||||
new(SystemDomainPool),
|
new(SystemDomainPool),
|
||||||
new(SystemTenantDomain),
|
new(SystemTenantDomain),
|
||||||
new(SystemModules),
|
new(SystemModules),
|
||||||
|
new(PlatformLoginVerify),
|
||||||
)
|
)
|
||||||
|
|
||||||
// 创建全局 Ormer
|
// 创建全局 Ormer
|
||||||
|
|||||||
34
models/platform_login_verify.go
Normal file
34
models/platform_login_verify.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// PlatformLoginVerify 平台登录验证配置(单行配置)
|
||||||
|
type PlatformLoginVerify struct {
|
||||||
|
ID uint64 `orm:"column(id);pk;auto" json:"id"`
|
||||||
|
OpenVerifyEnabled int8 `orm:"column(open_verify_enabled);default(1)" json:"openVerify_enabled"` // 0关闭 1开启
|
||||||
|
VerifyType string `orm:"column(verify_type);size(20);default(captcha)" json:"verify_type"` // captcha/sms/geetest/email
|
||||||
|
Geetest3ID *string `orm:"column(geetest3_id);size(128);null" json:"geetest3_id"`
|
||||||
|
Geetest3Key *string `orm:"column(geetest3_key);size(255);null" json:"geetest3_key"`
|
||||||
|
Geetest4ID *string `orm:"column(geetest4_id);size(128);null" json:"geetest4_id"`
|
||||||
|
Geetest4Key *string `orm:"column(geetest4_key);size(255);null" json:"geetest4_key"`
|
||||||
|
CreateTime time.Time `orm:"column(create_time);type(datetime);auto_now_add" json:"create_time"`
|
||||||
|
UpdateTime *time.Time `orm:"column(update_time);type(datetime);auto_now;null" json:"update_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PlatformLoginVerify) TableName() string {
|
||||||
|
return "yz_system_login_verify"
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPlatformLoginVerify() (*PlatformLoginVerify, error) {
|
||||||
|
var cfg PlatformLoginVerify
|
||||||
|
err := Orm.QueryTable(new(PlatformLoginVerify)).OrderBy("-id").One(&cfg)
|
||||||
|
if err != nil {
|
||||||
|
// 默认配置:验证码
|
||||||
|
return &PlatformLoginVerify{OpenVerifyEnabled: 1, VerifyType: "captcha"}, nil
|
||||||
|
}
|
||||||
|
if cfg.VerifyType == "" {
|
||||||
|
cfg.VerifyType = "captcha"
|
||||||
|
}
|
||||||
|
return &cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
@ -13,7 +13,7 @@ type SystemMenu struct {
|
|||||||
Sort int64 `orm:"column(sort);default(0)" json:"sort"` // 排序号
|
Sort int64 `orm:"column(sort);default(0)" json:"sort"` // 排序号
|
||||||
Status int8 `orm:"column(status);default(0)" json:"status"` // 状态:1-启用,0-禁用
|
Status int8 `orm:"column(status);default(0)" json:"status"` // 状态:1-启用,0-禁用
|
||||||
IsVisible *int8 `orm:"column(is_visible);null" json:"isVisible"` // 是否显示:1-显示 0-不显示
|
IsVisible *int8 `orm:"column(is_visible);null" json:"isVisible"` // 是否显示:1-显示 0-不显示
|
||||||
IsPlatform *int8 `orm:"column(is_platform);null" json:"isPlatform"` // 是否平台:1-是 0-否
|
Views *string `orm:"column(views);size(255);null" json:"views"` // 菜单显示端(JSON数组字符串):[1]=平台端 [2]=租户端 [1,2]=双端
|
||||||
Type int8 `orm:"column(type)" json:"type"` // 菜单类型:1-目录,2-页面,3-接口
|
Type int8 `orm:"column(type)" json:"type"` // 菜单类型:1-目录,2-页面,3-接口
|
||||||
Permission *string `orm:"column(permission);size(100);null" json:"permission"` // 权限标识(按钮类型时填写)
|
Permission *string `orm:"column(permission);size(100);null" json:"permission"` // 权限标识(按钮类型时填写)
|
||||||
Creater *string `orm:"column(creater);size(50);null" json:"creater"` // 创建者
|
Creater *string `orm:"column(creater);size(50);null" json:"creater"` // 创建者
|
||||||
|
|||||||
@ -38,4 +38,13 @@ func RegisterAuthRoutes() {
|
|||||||
beego.Router("/backend/createmenu", &controllers.AdminMenuController{}, "post:CreateMenu")
|
beego.Router("/backend/createmenu", &controllers.AdminMenuController{}, "post:CreateMenu")
|
||||||
beego.Router("/backend/updatemenu/:id", &controllers.AdminMenuController{}, "put:UpdateMenu")
|
beego.Router("/backend/updatemenu/:id", &controllers.AdminMenuController{}, "put:UpdateMenu")
|
||||||
beego.Router("/backend/deletemenu/:id", &controllers.AdminMenuController{}, "delete:DeleteMenu")
|
beego.Router("/backend/deletemenu/:id", &controllers.AdminMenuController{}, "delete:DeleteMenu")
|
||||||
|
|
||||||
|
// 模块管理(yz_system_modules)——语义更正:租户端走 /backend/modules/*
|
||||||
|
beego.Router("/backend/modules/list", &controllers.PlatformModulesController{}, "get:GetList")
|
||||||
|
beego.Router("/backend/modules/getTenantList", &controllers.PlatformModulesController{}, "get:GetTenantList")
|
||||||
|
beego.Router("/backend/modules/select/list", &controllers.PlatformModulesController{}, "get:GetSelectList")
|
||||||
|
beego.Router("/backend/modules/status", &controllers.PlatformModulesController{}, "post:ChangeStatus")
|
||||||
|
beego.Router("/backend/modules/batchDelete", &controllers.PlatformModulesController{}, "post:BatchDelete")
|
||||||
|
beego.Router("/backend/modules", &controllers.PlatformModulesController{}, "post:Add")
|
||||||
|
beego.Router("/backend/modules/:id", &controllers.PlatformModulesController{}, "get:GetDetail;put:Edit;delete:Delete")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,8 @@ func Register() {
|
|||||||
beego.Router("/platform/login/getGeetest3Infos", &controllers.PlatformAuthController{}, "get:GetGeetest3Infos")
|
beego.Router("/platform/login/getGeetest3Infos", &controllers.PlatformAuthController{}, "get:GetGeetest3Infos")
|
||||||
beego.Router("/platform/login/getGeetest4Infos", &controllers.PlatformAuthController{}, "get:GetGeetest4Infos")
|
beego.Router("/platform/login/getGeetest4Infos", &controllers.PlatformAuthController{}, "get:GetGeetest4Infos")
|
||||||
beego.Router("/platform/login/getOpenVerify", &controllers.PlatformAuthController{}, "get:GetOpenVerify")
|
beego.Router("/platform/login/getOpenVerify", &controllers.PlatformAuthController{}, "get:GetOpenVerify")
|
||||||
|
beego.Router("/platform/loginVerifyInfos", &controllers.PlatformLoginVerifyController{}, "get:GetLoginVerifyInfos")
|
||||||
|
beego.Router("/platform/saveloginVerifyInfos", &controllers.PlatformLoginVerifyController{}, "post:SaveLoginVerifyInfos")
|
||||||
|
|
||||||
// 找回密码相关
|
// 找回密码相关
|
||||||
beego.Router("/platform/resetPassword", &controllers.PlatformAuthController{}, "post:ResetPassword")
|
beego.Router("/platform/resetPassword", &controllers.PlatformAuthController{}, "post:ResetPassword")
|
||||||
|
|||||||
130
services/login_verify_code.go
Normal file
130
services/login_verify_code.go
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"server/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
type loginCodeItem struct {
|
||||||
|
Code string
|
||||||
|
Channel string
|
||||||
|
ExpiredAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
var loginCodeStore sync.Map
|
||||||
|
|
||||||
|
func codeKey(account, channel string) string {
|
||||||
|
return strings.ToLower(strings.TrimSpace(account)) + "|" + strings.TrimSpace(channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendPlatformLoginCode(account, channel string) error {
|
||||||
|
account = strings.TrimSpace(account)
|
||||||
|
channel = strings.TrimSpace(channel)
|
||||||
|
if account == "" {
|
||||||
|
return errors.New("账号不能为空")
|
||||||
|
}
|
||||||
|
if channel != "sms" && channel != "email" {
|
||||||
|
return errors.New("仅支持短信或邮箱验证码")
|
||||||
|
}
|
||||||
|
|
||||||
|
var u models.AdminUser
|
||||||
|
if err := models.Orm.QueryTable(new(models.AdminUser)).Filter("account", account).One(&u); err != nil {
|
||||||
|
return errors.New("用户不存在")
|
||||||
|
}
|
||||||
|
if u.Status == 0 {
|
||||||
|
return errors.New("账号已禁用")
|
||||||
|
}
|
||||||
|
if channel == "sms" && (u.Phone == nil || strings.TrimSpace(*u.Phone) == "") {
|
||||||
|
return errors.New("该账号未绑定手机号")
|
||||||
|
}
|
||||||
|
if channel == "email" && (u.Email == nil || strings.TrimSpace(*u.Email) == "") {
|
||||||
|
return errors.New("该账号未绑定邮箱")
|
||||||
|
}
|
||||||
|
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
code := fmt.Sprintf("%06d", rand.Intn(1000000))
|
||||||
|
loginCodeStore.Store(codeKey(account, channel), loginCodeItem{
|
||||||
|
Code: code,
|
||||||
|
Channel: channel,
|
||||||
|
ExpiredAt: time.Now().Add(5 * time.Minute),
|
||||||
|
})
|
||||||
|
// TODO: 接入短信/邮箱发送通道。当前阶段只做服务端验证码校验链路。
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyPlatformLoginCode(account, channel, code string) error {
|
||||||
|
account = strings.TrimSpace(account)
|
||||||
|
channel = strings.TrimSpace(channel)
|
||||||
|
code = strings.TrimSpace(code)
|
||||||
|
if account == "" || code == "" {
|
||||||
|
return errors.New("验证码不能为空")
|
||||||
|
}
|
||||||
|
val, ok := loginCodeStore.Load(codeKey(account, channel))
|
||||||
|
if !ok {
|
||||||
|
return errors.New("验证码不存在或已失效")
|
||||||
|
}
|
||||||
|
item, ok := val.(loginCodeItem)
|
||||||
|
if !ok {
|
||||||
|
return errors.New("验证码状态异常")
|
||||||
|
}
|
||||||
|
if time.Now().After(item.ExpiredAt) {
|
||||||
|
loginCodeStore.Delete(codeKey(account, channel))
|
||||||
|
return errors.New("验证码已过期")
|
||||||
|
}
|
||||||
|
if item.Code != code {
|
||||||
|
return errors.New("验证码错误")
|
||||||
|
}
|
||||||
|
loginCodeStore.Delete(codeKey(account, channel))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendBackendLoginCode(tenantName, account, channel string) error {
|
||||||
|
tenantName = strings.TrimSpace(tenantName)
|
||||||
|
account = strings.TrimSpace(account)
|
||||||
|
channel = strings.TrimSpace(channel)
|
||||||
|
if tenantName == "" || account == "" {
|
||||||
|
return errors.New("租户名称和账号不能为空")
|
||||||
|
}
|
||||||
|
if channel != "sms" && channel != "email" {
|
||||||
|
return errors.New("仅支持短信或邮箱验证码")
|
||||||
|
}
|
||||||
|
var tenant models.Tenant
|
||||||
|
if err := models.Orm.QueryTable(new(models.Tenant)).Filter("tenant_name", tenantName).One(&tenant); err != nil {
|
||||||
|
return errors.New("租户不存在")
|
||||||
|
}
|
||||||
|
var user models.TenantUser
|
||||||
|
if err := models.Orm.QueryTable(new(models.TenantUser)).
|
||||||
|
Filter("tid", tenant.ID).
|
||||||
|
Filter("account", account).
|
||||||
|
One(&user); err != nil {
|
||||||
|
return errors.New("用户不存在")
|
||||||
|
}
|
||||||
|
if user.Status == 0 {
|
||||||
|
return errors.New("账号已禁用")
|
||||||
|
}
|
||||||
|
if channel == "sms" && (user.Phone == nil || strings.TrimSpace(*user.Phone) == "") {
|
||||||
|
return errors.New("该账号未绑定手机号")
|
||||||
|
}
|
||||||
|
if channel == "email" && (user.Email == nil || strings.TrimSpace(*user.Email) == "") {
|
||||||
|
return errors.New("该账号未绑定邮箱")
|
||||||
|
}
|
||||||
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
code := fmt.Sprintf("%06d", rand.Intn(1000000))
|
||||||
|
loginCodeStore.Store(codeKey(tenantName+"#"+account, channel), loginCodeItem{
|
||||||
|
Code: code,
|
||||||
|
Channel: channel,
|
||||||
|
ExpiredAt: time.Now().Add(5 * time.Minute),
|
||||||
|
})
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyBackendLoginCode(tenantName, account, channel, code string) error {
|
||||||
|
return VerifyPlatformLoginCode(tenantName+"#"+account, channel, code)
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user