Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
855beb7fa9 | ||
|
|
f57816b1b0 | ||
|
|
ff08fefc30 | ||
|
|
f792ab9055 | ||
|
|
63af103a4e | ||
|
|
0a36d44cec | ||
|
|
a1f4e1de84 | ||
|
|
05b20d47db | ||
|
|
6b746f13d1 | ||
|
|
e838d5bcd2 | ||
|
|
0dcc21260e |
@@ -4,7 +4,7 @@ ARG BUILDARCH=amd64
|
||||
|
||||
# Stage 1: Builder Stage
|
||||
# FROM golang:${GO_VERSION}-alpine AS builder
|
||||
FROM crazymax/xgo:${GO_VERSION} AS builder
|
||||
FROM crazymax/xgo:${GO_VERSION} AS builder-backend
|
||||
|
||||
# Set up working directory
|
||||
WORKDIR /app
|
||||
@@ -27,7 +27,7 @@ RUN CGO_ENABLED=1 GOOS=linux go build -a \
|
||||
-installsuffix cgo -o release/apimain cmd/apimain.go
|
||||
|
||||
# Stage 2: Frontend Build Stage (builder2)
|
||||
FROM node:18-alpine AS builder2
|
||||
FROM node:18-alpine AS builder-admin-frontend
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /frontend
|
||||
@@ -50,12 +50,12 @@ WORKDIR /app
|
||||
RUN apk add --no-cache tzdata file
|
||||
|
||||
# Copy the built application and resources from the builder stage
|
||||
COPY --from=builder /app/release /app/
|
||||
COPY --from=builder /app/conf /app/conf/
|
||||
COPY --from=builder /app/resources /app/resources/
|
||||
COPY --from=builder /app/docs /app/docs/
|
||||
COPY --from=builder-backend /app/release /app/
|
||||
COPY --from=builder-backend /app/conf /app/conf/
|
||||
COPY --from=builder-backend /app/resources /app/resources/
|
||||
COPY --from=builder-backend /app/docs /app/docs/
|
||||
# Copy frontend build from builder2 stage
|
||||
COPY --from=builder2 /frontend/dist/ /app/resources/admin/
|
||||
COPY --from=builder-admin-frontend /frontend/dist/ /app/resources/admin/
|
||||
|
||||
# Ensure the binary is correctly built and linked
|
||||
RUN file /app/apimain && \
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
- 登录
|
||||
- 地址簿
|
||||
- 群组
|
||||
- 授权登录,支持`github`和`google`登录,支持`web后台`授权登录
|
||||
- 授权登录,支持`github`, `google` 和 `OIDC` 登录,支持`web后台`授权登录
|
||||
- i18n
|
||||
- Web Admin
|
||||
- 用户管理
|
||||
@@ -92,7 +92,7 @@
|
||||
|
||||
#### 登录
|
||||
|
||||
- 添加了`github`和`google`授权登录,需要在后台配置好就可以用了,具体可看后台OAuth配置
|
||||
- 添加了`github`, `google` 以及`OIDC`授权登录,需要在后台配置好就可以用了,具体可看后台OAuth配置
|
||||
- 添加了web后台授权登录,点击后直接登录后台就自动登录客户端了
|
||||
|
||||

|
||||
@@ -124,8 +124,10 @@
|
||||
4. 可以直接打开webclient,方便使用;也可以分享给游客,游客可以直接通过webclient远程到设备
|
||||
|
||||

|
||||
5. Oauth,暂时只支持了`Github`和`Google`, 需要创建一个`OAuth App`,然后配置到后台
|
||||
5. Oauth,支持了`Github`, `Google` 以及 `OIDC`, 需要创建一个`OAuth App`,然后配置到后台
|
||||

