This commit is contained in:
ljw
2024-10-31 14:03:48 +08:00
parent f57816b1b0
commit 855beb7fa9
6 changed files with 355 additions and 197 deletions
+97
View File
@@ -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": { "/admin/loginLog/delete": {
"post": { "post": {
"security": [ "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": { "/admin/peer/create": {
"post": { "post": {
"security": [ "security": [
@@ -3979,6 +4068,14 @@ const docTemplateadmin = `{
} }
} }
}, },
"response.ErrorResponse": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
}
},
"response.Response": { "response.Response": {
"type": "object", "type": "object",
"properties": { "properties": {
+97
View File
@@ -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": { "/admin/loginLog/delete": {
"post": { "post": {
"security": [ "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": { "/admin/peer/create": {
"post": { "post": {
"security": [ "security": [
@@ -3972,6 +4061,14 @@
} }
} }
}, },
"response.ErrorResponse": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
}
},
"response.Response": { "response.Response": {
"type": "object", "type": "object",
"properties": { "properties": {
+61
View File
@@ -653,6 +653,11 @@ definitions:
total: total:
type: integer type: integer
type: object type: object
response.ErrorResponse:
properties:
error:
type: string
type: object
response.Response: response.Response:
properties: properties:
code: code:
@@ -1520,6 +1525,27 @@ paths:
summary: 登录 summary: 登录
tags: 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: /admin/loginLog/delete:
post: post:
consumes: consumes:
@@ -1799,6 +1825,41 @@ paths:
summary: Oauth编辑 summary: Oauth编辑
tags: tags:
- Oauth - 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: /admin/peer/create:
post: post:
consumes: consumes:
+13 -11
View File
@@ -2,15 +2,16 @@ package admin
import ( import (
"Gwen/global" "Gwen/global"
"Gwen/http/controller/api"
"Gwen/http/request/admin" "Gwen/http/request/admin"
apiReq "Gwen/http/request/api"
"Gwen/http/response" "Gwen/http/response"
adResp "Gwen/http/response/admin" adResp "Gwen/http/response/admin"
apiReq "Gwen/http/request/api"
"Gwen/http/controller/api"
"Gwen/model" "Gwen/model"
"Gwen/service" "Gwen/service"
"fmt" "fmt"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm"
) )
type Login struct { type Login struct {
@@ -85,7 +86,6 @@ func (ct *Login) Logout(c *gin.Context) {
response.Success(c, nil) response.Success(c, nil)
} }
// LoginOptions // LoginOptions
// @Tags 登录 // @Tags 登录
// @Summary 登录选项 // @Summary 登录选项
@@ -95,13 +95,17 @@ func (ct *Login) Logout(c *gin.Context) {
// @Success 200 {object} []string // @Success 200 {object} []string
// @Failure 500 {object} response.ErrorResponse // @Failure 500 {object} response.ErrorResponse
// @Router /admin/login-options [post] // @Router /admin/login-options [post]
// 直接调用/api/login的LoginOptions方法
func (ct *Login) LoginOptions(c *gin.Context) { func (ct *Login) LoginOptions(c *gin.Context) {
l := &api.Login{} res := service.AllService.OauthService.List(1, 100, func(tx *gorm.DB) {
l.LoginOptions(c) tx.Select("op").Order("id")
})
var ops []string
for _, v := range res.Oauths {
ops = append(ops, v.Op)
}
response.Success(c, ops)
} }
// OidcAuth // OidcAuth
// @Tags Oauth // @Tags Oauth
// @Summary OidcAuth // @Summary OidcAuth
@@ -141,8 +145,6 @@ func (ct *Login) OidcAuth(c *gin.Context) {
}) })
} }
// OidcAuthQuery // OidcAuthQuery
// @Tags Oauth // @Tags Oauth
// @Summary OidcAuthQuery // @Summary OidcAuthQuery
@@ -158,8 +160,8 @@ func (ct *Login) OidcAuthQuery(c *gin.Context) {
if ut == nil { if ut == nil {
return return
} }
fmt.Println("u:", u) //fmt.Println("u:", u)
fmt.Println("ut:", ut) //fmt.Println("ut:", ut)
response.Success(c, &adResp.LoginPayload{ response.Success(c, &adResp.LoginPayload{
Token: ut.Token, Token: ut.Token,
Username: u.Username, Username: u.Username,
+36 -135
View File
@@ -32,6 +32,7 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error()) response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
return return
} }
//fmt.Println(f)
if f.Op != model.OauthTypeWebauth && f.Op != model.OauthTypeGoogle && f.Op != model.OauthTypeGithub && f.Op != model.OauthTypeOidc { if f.Op != model.OauthTypeWebauth && f.Op != model.OauthTypeGoogle && f.Op != model.OauthTypeGithub && f.Op != model.OauthTypeOidc {
response.Error(c, response.TranslateMsg(c, "ParamsError")) response.Error(c, response.TranslateMsg(c, "ParamsError"))
return return
@@ -79,7 +80,7 @@ func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken)
// 如果 UserId 为 0,说明还在授权中 // 如果 UserId 为 0,说明还在授权中
if v.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 return nil, nil
} }
@@ -123,6 +124,9 @@ func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken)
// @Router /oidc/auth-query [get] // @Router /oidc/auth-query [get]
func (o *Oauth) OidcAuthQuery(c *gin.Context) { func (o *Oauth) OidcAuthQuery(c *gin.Context) {
u, ut := o.OidcAuthQueryPre(c) u, ut := o.OidcAuthQueryPre(c)
if u == nil || ut == nil {
return
}
c.JSON(http.StatusOK, apiResp.LoginRes{ c.JSON(http.StatusOK, apiResp.LoginRes{
AccessToken: ut.Token, AccessToken: ut.Token,
Type: "access_token", Type: "access_token",
@@ -157,7 +161,10 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
ty := v.Op ty := v.Op
ac := v.Action ac := v.Action
var u *model.User var u *model.User
openid := ""
thirdName := ""
//fmt.Println("ty ac ", ty, ac) //fmt.Println("ty ac ", ty, ac)
if ty == model.OauthTypeGithub { if ty == model.OauthTypeGithub {
code := c.Query("code") code := c.Query("code")
err, userData := service.AllService.OauthService.GithubCallback(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())) c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
return return
} }
if ac == service.OauthActionTypeBind { openid = strconv.Itoa(userData.Id)
//fmt.Println("bind", ty, userData) thirdName = userData.Login
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
}
} else if ty == model.OauthTypeGoogle { } else if ty == model.OauthTypeGoogle {
code := c.Query("code") code := c.Query("code")
err, userData := service.AllService.OauthService.GoogleCallback(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())) c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
return return
} }
openid = userData.Email
//将空格替换成_ //将空格替换成_
googleName := strings.Replace(userData.Name, " ", "_", -1) thirdName = 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
}
} else if ty == model.OauthTypeOidc { } else if ty == model.OauthTypeOidc {
code := c.Query("code") code := c.Query("code")
err, userData := service.AllService.OauthService.OidcCallback(code) err, userData := service.AllService.OauthService.OidcCallback(code)
@@ -286,11 +191,16 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error())) c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
return return
} }
//将空格替换成_ openid = userData.Sub
// OidcName := strings.Replace(userData.Name, " ", "_", -1) thirdName = userData.PreferredUsername
} else {
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ParamsError"))
return
}
if ac == service.OauthActionTypeBind { if ac == service.OauthActionTypeBind {
//fmt.Println("bind", ty, userData) //fmt.Println("bind", ty, userData)
utr := service.AllService.OauthService.UserThirdInfo(ty, userData.Sub) utr := service.AllService.OauthService.UserThirdInfo(ty, openid)
if utr.UserId > 0 { if utr.UserId > 0 {
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser")) c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser"))
return return
@@ -301,70 +211,61 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound")) c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
return return
} }
//绑定, user preffered_username as username //绑定
err = service.AllService.OauthService.BindOidcUser(userData.Sub, userData.PreferredUsername, v.UserId) err := service.AllService.OauthService.BindOauthUser(ty, openid, thirdName, v.UserId)
if err != nil { if err != nil {
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail")) c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail"))
return return
} }
c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess")) c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess"))
return return
} else if ac == service.OauthActionTypeLogin { } else if ac == service.OauthActionTypeLogin {
//登录
if v.UserId != 0 { if v.UserId != 0 {
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess")) c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
return return
} }
u = service.AllService.UserService.InfoByOidcSub(userData.Sub) u = service.AllService.UserService.InfoByGithubId(openid)
if u == nil { if u == nil {
oa := service.AllService.OauthService.InfoByOp(ty) oa := service.AllService.OauthService.InfoByOp(ty)
if !*oa.AutoRegister { if !*oa.AutoRegister {
//c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定") //c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定")
v.ThirdName = thirdName
v.ThirdName = userData.PreferredUsername v.ThirdOpenId = openid
v.ThirdOpenId = userData.Sub
v.ThirdEmail = userData.Email
url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey
c.Redirect(http.StatusFound, url) c.Redirect(http.StatusFound, url)
return return
} }
//自动注册 //自动注册
u = service.AllService.UserService.RegisterByOidc(userData.PreferredUsername, userData.Sub) u = service.AllService.UserService.RegisterByOauth(ty, thirdName, openid)
if u.Id == 0 { if u.Id == 0 {
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed")) c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed"))
return 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"))
return
}
// 认证成功,设置缓存
v.UserId = u.Id v.UserId = u.Id
service.AllService.OauthService.SetOauthCache(cacheKey, v, 0) service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
// 如果是webadmin,登录成功后跳转到webadmin // 如果是webadmin,登录成功后跳转到webadmin
if v.DeviceType == "webadmin" { if v.DeviceType == "webadmin" {
service.AllService.UserService.Login(u, &model.LoginLog{ /*service.AllService.UserService.Login(u, &model.LoginLog{
UserId: u.Id, UserId: u.Id,
Client: "webadmin", Client: "webadmin",
Uuid: "",//must be empty Uuid: "", //must be empty
Ip: c.ClientIP(), Ip: c.ClientIP(),
Type: "account", Type: model.LoginLogTypeOauth,
Platform: v.DeviceOs, Platform: v.DeviceOs,
}) })*/
url := global.Config.Rustdesk.ApiServer + "/_admin/#/" url := global.Config.Rustdesk.ApiServer + "/_admin/#/"
c.Redirect(http.StatusFound, url) c.Redirect(http.StatusFound, url)
return return
} }
c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess")) c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
return return
} else {
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ParamsError"))
return
}
} }
+1 -1
View File
@@ -253,6 +253,7 @@ func (os *OauthService) getOidcConfig() (error, *oauth2.Config) {
} }
func getHTTPClientWithProxy() *http.Client { func getHTTPClientWithProxy() *http.Client {
//todo add timeout
if global.Config.Proxy.Enable { if global.Config.Proxy.Enable {
if global.Config.Proxy.Host == "" { if global.Config.Proxy.Host == "" {
global.Logger.Warn("Proxy is enabled but proxy host is empty.") 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 return global.DB.Where("user_id = ?", userid).Delete(&model.UserThird{}).Error
} }
// InfoById 根据id取用户信息 // InfoById 根据id取用户信息
func (os *OauthService) InfoById(id uint) *model.Oauth { func (os *OauthService) InfoById(id uint) *model.Oauth {
u := &model.Oauth{} u := &model.Oauth{}