批量更新
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"server/models"
|
||||
"server/pkg/jwtutil"
|
||||
|
||||
beego "github.com/beego/beego/v2/server/web"
|
||||
)
|
||||
|
||||
// PlatformAuthIdpController 统一认证 —— 第三方登录配置(平台端管理)
|
||||
//
|
||||
// 配置说明:
|
||||
// - tid = 0 :平台全局配置,所有租户共用
|
||||
// - tid > 0 :租户自带身份源,仅该租户可见(第10条需求:企业自带钉钉/飞书等)
|
||||
//
|
||||
// 配置对象只有「租户用户登录」,平台端自身不使用第三方登录。
|
||||
type PlatformAuthIdpController struct {
|
||||
beego.Controller
|
||||
}
|
||||
|
||||
func (c *PlatformAuthIdpController) serveJSON(data map[string]interface{}) {
|
||||
c.Data["json"] = data
|
||||
_ = c.ServeJSON()
|
||||
}
|
||||
|
||||
// Prepare 统一鉴权:仅平台管理员可维护第三方登录配置
|
||||
func (c *PlatformAuthIdpController) Prepare() {
|
||||
authHeader := c.Ctx.Request.Header.Get("Authorization")
|
||||
if authHeader == "" {
|
||||
c.Ctx.Output.SetStatus(401)
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "未登录"})
|
||||
c.StopRun()
|
||||
return
|
||||
}
|
||||
parts := strings.SplitN(authHeader, " ", 2)
|
||||
if len(parts) != 2 || parts[0] != "Bearer" {
|
||||
c.Ctx.Output.SetStatus(401)
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "认证信息格式错误"})
|
||||
c.StopRun()
|
||||
return
|
||||
}
|
||||
claims, err := jwtutil.ParseToken(parts[1])
|
||||
if err != nil {
|
||||
c.Ctx.Output.SetStatus(401)
|
||||
c.serveJSON(map[string]interface{}{"code": 401, "msg": "登录已失效,请重新登录"})
|
||||
c.StopRun()
|
||||
return
|
||||
}
|
||||
if claims.UserType != "platform" {
|
||||
c.Ctx.Output.SetStatus(403)
|
||||
c.serveJSON(map[string]interface{}{"code": 403, "msg": "无权访问"})
|
||||
c.StopRun()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type authIdpPayload struct {
|
||||
Tid uint64 `json:"tid"`
|
||||
Provider string `json:"provider"`
|
||||
Name string `json:"name"`
|
||||
AppID string `json:"app_id"`
|
||||
AppSecret string `json:"app_secret"`
|
||||
ProxyURL string `json:"proxy_url"`
|
||||
Scopes string `json:"scopes"`
|
||||
AuthURL string `json:"auth_url"`
|
||||
TokenURL string `json:"token_url"`
|
||||
UserinfoURL string `json:"userinfo_url"`
|
||||
Status *int8 `json:"status"`
|
||||
}
|
||||
|
||||
func (c *PlatformAuthIdpController) parsePayload() (authIdpPayload, bool) {
|
||||
var p authIdpPayload
|
||||
raw, _ := io.ReadAll(c.Ctx.Request.Body)
|
||||
if len(raw) > 0 {
|
||||
if err := json.Unmarshal(raw, &p); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "参数错误"})
|
||||
return p, false
|
||||
}
|
||||
}
|
||||
return p, true
|
||||
}
|
||||
|
||||
// List 配置列表
|
||||
// GET /platform/authIdp/list?tid=0
|
||||
func (c *PlatformAuthIdpController) List() {
|
||||
tid, _ := c.GetInt64("tid", 0)
|
||||
var rows []models.AuthTenantIdp
|
||||
if _, err := models.Orm.QueryTable(new(models.AuthTenantIdp)).
|
||||
Filter("tid", tid).OrderBy("id").All(&rows); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 500, "msg": "查询失败: " + err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// 脱敏:不下发 AppSecret
|
||||
list := make([]map[string]interface{}, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
list = append(list, map[string]interface{}{
|
||||
"id": r.ID,
|
||||
"tid": r.Tid,
|
||||
"provider": r.Provider,
|
||||
"name": derefAuthIdp(r.Name),
|
||||
"app_id": derefAuthIdp(r.AppID),
|
||||
"proxy_url": derefAuthIdp(r.ProxyURL),
|
||||
"scopes": derefAuthIdp(r.Scopes),
|
||||
"auth_url": derefAuthIdp(r.AuthURL),
|
||||
"token_url": derefAuthIdp(r.TokenURL),
|
||||
"userinfo_url": derefAuthIdp(r.UserinfoURL),
|
||||
"status": r.Status,
|
||||
"has_secret": r.AppSecret != nil && *r.AppSecret != "",
|
||||
})
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200, "msg": "success",
|
||||
"data": map[string]interface{}{"list": list, "total": len(list)},
|
||||
})
|
||||
}
|
||||
|
||||
// Create 新增配置
|
||||
// POST /platform/authIdp/create
|
||||
func (c *PlatformAuthIdpController) Create() {
|
||||
p, ok := c.parsePayload()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
p.Provider = strings.TrimSpace(p.Provider)
|
||||
if p.Provider == "" {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "provider 不能为空"})
|
||||
return
|
||||
}
|
||||
if exist := models.Orm.QueryTable(new(models.AuthTenantIdp)).
|
||||
Filter("tid", p.Tid).Filter("provider", p.Provider).Exist(); exist {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "该登录方式已配置,请直接编辑"})
|
||||
return
|
||||
}
|
||||
|
||||
item := &models.AuthTenantIdp{
|
||||
Tid: p.Tid,
|
||||
Provider: p.Provider,
|
||||
Status: 1,
|
||||
}
|
||||
fillAuthIdp(item, &p)
|
||||
if p.Status != nil {
|
||||
item.Status = *p.Status
|
||||
}
|
||||
id, err := models.Orm.Insert(item)
|
||||
if err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 500, "msg": "创建失败: " + err.Error()})
|
||||
return
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{"code": 200, "msg": "success", "data": map[string]interface{}{"id": id}})
|
||||
}
|
||||
|
||||
// Edit 编辑配置(app_secret 留空表示不修改)
|
||||
// POST /platform/authIdp/edit/:id
|
||||
func (c *PlatformAuthIdpController) Edit() {
|
||||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "无效ID"})
|
||||
return
|
||||
}
|
||||
p, ok := c.parsePayload()
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
var row models.AuthTenantIdp
|
||||
if err := models.Orm.QueryTable(new(models.AuthTenantIdp)).Filter("id", id).One(&row); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 404, "msg": "记录不存在"})
|
||||
return
|
||||
}
|
||||
fillAuthIdp(&row, &p)
|
||||
if p.Status != nil {
|
||||
row.Status = *p.Status
|
||||
}
|
||||
if _, err := models.Orm.Update(&row); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 500, "msg": "更新失败: " + err.Error()})
|
||||
return
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{"code": 200, "msg": "success"})
|
||||
}
|
||||
|
||||
// Delete 删除配置
|
||||
// DELETE /platform/authIdp/delete/:id
|
||||
func (c *PlatformAuthIdpController) Delete() {
|
||||
id, err := strconv.ParseUint(c.Ctx.Input.Param(":id"), 10, 64)
|
||||
if err != nil || id == 0 {
|
||||
c.serveJSON(map[string]interface{}{"code": 400, "msg": "无效ID"})
|
||||
return
|
||||
}
|
||||
if _, err := models.Orm.QueryTable(new(models.AuthTenantIdp)).Filter("id", id).Delete(); err != nil {
|
||||
c.serveJSON(map[string]interface{}{"code": 500, "msg": "删除失败: " + err.Error()})
|
||||
return
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{"code": 200, "msg": "success"})
|
||||
}
|
||||
|
||||
// CallbackHint 返回各平台需要填写的回调地址(方便复制)
|
||||
// GET /platform/authIdp/callbackHint?provider=wechat
|
||||
func (c *PlatformAuthIdpController) CallbackHint() {
|
||||
provider := strings.TrimSpace(c.GetString("provider"))
|
||||
base := jwtutil.Issuer()
|
||||
if base == "" {
|
||||
scheme := "https"
|
||||
if c.Ctx.Request.TLS == nil {
|
||||
scheme = "http"
|
||||
}
|
||||
base = fmt.Sprintf("%s://%s/auth", scheme, c.Ctx.Request.Host)
|
||||
}
|
||||
c.serveJSON(map[string]interface{}{
|
||||
"code": 200,
|
||||
"data": map[string]interface{}{
|
||||
"callback": fmt.Sprintf("%s/third/%s/callback", base, provider),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- 工具
|
||||
|
||||
// fillAuthIdp 把请求参数写入模型;留空字段表示不修改
|
||||
func fillAuthIdp(item *models.AuthTenantIdp, p *authIdpPayload) {
|
||||
if v := strings.TrimSpace(p.Name); v != "" {
|
||||
item.Name = &v
|
||||
}
|
||||
if v := strings.TrimSpace(p.AppID); v != "" {
|
||||
item.AppID = &v
|
||||
}
|
||||
if v := strings.TrimSpace(p.AppSecret); v != "" {
|
||||
item.AppSecret = &v
|
||||
}
|
||||
if v := strings.TrimSpace(p.ProxyURL); v != "" {
|
||||
item.ProxyURL = &v
|
||||
}
|
||||
if v := strings.TrimSpace(p.Scopes); v != "" {
|
||||
item.Scopes = &v
|
||||
}
|
||||
if v := strings.TrimSpace(p.AuthURL); v != "" {
|
||||
item.AuthURL = &v
|
||||
}
|
||||
if v := strings.TrimSpace(p.TokenURL); v != "" {
|
||||
item.TokenURL = &v
|
||||
}
|
||||
if v := strings.TrimSpace(p.UserinfoURL); v != "" {
|
||||
item.UserinfoURL = &v
|
||||
}
|
||||
}
|
||||
|
||||
func derefAuthIdp(p *string) string {
|
||||
if p == nil {
|
||||
return ""
|
||||
}
|
||||
return *p
|
||||
}
|
||||
Reference in New Issue
Block a user