|
||||
- 对于`Google` 和 `Github`, `Issuer` 和 `Scopes`不需要填写.
|
||||
- 对于`OIDC`, `Issuer`是必须的。`Scopes`是可选的,默认为 `openid,profile,email`. 确保可以获取 `sub`,`email` 和`preferred_username`
|
||||
- `github oauth app`在`Settings`->`Developer settings`->`OAuth Apps`->`New OAuth App`
|
||||
中创建,地址 [https://github.com/settings/developers](https://github.com/settings/developers)
|
||||
- `Authorization callback URL`填写`http://<your server[:port]>/api/oauth/callback`
|
||||
|
||||
@@ -18,7 +18,7 @@ desktop software that provides self-hosted solutions.
|
||||
- Login
|
||||
- Address Book
|
||||
- Groups
|
||||
- Authorized login, supports `GitHub` and `Google` login, supports `web admin` authorized login
|
||||
- Authorized login, supports `GitHub`, `Google` and `OIDC` login, supports `web admin` authorized login
|
||||
- i18n
|
||||
- Web Admin
|
||||
- User Management
|
||||
@@ -93,7 +93,7 @@ Basic implementation of the PC client's primary interfaces.Supports the Personal
|
||||
|
||||
#### Login
|
||||
|
||||
- Added `GitHub` and `Google` login, which can be used after configuration in the admin panel. See the OAuth
|
||||
- Added `GitHub`, `Google` and `OIDC` login, which can be used after configuration in the admin panel. See the OAuth
|
||||
configuration section for details.
|
||||
- Added authorization login for the web admin panel.
|
||||
|
||||
@@ -128,9 +128,11 @@ installation are `admin` `admin`, please change the password immediately.
|
||||
4. You can directly launch the client or open the web client for convenience; you can also share it with guests, who can remotely access the device via the web client.
|
||||
|
||||

|
||||
5. OAuth support: Currently, `GitHub` and `Google` is supported. You need to create an `OAuth App` and configure it in
|
||||
5. OAuth support: Currently, `GitHub`, `Google` and `OIDC` are supported. You need to create an `OAuth App` and configure it in
|
||||
the admin panel.
|
||||

|
||||
- For `Google` and `Github`, you don't need to fill the `Issuer` and `Scpoes`
|
||||
- For `OIDC`, you must set the `Issuer`. And `Scopes` is optional which default is `openid,email,profile`, please make sure this `Oauth App` can access `sub`, `email` and `preferred_username`
|
||||
- Create a `GitHub OAuth App`
|
||||
at `Settings` -> `Developer settings` -> `OAuth Apps` -> `New OAuth App` [here](https://github.com/settings/developers).
|
||||
- Set the `Authorization callback URL` to `http://<your server[:port]>/api/oauth/callback`,
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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:
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 21 KiB |
@@ -2,13 +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"
|
||||
"Gwen/model"
|
||||
"Gwen/service"
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type Login struct {
|
||||
@@ -51,7 +54,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 +85,87 @@ 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]
|
||||
func (ct *Login) LoginOptions(c *gin.Context) {
|
||||
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
|
||||
// @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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ func (o *Oauth) BindConfirm(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.CurUser(c)
|
||||
err = service.AllService.OauthService.BindGithubUser(v.ThirdOpenId, v.ThirdOpenId, u.Id)
|
||||
err = service.AllService.OauthService.BindOauthUser(v.Op, v.ThirdOpenId, v.ThirdName, u.Id)
|
||||
if err != nil {
|
||||
response.Fail(c, 101, response.TranslateMsg(c, "BindFail"))
|
||||
return
|
||||
|
||||
@@ -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
|
||||
@@ -59,6 +60,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, please login and bind"})
|
||||
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 +123,10 @@ 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())
|
||||
u, ut := o.OidcAuthQueryPre(c)
|
||||
if u == nil || ut == nil {
|
||||
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,
|
||||
})
|
||||
c.JSON(http.StatusOK, apiResp.LoginRes{
|
||||
AccessToken: ut.Token,
|
||||
Type: "access_token",
|
||||
@@ -129,7 +160,11 @@ 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)
|
||||
@@ -137,187 +172,100 @@ 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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ty == model.OauthTypeGoogle {
|
||||
openid = strconv.Itoa(userData.Id)
|
||||
thirdName = userData.Login
|
||||
} else if ty == model.OauthTypeGoogle {
|
||||
code := c.Query("code")
|
||||
err, userData := service.AllService.OauthService.GoogleCallback(code)
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
}
|
||||
if ty == model.OauthTypeOidc {
|
||||
thirdName = strings.Replace(userData.Name, " ", "_", -1)
|
||||
} else if ty == model.OauthTypeOidc {
|
||||
code := c.Query("code")
|
||||
err, userData := service.AllService.OauthService.OidcCallback(code)
|
||||
if err != nil {
|
||||
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"))
|
||||
return
|
||||
} else if ac == service.OauthActionTypeLogin {
|
||||
if v.UserId != 0 {
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
|
||||
return
|
||||
}
|
||||
u := service.AllService.UserService.InfoByOidcSub(userData.Sub)
|
||||
if u == nil {
|
||||
oa := service.AllService.OauthService.InfoByOp(ty)
|
||||
if !*oa.AutoRegister {
|
||||
//c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定")
|
||||
openid = userData.Sub
|
||||
thirdName = userData.PreferredUsername
|
||||
} else {
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ParamsError"))
|
||||
return
|
||||
}
|
||||
if ac == service.OauthActionTypeBind {
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
v.UserId = u.Id
|
||||
service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
|
||||
c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
|
||||
//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
|
||||
}
|
||||
//绑定
|
||||
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.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)
|
||||
// 如果是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
|
||||
}
|
||||
|
||||
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "SystemError"))
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.")
|
||||
@@ -441,6 +442,11 @@ func (os *OauthService) UnBindThird(thirdType string, userid uint) error {
|
||||
return global.DB.Where("user_id = ? and third_type = ?", userid, thirdType).Delete(&model.UserThird{}).Error
|
||||
}
|
||||
|
||||
// DeleteUserByUserId: When user is deleted, delete all third party bindings
|
||||
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{}
|
||||
|
||||
@@ -148,8 +148,37 @@ func (us *UserService) Create(u *model.User) error {
|
||||
func (us *UserService) Logout(u *model.User, token string) error {
|
||||
return global.DB.Where("user_id = ? and token = ?", u.Id, token).Delete(&model.UserToken{}).Error
|
||||
}
|
||||
|
||||
// Delete 删除用户和oauth信息
|
||||
func (us *UserService) Delete(u *model.User) error {
|
||||
return global.DB.Delete(u).Error
|
||||
tx := global.DB.Begin()
|
||||
// 删除用户
|
||||
if err := tx.Delete(u).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
// 删除关联的 OAuth 信息
|
||||
if err := tx.Where("user_id = ?", u.Id).Delete(&model.UserThird{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
// 删除关联的ab
|
||||
if err := tx.Where("user_id = ?", u.Id).Delete(&model.AddressBook{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
// 删除关联的abc
|
||||
if err := tx.Where("user_id = ?", u.Id).Delete(&model.AddressBookCollection{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
// 删除关联的abcr
|
||||
if err := tx.Where("user_id = ?", u.Id).Delete(&model.AddressBookCollectionRule{}).Error; err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
tx.Commit()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update 更新
|
||||
@@ -252,14 +281,14 @@ func (us *UserService) RegisterByOauth(thirdType, thirdName, uid string) *model.
|
||||
Username: username,
|
||||
GroupId: 1,
|
||||
}
|
||||
global.DB.Create(u)
|
||||
tx.Create(u)
|
||||
if u.Id == 0 {
|
||||
tx.Rollback()
|
||||
return u
|
||||
}
|
||||
|
||||
ut.UserId = u.Id
|
||||
global.DB.Create(ut)
|
||||
tx.Create(ut)
|
||||
|
||||
tx.Commit()
|
||||
return u
|
||||
|
||||
Reference in New Issue
Block a user