diff --git a/docs/admin/admin_docs.go b/docs/admin/admin_docs.go index 684818c..8fb653e 100644 --- a/docs/admin/admin_docs.go +++ b/docs/admin/admin_docs.go @@ -1453,6 +1453,38 @@ const docTemplateadmin = `{ } } }, + "/admin/login-options": { + "post": { + "description": "登录选项", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "登录" + ], + "summary": "登录选项", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.ErrorResponse" + } + } + } + } + }, "/admin/loginLog/delete": { "post": { "security": [ @@ -1922,6 +1954,63 @@ const docTemplateadmin = `{ } } }, + "/admin/oidc/auth": { + "post": { + "description": "OidcAuth", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Oauth" + ], + "summary": "OidcAuth", + "responses": {} + } + }, + "/admin/oidc/auth-query": { + "get": { + "description": "OidcAuthQuery", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Oauth" + ], + "summary": "OidcAuthQuery", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/admin.LoginPayload" + } + } + } + ] + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, "/admin/peer/create": { "post": { "security": [ @@ -3979,6 +4068,14 @@ const docTemplateadmin = `{ } } }, + "response.ErrorResponse": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + }, "response.Response": { "type": "object", "properties": { diff --git a/docs/admin/admin_swagger.json b/docs/admin/admin_swagger.json index 27961d3..f41ba63 100644 --- a/docs/admin/admin_swagger.json +++ b/docs/admin/admin_swagger.json @@ -1446,6 +1446,38 @@ } } }, + "/admin/login-options": { + "post": { + "description": "登录选项", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "登录" + ], + "summary": "登录选项", + "responses": { + "200": { + "description": "OK", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.ErrorResponse" + } + } + } + } + }, "/admin/loginLog/delete": { "post": { "security": [ @@ -1915,6 +1947,63 @@ } } }, + "/admin/oidc/auth": { + "post": { + "description": "OidcAuth", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Oauth" + ], + "summary": "OidcAuth", + "responses": {} + } + }, + "/admin/oidc/auth-query": { + "get": { + "description": "OidcAuthQuery", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "Oauth" + ], + "summary": "OidcAuthQuery", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/response.Response" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/admin.LoginPayload" + } + } + } + ] + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.Response" + } + } + } + } + }, "/admin/peer/create": { "post": { "security": [ @@ -3972,6 +4061,14 @@ } } }, + "response.ErrorResponse": { + "type": "object", + "properties": { + "error": { + "type": "string" + } + } + }, "response.Response": { "type": "object", "properties": { diff --git a/docs/admin/admin_swagger.yaml b/docs/admin/admin_swagger.yaml index 1d6aeb2..1008a77 100644 --- a/docs/admin/admin_swagger.yaml +++ b/docs/admin/admin_swagger.yaml @@ -653,6 +653,11 @@ definitions: total: type: integer type: object + response.ErrorResponse: + properties: + error: + type: string + type: object response.Response: properties: code: @@ -1520,6 +1525,27 @@ paths: summary: 登录 tags: - 登录 + /admin/login-options: + post: + consumes: + - application/json + description: 登录选项 + produces: + - application/json + responses: + "200": + description: OK + schema: + items: + type: string + type: array + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.ErrorResponse' + summary: 登录选项 + tags: + - 登录 /admin/loginLog/delete: post: consumes: @@ -1799,6 +1825,41 @@ paths: summary: Oauth编辑 tags: - Oauth + /admin/oidc/auth: + post: + consumes: + - application/json + description: OidcAuth + produces: + - application/json + responses: {} + summary: OidcAuth + tags: + - Oauth + /admin/oidc/auth-query: + get: + consumes: + - application/json + description: OidcAuthQuery + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/response.Response' + - properties: + data: + $ref: '#/definitions/admin.LoginPayload' + type: object + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.Response' + summary: OidcAuthQuery + tags: + - Oauth /admin/peer/create: post: consumes: diff --git a/http/controller/admin/login.go b/http/controller/admin/login.go index 21f432c..3d6ea12 100644 --- a/http/controller/admin/login.go +++ b/http/controller/admin/login.go @@ -2,15 +2,16 @@ package admin import ( "Gwen/global" + "Gwen/http/controller/api" "Gwen/http/request/admin" + apiReq "Gwen/http/request/api" "Gwen/http/response" adResp "Gwen/http/response/admin" - apiReq "Gwen/http/request/api" - "Gwen/http/controller/api" "Gwen/model" "Gwen/service" "fmt" "github.com/gin-gonic/gin" + "gorm.io/gorm" ) type Login struct { @@ -85,7 +86,6 @@ func (ct *Login) Logout(c *gin.Context) { response.Success(c, nil) } - // LoginOptions // @Tags 登录 // @Summary 登录选项 @@ -95,13 +95,17 @@ func (ct *Login) Logout(c *gin.Context) { // @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) + res := service.AllService.OauthService.List(1, 100, func(tx *gorm.DB) { + tx.Select("op").Order("id") + }) + var ops []string + for _, v := range res.Oauths { + ops = append(ops, v.Op) + } + response.Success(c, ops) } - // OidcAuth // @Tags Oauth // @Summary OidcAuth @@ -126,13 +130,13 @@ func (ct *Login) OidcAuth(c *gin.Context) { } service.AllService.OauthService.SetOauthCache(code, &service.OauthCacheItem{ - Action: service.OauthActionTypeLogin, - Op: f.Op, - Id: f.Id, + Action: service.OauthActionTypeLogin, + Op: f.Op, + Id: f.Id, DeviceType: "webadmin", // DeviceOs: ct.Platform(c), - DeviceOs: f.DeviceInfo.Os, - Uuid: f.Uuid, + DeviceOs: f.DeviceInfo.Os, + Uuid: f.Uuid, }, 5*60) response.Success(c, gin.H{ @@ -141,8 +145,6 @@ func (ct *Login) OidcAuth(c *gin.Context) { }) } - - // OidcAuthQuery // @Tags Oauth // @Summary OidcAuthQuery @@ -158,12 +160,12 @@ func (ct *Login) OidcAuthQuery(c *gin.Context) { if ut == nil { return } - fmt.Println("u:", u) - fmt.Println("ut:", ut) + //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 4ad15db..96f7a80 100644 --- a/http/controller/api/ouath.go +++ b/http/controller/api/ouath.go @@ -32,6 +32,7 @@ func (o *Oauth) OidcAuth(c *gin.Context) { response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error()) return } + //fmt.Println(f) if f.Op != model.OauthTypeWebauth && f.Op != model.OauthTypeGoogle && f.Op != model.OauthTypeGithub && f.Op != model.OauthTypeOidc { response.Error(c, response.TranslateMsg(c, "ParamsError")) return @@ -79,7 +80,7 @@ func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken) // 如果 UserId 为 0,说明还在授权中 if v.UserId == 0 { - c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress"}) + c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress, please login and bind"}) return nil, nil } @@ -123,6 +124,9 @@ func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken) // @Router /oidc/auth-query [get] func (o *Oauth) OidcAuthQuery(c *gin.Context) { u, ut := o.OidcAuthQueryPre(c) + if u == nil || ut == nil { + return + } c.JSON(http.StatusOK, apiResp.LoginRes{ AccessToken: ut.Token, Type: "access_token", @@ -157,7 +161,10 @@ func (o *Oauth) OauthCallback(c *gin.Context) { ty := v.Op ac := v.Action var u *model.User + openid := "" + thirdName := "" //fmt.Println("ty ac ", ty, ac) + if ty == model.OauthTypeGithub { code := c.Query("code") err, userData := service.AllService.OauthService.GithubCallback(code) @@ -165,59 +172,8 @@ func (o *Oauth) OauthCallback(c *gin.Context) { c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error())) return } - if ac == service.OauthActionTypeBind { - //fmt.Println("bind", ty, userData) - utr := service.AllService.OauthService.UserThirdInfo(ty, strconv.Itoa(userData.Id)) - if utr.UserId > 0 { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser")) - return - } - //绑定 - u = service.AllService.UserService.InfoById(v.UserId) - if u == nil { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound")) - return - } - //绑定github - err = service.AllService.OauthService.BindGithubUser(strconv.Itoa(userData.Id), userData.Login, v.UserId) - if err != nil { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail")) - return - } - c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess")) - return - } else if ac == service.OauthActionTypeLogin { - //登录 - if v.UserId != 0 { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess")) - return - } - u = service.AllService.UserService.InfoByGithubId(strconv.Itoa(userData.Id)) - if u == nil { - oa := service.AllService.OauthService.InfoByOp(ty) - if !*oa.AutoRegister { - //c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定") - v.ThirdName = userData.Login - v.ThirdOpenId = strconv.Itoa(userData.Id) - url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey - c.Redirect(http.StatusFound, url) - return - } - - //自动注册 - u = service.AllService.UserService.RegisterByGithub(userData.Login, strconv.Itoa(userData.Id)) - if u.Id == 0 { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed")) - return - } - } - - // v.UserId = u.Id - // service.AllService.OauthService.SetOauthCache(cacheKey, v, 0) - // c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess")) - // return - } - + openid = strconv.Itoa(userData.Id) + thirdName = userData.Login } else if ty == model.OauthTypeGoogle { code := c.Query("code") err, userData := service.AllService.OauthService.GoogleCallback(code) @@ -225,60 +181,9 @@ func (o *Oauth) OauthCallback(c *gin.Context) { c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error())) return } + openid = userData.Email //将空格替换成_ - googleName := strings.Replace(userData.Name, " ", "_", -1) - if ac == service.OauthActionTypeBind { - //fmt.Println("bind", ty, userData) - utr := service.AllService.OauthService.UserThirdInfo(ty, userData.Email) - if utr.UserId > 0 { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser")) - return - } - //绑定 - u = service.AllService.UserService.InfoById(v.UserId) - if u == nil { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound")) - return - } - //绑定 - err = service.AllService.OauthService.BindGoogleUser(userData.Email, googleName, v.UserId) - if err != nil { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail")) - return - } - c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess")) - return - } else if ac == service.OauthActionTypeLogin { - if v.UserId != 0 { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess")) - return - } - u = service.AllService.UserService.InfoByGoogleEmail(userData.Email) - if u == nil { - oa := service.AllService.OauthService.InfoByOp(ty) - if !*oa.AutoRegister { - //c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定") - - v.ThirdName = googleName - v.ThirdOpenId = userData.Email - url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey - c.Redirect(http.StatusFound, url) - return - } - - //自动注册 - u = service.AllService.UserService.RegisterByGoogle(googleName, userData.Email) - if u.Id == 0 { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed")) - return - } - } - - // v.UserId = u.Id - // service.AllService.OauthService.SetOauthCache(cacheKey, v, 0) - // c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess")) - // return - } + thirdName = strings.Replace(userData.Name, " ", "_", -1) } else if ty == model.OauthTypeOidc { code := c.Query("code") err, userData := service.AllService.OauthService.OidcCallback(code) @@ -286,85 +191,81 @@ func (o *Oauth) OauthCallback(c *gin.Context) { c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error())) return } - //将空格替换成_ - // OidcName := strings.Replace(userData.Name, " ", "_", -1) - if ac == service.OauthActionTypeBind { - //fmt.Println("bind", ty, userData) - utr := service.AllService.OauthService.UserThirdInfo(ty, userData.Sub) - if utr.UserId > 0 { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser")) - return - } - //绑定 - u = service.AllService.UserService.InfoById(v.UserId) - if u == nil { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound")) - return - } - //绑定, user preffered_username as username - err = service.AllService.OauthService.BindOidcUser(userData.Sub, userData.PreferredUsername, v.UserId) - if err != nil { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail")) - return - } - c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess")) + openid = userData.Sub + thirdName = userData.PreferredUsername + } else { + c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ParamsError")) + return + } + if ac == service.OauthActionTypeBind { + + //fmt.Println("bind", ty, userData) + utr := service.AllService.OauthService.UserThirdInfo(ty, openid) + if utr.UserId > 0 { + c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser")) return - } else if ac == service.OauthActionTypeLogin { - if v.UserId != 0 { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess")) + } + //绑定 + u = service.AllService.UserService.InfoById(v.UserId) + if u == nil { + c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound")) + return + } + //绑定 + err := service.AllService.OauthService.BindOauthUser(ty, openid, thirdName, v.UserId) + if err != nil { + c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail")) + return + } + c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess")) + return + + } else if ac == service.OauthActionTypeLogin { + //登录 + if v.UserId != 0 { + c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess")) + return + } + u = service.AllService.UserService.InfoByGithubId(openid) + if u == nil { + oa := service.AllService.OauthService.InfoByOp(ty) + if !*oa.AutoRegister { + //c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定") + v.ThirdName = thirdName + v.ThirdOpenId = openid + url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey + c.Redirect(http.StatusFound, url) return } - u = service.AllService.UserService.InfoByOidcSub(userData.Sub) - if u == nil { - oa := service.AllService.OauthService.InfoByOp(ty) - if !*oa.AutoRegister { - //c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定") - v.ThirdName = userData.PreferredUsername - v.ThirdOpenId = userData.Sub - v.ThirdEmail = userData.Email - url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey - c.Redirect(http.StatusFound, url) - return - } - - //自动注册 - u = service.AllService.UserService.RegisterByOidc(userData.PreferredUsername, userData.Sub) - if u.Id == 0 { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed")) - return - } + //自动注册 + u = service.AllService.UserService.RegisterByOauth(ty, thirdName, openid) + if u.Id == 0 { + c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed")) + return } - - // v.UserId = u.Id - // service.AllService.OauthService.SetOauthCache(cacheKey, v, 0) - // c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess")) - // return } - } - // 如果u为空,说明没有绑定用户 - if u == nil { - c.String(http.StatusInternalServerError, response.TranslateMsg(c, "SystemError")) + 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: model.LoginLogTypeOauth, + Platform: v.DeviceOs, + })*/ + url := global.Config.Rustdesk.ApiServer + "/_admin/#/" + c.Redirect(http.StatusFound, url) + return + } + c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess")) + return + } else { + c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ParamsError")) 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/service/oauth.go b/service/oauth.go index e9f4fe7..2880fef 100644 --- a/service/oauth.go +++ b/service/oauth.go @@ -253,6 +253,7 @@ func (os *OauthService) getOidcConfig() (error, *oauth2.Config) { } func getHTTPClientWithProxy() *http.Client { + //todo add timeout if global.Config.Proxy.Enable { if global.Config.Proxy.Host == "" { global.Logger.Warn("Proxy is enabled but proxy host is empty.") @@ -446,7 +447,6 @@ func (os *OauthService) DeleteUserByUserId(userid uint) error { return global.DB.Where("user_id = ?", userid).Delete(&model.UserThird{}).Error } - // InfoById 根据id取用户信息 func (os *OauthService) InfoById(id uint) *model.Oauth { u := &model.Oauth{}