From 7c1fc4fa6d0f922bec9ea72f8d1485be0f65b46c Mon Sep 17 00:00:00 2001 From: Tao Chen Date: Thu, 31 Oct 2024 09:21:30 +0800 Subject: [PATCH] add some /admin/ to surport web OIDC --- http/controller/admin/login.go | 87 ++++++++++++++++++- http/controller/api/ouath.go | 151 +++++++++++++++++++++------------ http/router/admin.go | 4 +- 3 files changed, 188 insertions(+), 54 deletions(-) diff --git a/http/controller/admin/login.go b/http/controller/admin/login.go index b175044..21f432c 100644 --- a/http/controller/admin/login.go +++ b/http/controller/admin/login.go @@ -5,6 +5,8 @@ import ( "Gwen/http/request/admin" "Gwen/http/response" adResp "Gwen/http/response/admin" + apiReq "Gwen/http/request/api" + "Gwen/http/controller/api" "Gwen/model" "Gwen/service" "fmt" @@ -51,7 +53,7 @@ func (ct *Login) Login(c *gin.Context) { ut := service.AllService.UserService.Login(u, &model.LoginLog{ UserId: u.Id, Client: "webadmin", - Uuid: "", + Uuid: "", //must be empty Ip: c.ClientIP(), Type: "account", Platform: f.Platform, @@ -82,3 +84,86 @@ func (ct *Login) Logout(c *gin.Context) { } response.Success(c, nil) } + + +// LoginOptions +// @Tags 登录 +// @Summary 登录选项 +// @Description 登录选项 +// @Accept json +// @Produce json +// @Success 200 {object} []string +// @Failure 500 {object} response.ErrorResponse +// @Router /admin/login-options [post] +// 直接调用/api/login的LoginOptions方法 +func (ct *Login) LoginOptions(c *gin.Context) { + l := &api.Login{} + l.LoginOptions(c) +} + + +// OidcAuth +// @Tags Oauth +// @Summary OidcAuth +// @Description OidcAuth +// @Accept json +// @Produce json +// @Router /admin/oidc/auth [post] +func (ct *Login) OidcAuth(c *gin.Context) { + // o := &api.Oauth{} + // o.OidcAuth(c) + f := &apiReq.OidcAuthRequest{} + err := c.ShouldBindJSON(f) + if err != nil { + response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error()) + return + } + + err, code, url := service.AllService.OauthService.BeginAuth(f.Op) + if err != nil { + response.Error(c, response.TranslateMsg(c, err.Error())) + return + } + + service.AllService.OauthService.SetOauthCache(code, &service.OauthCacheItem{ + Action: service.OauthActionTypeLogin, + Op: f.Op, + Id: f.Id, + DeviceType: "webadmin", + // DeviceOs: ct.Platform(c), + DeviceOs: f.DeviceInfo.Os, + Uuid: f.Uuid, + }, 5*60) + + response.Success(c, gin.H{ + "code": code, + "url": url, + }) +} + + + +// OidcAuthQuery +// @Tags Oauth +// @Summary OidcAuthQuery +// @Description OidcAuthQuery +// @Accept json +// @Produce json +// @Success 200 {object} response.Response{data=adResp.LoginPayload} +// @Failure 500 {object} response.Response +// @Router /admin/oidc/auth-query [get] +func (ct *Login) OidcAuthQuery(c *gin.Context) { + o := &api.Oauth{} + u, ut := o.OidcAuthQueryPre(c) + if ut == nil { + return + } + fmt.Println("u:", u) + fmt.Println("ut:", ut) + response.Success(c, &adResp.LoginPayload{ + Token: ut.Token, + Username: u.Username, + RouteNames: service.AllService.UserService.RouteNames(u), + Nickname: u.Nickname, + }) +} \ No newline at end of file diff --git a/http/controller/api/ouath.go b/http/controller/api/ouath.go index 47fa129..4ad15db 100644 --- a/http/controller/api/ouath.go +++ b/http/controller/api/ouath.go @@ -59,6 +59,59 @@ func (o *Oauth) OidcAuth(c *gin.Context) { }) } +func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken) { + var u *model.User + var ut *model.UserToken + q := &api.OidcAuthQuery{} + + // 解析查询参数并处理错误 + if err := c.ShouldBindQuery(q); err != nil { + response.Error(c, response.TranslateMsg(c, "ParamsError")+": "+err.Error()) + return nil, nil + } + + // 获取 OAuth 缓存 + v := service.AllService.OauthService.GetOauthCache(q.Code) + if v == nil { + response.Error(c, response.TranslateMsg(c, "OauthExpired")) + return nil, nil + } + + // 如果 UserId 为 0,说明还在授权中 + if v.UserId == 0 { + c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress"}) + return nil, nil + } + + // 获取用户信息 + u = service.AllService.UserService.InfoById(v.UserId) + if u == nil { + response.Error(c, response.TranslateMsg(c, "UserNotFound")) + return nil, nil + } + + // 删除 OAuth 缓存 + service.AllService.OauthService.DeleteOauthCache(q.Code) + + // 创建登录日志并生成用户令牌 + ut = service.AllService.UserService.Login(u, &model.LoginLog{ + UserId: u.Id, + Client: v.DeviceType, + Uuid: v.Uuid, + Ip: c.ClientIP(), + Type: model.LoginLogTypeOauth, + Platform: v.DeviceOs, + }) + + if ut == nil { + response.Error(c, response.TranslateMsg(c, "LoginFailed")) + return nil, nil + } + + // 返回用户令牌 + return u, ut +} + // OidcAuthQuery // @Tags Oauth // @Summary OidcAuthQuery @@ -69,33 +122,7 @@ func (o *Oauth) OidcAuth(c *gin.Context) { // @Failure 500 {object} response.ErrorResponse // @Router /oidc/auth-query [get] func (o *Oauth) OidcAuthQuery(c *gin.Context) { - q := &api.OidcAuthQuery{} - err := c.ShouldBindQuery(q) - if err != nil { - response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error()) - return - } - v := service.AllService.OauthService.GetOauthCache(q.Code) - if v == nil { - response.Error(c, response.TranslateMsg(c, "OauthExpired")) - return - } - if v.UserId == 0 { - //正在授权 - c.JSON(http.StatusOK, gin.H{}) - return - } - u := service.AllService.UserService.InfoById(v.UserId) - //fmt.Println("auth success u", u) - service.AllService.OauthService.DeleteOauthCache(q.Code) - ut := service.AllService.UserService.Login(u, &model.LoginLog{ - UserId: u.Id, - Client: v.DeviceType, - Uuid: v.Uuid, - Ip: c.ClientIP(), - Type: model.LoginLogTypeOauth, - Platform: v.DeviceOs, - }) + u, ut := o.OidcAuthQueryPre(c) c.JSON(http.StatusOK, apiResp.LoginRes{ AccessToken: ut.Token, Type: "access_token", @@ -129,6 +156,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) { ty := v.Op ac := v.Action + var u *model.User //fmt.Println("ty ac ", ty, ac) if ty == model.OauthTypeGithub { code := c.Query("code") @@ -145,7 +173,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) { return } //绑定 - u := service.AllService.UserService.InfoById(v.UserId) + u = service.AllService.UserService.InfoById(v.UserId) if u == nil { c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound")) return @@ -164,7 +192,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) { c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess")) return } - u := service.AllService.UserService.InfoByGithubId(strconv.Itoa(userData.Id)) + u = service.AllService.UserService.InfoByGithubId(strconv.Itoa(userData.Id)) if u == nil { oa := service.AllService.OauthService.InfoByOp(ty) if !*oa.AutoRegister { @@ -184,15 +212,13 @@ func (o *Oauth) OauthCallback(c *gin.Context) { } } - v.UserId = u.Id - service.AllService.OauthService.SetOauthCache(cacheKey, v, 0) - c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess")) - return + // v.UserId = u.Id + // service.AllService.OauthService.SetOauthCache(cacheKey, v, 0) + // c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess")) + // return } - } - - if ty == model.OauthTypeGoogle { + } else if ty == model.OauthTypeGoogle { code := c.Query("code") err, userData := service.AllService.OauthService.GoogleCallback(code) if err != nil { @@ -209,7 +235,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) { return } //绑定 - u := service.AllService.UserService.InfoById(v.UserId) + u = service.AllService.UserService.InfoById(v.UserId) if u == nil { c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound")) return @@ -227,7 +253,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) { c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess")) return } - u := service.AllService.UserService.InfoByGoogleEmail(userData.Email) + u = service.AllService.UserService.InfoByGoogleEmail(userData.Email) if u == nil { oa := service.AllService.OauthService.InfoByOp(ty) if !*oa.AutoRegister { @@ -248,13 +274,12 @@ func (o *Oauth) OauthCallback(c *gin.Context) { } } - v.UserId = u.Id - service.AllService.OauthService.SetOauthCache(cacheKey, v, 0) - c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess")) - return + // v.UserId = u.Id + // service.AllService.OauthService.SetOauthCache(cacheKey, v, 0) + // c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess")) + // return } - } - if ty == model.OauthTypeOidc { + } else if ty == model.OauthTypeOidc { code := c.Query("code") err, userData := service.AllService.OauthService.OidcCallback(code) if err != nil { @@ -271,7 +296,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) { return } //绑定 - u := service.AllService.UserService.InfoById(v.UserId) + u = service.AllService.UserService.InfoById(v.UserId) if u == nil { c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound")) return @@ -289,7 +314,7 @@ func (o *Oauth) OauthCallback(c *gin.Context) { c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess")) return } - u := service.AllService.UserService.InfoByOidcSub(userData.Sub) + u = service.AllService.UserService.InfoByOidcSub(userData.Sub) if u == nil { oa := service.AllService.OauthService.InfoByOp(ty) if !*oa.AutoRegister { @@ -311,13 +336,35 @@ func (o *Oauth) OauthCallback(c *gin.Context) { } } - v.UserId = u.Id - service.AllService.OauthService.SetOauthCache(cacheKey, v, 0) - c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess")) - return + // v.UserId = u.Id + // service.AllService.OauthService.SetOauthCache(cacheKey, v, 0) + // c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess")) + // return } } - - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "SystemError")) + // 如果u为空,说明没有绑定用户 + if u == nil { + c.String(http.StatusInternalServerError, response.TranslateMsg(c, "SystemError")) + return + } + // 认证成功,设置缓存 + v.UserId = u.Id + service.AllService.OauthService.SetOauthCache(cacheKey, v, 0) + // 如果是webadmin,登录成功后跳转到webadmin + if v.DeviceType == "webadmin" { + service.AllService.UserService.Login(u, &model.LoginLog{ + UserId: u.Id, + Client: "webadmin", + Uuid: "",//must be empty + Ip: c.ClientIP(), + Type: "account", + Platform: v.DeviceOs, + }) + url := global.Config.Rustdesk.ApiServer + "/_admin/#/" + c.Redirect(http.StatusFound, url) + return + } + c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess")) + return } diff --git a/http/router/admin.go b/http/router/admin.go index 2636fab..2026cc6 100644 --- a/http/router/admin.go +++ b/http/router/admin.go @@ -33,7 +33,6 @@ func Init(g *gin.Engine) { rs := &admin.Rustdesk{} adg.GET("/server-config", rs.ServerConfig) adg.GET("/app-config", rs.AppConfig) - //访问静态文件 //g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/upload")) } @@ -41,6 +40,9 @@ func LoginBind(rg *gin.RouterGroup) { cont := &admin.Login{} rg.POST("/login", cont.Login) rg.POST("/logout", cont.Logout) + rg.GET("/login-options", cont.LoginOptions) + rg.POST("/oidc/auth", cont.OidcAuth) + rg.GET("/oidc/auth-query", cont.OidcAuthQuery) } func UserBind(rg *gin.RouterGroup) {