From 72e04a140d60d32221c3406db6b551b270710629 Mon Sep 17 00:00:00 2001 From: TsMask <340112800@qq.com> Date: Tue, 12 Aug 2025 10:35:18 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=A2=E6=88=B7=E7=AB=AFoauth2?= =?UTF-8?q?=E8=AE=A4=E8=AF=81=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app.go | 4 +- src/modules/auth/auth.go | 58 ++++++ .../{oauth2 => auth}/controller/oauth2.go | 4 +- src/modules/auth/controller/oauth2_client.go | 168 ++++++++++++++++++ .../model/oauth2_body.go} | 7 + .../{oauth2 => auth}/model/oauth2_client.go | 0 .../model/oauth2_log_login.go | 0 .../repository/oauth2_client.go | 2 +- .../repository/oauth2_log_login.go | 7 +- .../{oauth2 => auth}/service/oauth2.go | 4 +- .../{oauth2 => auth}/service/oauth2_client.go | 8 +- .../service/oauth2_log_login.go | 4 +- .../{oauth2/open_api.go => oam/oauth2_api.go} | 6 +- src/modules/oauth2/model/code_query.go | 8 - src/modules/oauth2/oauth2.go | 74 -------- 15 files changed, 252 insertions(+), 102 deletions(-) rename src/modules/{oauth2 => auth}/controller/oauth2.go (98%) create mode 100644 src/modules/auth/controller/oauth2_client.go rename src/modules/{oauth2/model/token_body.go => auth/model/oauth2_body.go} (67%) rename src/modules/{oauth2 => auth}/model/oauth2_client.go (100%) rename src/modules/{oauth2 => auth}/model/oauth2_log_login.go (100%) rename src/modules/{oauth2 => auth}/repository/oauth2_client.go (99%) rename src/modules/{oauth2 => auth}/repository/oauth2_log_login.go (96%) rename src/modules/{oauth2 => auth}/service/oauth2.go (96%) rename src/modules/{oauth2 => auth}/service/oauth2_client.go (87%) rename src/modules/{oauth2 => auth}/service/oauth2_log_login.go (96%) rename src/modules/{oauth2/open_api.go => oam/oauth2_api.go} (85%) delete mode 100644 src/modules/oauth2/model/code_query.go delete mode 100644 src/modules/oauth2/oauth2.go diff --git a/src/app.go b/src/app.go index da30bf86..407f533a 100644 --- a/src/app.go +++ b/src/app.go @@ -17,7 +17,6 @@ import ( networkelement "be.ems/src/modules/network_element" "be.ems/src/modules/notification" "be.ems/src/modules/oam" - "be.ems/src/modules/oauth2" "be.ems/src/modules/system" "be.ems/src/modules/tool" "be.ems/src/modules/trace" @@ -84,10 +83,9 @@ func ModulesRoute(app *gin.Engine) { system.Setup(app) // 认证模块 auth.Setup(app) - // 开放客户端模块 - oauth2.Setup(app) // 网元OAM对接 oam.Setup(app) + oam.SetupOauth2(app) // 通用模块 common.Setup(app) diff --git a/src/modules/auth/auth.go b/src/modules/auth/auth.go index 801e916f..d177b4b4 100644 --- a/src/modules/auth/auth.go +++ b/src/modules/auth/auth.go @@ -116,4 +116,62 @@ func Setup(router *gin.Engine) { ) } + // 客户端授权管理 + oauth2Client := controller.NewOauth2Client + oauth2ClientGroup := router.Group("/oauth2/client") + { + oauth2ClientGroup.GET("/list", + middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), + oauth2Client.List, + ) + oauth2ClientGroup.GET("/:clientId", + middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), + oauth2Client.Info, + ) + oauth2ClientGroup.POST("", + middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), + middleware.OperateLog(middleware.OptionNew("log.operate.title.oauth2client", middleware.BUSINESS_TYPE_INSERT)), + oauth2Client.Add, + ) + oauth2ClientGroup.PUT("", + middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), + middleware.OperateLog(middleware.OptionNew("log.operate.title.oauth2client", middleware.BUSINESS_TYPE_UPDATE)), + oauth2Client.Edit, + ) + oauth2ClientGroup.DELETE("/:id", + middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), + middleware.OperateLog(middleware.OptionNew("log.operate.title.oauth2client", middleware.BUSINESS_TYPE_DELETE)), + oauth2Client.Remove, + ) + } + + // 授权认证 + oauth2 := controller.NewOauth2 + oauth2Group := router.Group("/oauth2") + { + oauth2Group.GET("/authorize", + middleware.RateLimit(middleware.LimitOption{ + Time: 60, + Count: 30, + Type: middleware.LIMIT_IP, + }), + oauth2.Authorize, + ) + oauth2Group.POST("/token", + middleware.RateLimit(middleware.LimitOption{ + Time: 180, + Count: 15, + Type: middleware.LIMIT_IP, + }), + oauth2.Token, + ) + oauth2Group.POST("/refresh-token", + middleware.RateLimit(middleware.LimitOption{ + Time: 60, + Count: 5, + Type: middleware.LIMIT_IP, + }), + oauth2.RefreshToken, + ) + } } diff --git a/src/modules/oauth2/controller/oauth2.go b/src/modules/auth/controller/oauth2.go similarity index 98% rename from src/modules/oauth2/controller/oauth2.go rename to src/modules/auth/controller/oauth2.go index bb8fceb3..6da8add9 100644 --- a/src/modules/oauth2/controller/oauth2.go +++ b/src/modules/auth/controller/oauth2.go @@ -11,8 +11,8 @@ import ( "be.ems/src/framework/reqctx" "be.ems/src/framework/resp" "be.ems/src/framework/token" - "be.ems/src/modules/oauth2/model" - "be.ems/src/modules/oauth2/service" + "be.ems/src/modules/auth/model" + "be.ems/src/modules/auth/service" ) // NewOauth2 实例化控制层 diff --git a/src/modules/auth/controller/oauth2_client.go b/src/modules/auth/controller/oauth2_client.go new file mode 100644 index 00000000..830c9b71 --- /dev/null +++ b/src/modules/auth/controller/oauth2_client.go @@ -0,0 +1,168 @@ +package controller + +import ( + "fmt" + "strings" + + "github.com/gin-gonic/gin" + + "be.ems/src/framework/i18n" + "be.ems/src/framework/reqctx" + "be.ems/src/framework/resp" + "be.ems/src/framework/utils/parse" + "be.ems/src/modules/auth/model" + "be.ems/src/modules/auth/service" +) + +// NewOauth2Client 实例化控制层 +var NewOauth2Client = &Oauth2ClientController{ + oauth2ClientService: service.NewOauth2ClientService, +} + +// Oauth2ClientController 客户端授权管理 控制层处理 +// +// PATH /oauth2/client +type Oauth2ClientController struct { + oauth2ClientService *service.Oauth2ClientService // 用户授权第三方应用信息服务 +} + +// List 列表 +// +// GET /list +func (s Oauth2ClientController) List(c *gin.Context) { + query := reqctx.QueryMap(c) + rows, total := s.oauth2ClientService.FindByPage(query) + c.JSON(200, resp.OkData(map[string]any{"rows": rows, "total": total})) +} + +// Info 信息 +// +// GET /:clientId +func (s Oauth2ClientController) Info(c *gin.Context) { + clientId := c.Param("clientId") + if clientId == "" { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: clientId is empty")) + return + } + + info := s.oauth2ClientService.FindByClientId(clientId) + if info.ClientId == clientId { + c.JSON(200, resp.OkData(info)) + return + } + c.JSON(200, resp.ErrMsg("clientId does not exist")) +} + +// Add 新增 +// +// POST / +func (s Oauth2ClientController) Add(c *gin.Context) { + var body model.Oauth2Client + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + if body.Id > 0 { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id not is empty")) + return + } + + // 本地IP地址不支持 + localHosts := []string{"127.0.0.1", "localhost", "::ffff:", "::1"} + localHost := false + for _, host := range localHosts { + if strings.Contains(body.IPWhite, host) { + localHost = true + break + } + } + if localHost { + c.JSON(200, resp.ErrMsg("no support local host")) + return + } + + body.CreateBy = reqctx.LoginUserToUserName(c) + insertId := s.oauth2ClientService.Insert(body) + if insertId > 0 { + c.JSON(200, resp.OkData(insertId)) + return + } + c.JSON(200, resp.Err(nil)) +} + +// Edit 更新 +// +// PUT / +func (s Oauth2ClientController) Edit(c *gin.Context) { + var body model.Oauth2Client + if err := c.ShouldBindBodyWithJSON(&body); err != nil { + errMsgs := fmt.Sprintf("bind err: %s", resp.FormatBindError(err)) + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_PARSER, errMsgs)) + return + } + if body.Id <= 0 { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty")) + return + } + + // 本地IP地址不支持 + localHosts := []string{"127.0.0.1", "localhost", "::ffff:", "::1"} + localHost := false + for _, host := range localHosts { + if strings.Contains(body.IPWhite, host) { + localHost = true + break + } + } + if localHost { + c.JSON(200, resp.ErrMsg("no support local host")) + return + } + + // 查询信息 + info := s.oauth2ClientService.FindById(body.Id) + if info.ClientId == "" || info.Id != body.Id { + c.JSON(200, resp.ErrMsg("modification failed, data not exist")) + return + } + + info.Title = body.Title + info.IPWhite = body.IPWhite + info.Remark = body.Remark + info.UpdateBy = reqctx.LoginUserToUserName(c) + rowsAffected := s.oauth2ClientService.Update(info) + if rowsAffected > 0 { + c.JSON(200, resp.Ok(nil)) + return + } + c.JSON(200, resp.Err(nil)) +} + +// Remove 删除 +// +// DELETE /:id +func (s Oauth2ClientController) Remove(c *gin.Context) { + language := reqctx.AcceptLanguage(c) + id := c.Param("id") + if id == "" { + c.JSON(422, resp.CodeMsg(resp.CODE_PARAM_CHEACK, "bind err: id is empty")) + return + } + + // 处理字符转id数组后去重 + uniqueIDs := parse.RemoveDuplicatesToArray(id, ",") + // 转换成int64数组类型 + ids := make([]int64, 0) + for _, v := range uniqueIDs { + ids = append(ids, parse.Number(v)) + } + + rows, err := s.oauth2ClientService.DeleteByIds(ids) + if err != nil { + c.JSON(200, resp.ErrMsg(err.Error())) + return + } + msg := i18n.TTemplate(language, "app.common.deleteSuccess", map[string]any{"num": rows}) + c.JSON(200, resp.OkMsg(msg)) +} diff --git a/src/modules/oauth2/model/token_body.go b/src/modules/auth/model/oauth2_body.go similarity index 67% rename from src/modules/oauth2/model/token_body.go rename to src/modules/auth/model/oauth2_body.go index 2f82ab8f..17a8e165 100644 --- a/src/modules/oauth2/model/token_body.go +++ b/src/modules/auth/model/oauth2_body.go @@ -8,3 +8,10 @@ type TokenBody struct { Code string `json:"code"` // 授权拿到的code值 RefreshToken string `json:"refreshToken"` // 刷新令牌 } + +// CodeQuery 重定向授权码参数 +type CodeQuery struct { + RedirectUrl string `form:"redirectUrl" binding:"required"` // 授权回调地址 + ClientId string `form:"clientId" binding:"required"` // 申请得到的客户端ID + State string `form:"state" binding:"required"` // 随机字符串,认证服务器会原封不动地返回这个值 +} diff --git a/src/modules/oauth2/model/oauth2_client.go b/src/modules/auth/model/oauth2_client.go similarity index 100% rename from src/modules/oauth2/model/oauth2_client.go rename to src/modules/auth/model/oauth2_client.go diff --git a/src/modules/oauth2/model/oauth2_log_login.go b/src/modules/auth/model/oauth2_log_login.go similarity index 100% rename from src/modules/oauth2/model/oauth2_log_login.go rename to src/modules/auth/model/oauth2_log_login.go diff --git a/src/modules/oauth2/repository/oauth2_client.go b/src/modules/auth/repository/oauth2_client.go similarity index 99% rename from src/modules/oauth2/repository/oauth2_client.go rename to src/modules/auth/repository/oauth2_client.go index 1c7253c4..503ea2c4 100644 --- a/src/modules/oauth2/repository/oauth2_client.go +++ b/src/modules/auth/repository/oauth2_client.go @@ -6,7 +6,7 @@ import ( "be.ems/src/framework/database/db" "be.ems/src/framework/logger" - "be.ems/src/modules/oauth2/model" + "be.ems/src/modules/auth/model" ) // NewOauth2Client 实例化数据层 diff --git a/src/modules/oauth2/repository/oauth2_log_login.go b/src/modules/auth/repository/oauth2_log_login.go similarity index 96% rename from src/modules/oauth2/repository/oauth2_log_login.go rename to src/modules/auth/repository/oauth2_log_login.go index f712b9d4..71dc09b7 100644 --- a/src/modules/oauth2/repository/oauth2_log_login.go +++ b/src/modules/auth/repository/oauth2_log_login.go @@ -7,7 +7,7 @@ import ( "be.ems/src/framework/database/db" "be.ems/src/framework/logger" - "be.ems/src/modules/oauth2/model" + "be.ems/src/modules/auth/model" ) // NewOauth2LogLogin 实例化数据层 @@ -69,9 +69,10 @@ func (r Oauth2LogLoginRepository) SelectByPage(query map[string]string) ([]model sortOrder := sortOrderArr[i] // 排序字段 sort := "id" - if sortBy == "loginIp" { + switch sortBy { + case "loginIp": sort = "login_ip" - } else if sortBy == "createTime" { + case "createTime": sort = "create_time" } // 排序方式 diff --git a/src/modules/oauth2/service/oauth2.go b/src/modules/auth/service/oauth2.go similarity index 96% rename from src/modules/oauth2/service/oauth2.go rename to src/modules/auth/service/oauth2.go index 3ca444c4..81b29c77 100644 --- a/src/modules/oauth2/service/oauth2.go +++ b/src/modules/auth/service/oauth2.go @@ -10,8 +10,8 @@ import ( "be.ems/src/framework/token" "be.ems/src/framework/utils/crypto" "be.ems/src/framework/utils/generate" - "be.ems/src/modules/oauth2/model" - "be.ems/src/modules/oauth2/repository" + "be.ems/src/modules/auth/model" + "be.ems/src/modules/auth/repository" ) // NewOauth2Service 实例化服务层 diff --git a/src/modules/oauth2/service/oauth2_client.go b/src/modules/auth/service/oauth2_client.go similarity index 87% rename from src/modules/oauth2/service/oauth2_client.go rename to src/modules/auth/service/oauth2_client.go index 6edc055f..de44d6c0 100644 --- a/src/modules/oauth2/service/oauth2_client.go +++ b/src/modules/auth/service/oauth2_client.go @@ -4,8 +4,8 @@ import ( "fmt" "be.ems/src/framework/utils/generate" - "be.ems/src/modules/oauth2/model" - "be.ems/src/modules/oauth2/repository" + "be.ems/src/modules/auth/model" + "be.ems/src/modules/auth/repository" ) // NewOauth2ClientService 实例化服务层 @@ -55,11 +55,11 @@ func (s Oauth2ClientService) DeleteByIds(ids []int64) (int64, error) { arr := s.oauth2ClientRepository.SelectByIds(ids) if len(arr) <= 0 { // return 0, fmt.Errorf("没有权限访问用户授权第三方应用数据!") - return 0, fmt.Errorf("No permission to access user-authorized third-party application data!") + return 0, fmt.Errorf("no permission to access user-authorized third-party application data") } if len(arr) == len(ids) { return s.oauth2ClientRepository.DeleteByIds(ids), nil } // return 0, fmt.Errorf("删除用户授权第三方应用信息失败!") - return 0, fmt.Errorf("Failed to delete user-authorized third-party application information!") + return 0, fmt.Errorf("failed to delete user-authorized third-party application information") } diff --git a/src/modules/oauth2/service/oauth2_log_login.go b/src/modules/auth/service/oauth2_log_login.go similarity index 96% rename from src/modules/oauth2/service/oauth2_log_login.go rename to src/modules/auth/service/oauth2_log_login.go index e400fa9c..cd30dc01 100644 --- a/src/modules/oauth2/service/oauth2_log_login.go +++ b/src/modules/auth/service/oauth2_log_login.go @@ -6,8 +6,8 @@ import ( "be.ems/src/framework/constants" "be.ems/src/framework/utils/date" "be.ems/src/framework/utils/file" - "be.ems/src/modules/oauth2/model" - "be.ems/src/modules/oauth2/repository" + "be.ems/src/modules/auth/model" + "be.ems/src/modules/auth/repository" ) // NewOauth2LogLogin 实例化服务层 diff --git a/src/modules/oauth2/open_api.go b/src/modules/oam/oauth2_api.go similarity index 85% rename from src/modules/oauth2/open_api.go rename to src/modules/oam/oauth2_api.go index 84f96e03..f8022cff 100644 --- a/src/modules/oauth2/open_api.go +++ b/src/modules/oam/oauth2_api.go @@ -1,4 +1,4 @@ -package oauth2 +package oam import ( "github.com/gin-gonic/gin" @@ -8,8 +8,8 @@ import ( neController "be.ems/src/modules/network_element/controller" ) -// openAPI 客户端授权开放接口 -func openAPI(router *gin.Engine) { +// SetupOauth2 客户端授权开放接口 +func SetupOauth2(router *gin.Engine) { openApiGroup := router.Group("/open-api") // 监控 diff --git a/src/modules/oauth2/model/code_query.go b/src/modules/oauth2/model/code_query.go deleted file mode 100644 index 9c32a195..00000000 --- a/src/modules/oauth2/model/code_query.go +++ /dev/null @@ -1,8 +0,0 @@ -package model - -// CodeQuery 重定向授权码参数 -type CodeQuery struct { - RedirectUrl string `form:"redirectUrl" binding:"required"` // 授权回调地址 - ClientId string `form:"clientId" binding:"required"` // 申请得到的客户端ID - State string `form:"state" binding:"required"` // 随机字符串,认证服务器会原封不动地返回这个值 -} diff --git a/src/modules/oauth2/oauth2.go b/src/modules/oauth2/oauth2.go deleted file mode 100644 index 7cc1cbac..00000000 --- a/src/modules/oauth2/oauth2.go +++ /dev/null @@ -1,74 +0,0 @@ -package oauth2 - -import ( - "github.com/gin-gonic/gin" - - "be.ems/src/framework/logger" - "be.ems/src/framework/middleware" - "be.ems/src/modules/oauth2/controller" -) - -// Setup 模块路由注册 -func Setup(router *gin.Engine) { - logger.Infof("开始加载 ====> oauth2 模块路由") - - // 客户端授权管理 - oauth2ClientGroup := router.Group("/oauth2/client") - { - oauth2ClientGroup.GET("/list", - middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), - controller.NewOauth2Client.List, - ) - oauth2ClientGroup.GET("/:clientId", - middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), - controller.NewOauth2Client.Info, - ) - oauth2ClientGroup.POST("", - middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), - middleware.OperateLog(middleware.OptionNew("log.operate.title.oauth2client", middleware.BUSINESS_TYPE_INSERT)), - controller.NewOauth2Client.Add, - ) - oauth2ClientGroup.PUT("", - middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), - middleware.OperateLog(middleware.OptionNew("log.operate.title.oauth2client", middleware.BUSINESS_TYPE_UPDATE)), - controller.NewOauth2Client.Edit, - ) - oauth2ClientGroup.DELETE("/:id", - middleware.AuthorizeUser(map[string][]string{"matchRoles": {"admin"}}), - middleware.OperateLog(middleware.OptionNew("log.operate.title.oauth2client", middleware.BUSINESS_TYPE_DELETE)), - controller.NewOauth2Client.Remove, - ) - } - - // 授权认证 - oauth2Group := router.Group("/oauth2") - { - oauth2Group.GET("/authorize", - middleware.RateLimit(middleware.LimitOption{ - Time: 60, - Count: 30, - Type: middleware.LIMIT_IP, - }), - controller.NewOauth2.Authorize, - ) - oauth2Group.POST("/token", - middleware.RateLimit(middleware.LimitOption{ - Time: 180, - Count: 15, - Type: middleware.LIMIT_IP, - }), - controller.NewOauth2.Token, - ) - oauth2Group.POST("/refresh-token", - middleware.RateLimit(middleware.LimitOption{ - Time: 60, - Count: 5, - Type: middleware.LIMIT_IP, - }), - controller.NewOauth2.RefreshToken, - ) - } - - // ==== 授权认证的开放接口 ==== - openAPI(router) -}