Compare commits

...

27 Commits

Author SHA1 Message Date
ljw
7ad7a0ff41 fix #45 2024-11-02 18:49:16 +08:00
ljw
737fe749de load key from file 2024-11-01 14:56:11 +08:00
b9c6f17e3f Merge pull request #42 from IamTaoChen/docker
Docker Optimize
2024-11-01 13:10:59 +08:00
Tao Chen
af6a340003 add more 2024-11-01 01:33:08 +08:00
Tao Chen
8ba3bee944 optimize scripts 2024-11-01 01:33:05 +08:00
Tao Chen
153c3566b6 optimize build speed, like cache and mirror 2024-11-01 01:32:45 +08:00
Tao Chen
97a4753f4f add ARG CONTRY=CN to improve the alpinelinux install speed 2024-11-01 00:29:33 +08:00
Tao Chen
74c3899b55 add bash to run dev-docker 2024-11-01 00:28:43 +08:00
ljw
273ac6d1a8 add remove user token #34 2024-10-31 22:29:12 +08:00
5edbb39a63 Merge pull request #40 from IamTaoChen/resetEmptyPassWD
Reset empty password
2024-10-31 18:46:34 +08:00
Tao Chen
0c974c4113 Merge branch 'master' into resetEmptyPassWD 2024-10-31 16:35:32 +08:00
Tao Chen
46657a525d ommit check old passwd if password is empty 2024-10-31 16:23:06 +08:00
Tao Chen
b36aa6f917 add IsPasswordEmpty... 2024-10-31 16:22:42 +08:00
ljw
cddb0ebef9 up readme #28 2024-10-31 15:48:36 +08:00
ljw
788c4e3531 up readme #28 2024-10-31 15:47:39 +08:00
ljw
47f9ad8274 add register 2024-10-31 15:14:30 +08:00
ljw
855beb7fa9 up oauth 2024-10-31 14:03:48 +08:00
f57816b1b0 Merge pull request #36 from IamTaoChen/oidc-for-web
OIDC for web
2024-10-31 11:10:46 +08:00
Tao Chen
ff08fefc30 rename build stage 2024-10-31 09:21:43 +08:00
Tao Chen
f792ab9055 add some /admin/ to surport web OIDC 2024-10-31 09:21:30 +08:00
ljw
63af103a4e fix buidconfirm 2024-10-30 20:59:51 +08:00
ljw
0a36d44cec up del user 2024-10-30 19:34:56 +08:00
a1f4e1de84 Merge pull request #32 from IamTaoChen/bug/odic-user
delete user from user_thirds and update README
2024-10-30 19:08:50 +08:00
Tao Chen
05b20d47db modify delete user 2024-10-30 16:33:01 +08:00
Tao Chen
6b746f13d1 update README 2024-10-30 16:31:47 +08:00
Tao Chen
e838d5bcd2 update README for OIDC 2024-10-30 16:29:49 +08:00
Tao Chen
0dcc21260e delete user from user_thirds, too 2024-10-30 15:59:33 +08:00
37 changed files with 1665 additions and 385 deletions

View File

@@ -1,8 +1,11 @@
# Ignore Docker Compose configuration files # Ignore Docker Compose configuration files
docker-compose.yaml docker-compose.yaml
docker-compose-dev.yaml
# Ignore development Dockerfile # Ignore development Dockerfile
Dockerfile
Dockerfile.dev Dockerfile.dev
docker-dev.sh
# Ignore the data directory # Ignore the data directory
data/ data/

View File

@@ -4,7 +4,7 @@ ARG BUILDARCH=amd64
# Stage 1: Builder Stage # Stage 1: Builder Stage
# FROM golang:${GO_VERSION}-alpine AS builder # 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 # Set up working directory
WORKDIR /app WORKDIR /app
@@ -12,33 +12,46 @@ WORKDIR /app
# Step 1: Copy the source code # Step 1: Copy the source code
COPY . . COPY . .
# use --mount=type=cache,target=/go/pkg/mod to cache the go mod
# Step 2: Download dependencies # Step 2: Download dependencies
RUN go mod tidy && go mod download RUN --mount=type=cache,target=/go/pkg/mod \
go mod tidy && go mod download && go install github.com/swaggo/swag/cmd/swag@latest
# Step 3: Run swag build script
# Step 3: Install swag and Run the build script RUN --mount=type=cache,target=/go/pkg/mod \
RUN go install github.com/swaggo/swag/cmd/swag@latest && \
swag init -g cmd/apimain.go --output docs/api --instanceName api --exclude http/controller/admin && \ swag init -g cmd/apimain.go --output docs/api --instanceName api --exclude http/controller/admin && \
swag init -g cmd/apimain.go --output docs/admin --instanceName admin --exclude http/controller/api swag init -g cmd/apimain.go --output docs/admin --instanceName admin --exclude http/controller/api
# Build the Go application with CGO enabled and specified ldflags # Step 4: Build the Go application with CGO enabled and specified ldflags
RUN CGO_ENABLED=1 GOOS=linux go build -a \ RUN --mount=type=cache,target=/go/pkg/mod \
CGO_ENABLED=1 GOOS=linux go build -a \
-ldflags "-s -w --extldflags '-static -fpic'" \ -ldflags "-s -w --extldflags '-static -fpic'" \
-installsuffix cgo -o release/apimain cmd/apimain.go -installsuffix cgo -o release/apimain cmd/apimain.go
# Stage 2: Frontend Build Stage (builder2) # Stage 2: Frontend Build Stage (builder2)
FROM node:18-alpine AS builder2 FROM node:18-alpine AS builder-admin-frontend
# Set working directory # Set working directory
WORKDIR /frontend WORKDIR /frontend
RUN apk update && apk add git --no-cache ARG COUNTRY
# Install required tools without caching index to minimize image size
RUN if [ "$COUNTRY" = "CN" ] ; then \
echo "It is in China, updating the repositories"; \
sed -i 's#https\?://dl-cdn.alpinelinux.org/alpine#https://mirrors.tuna.tsinghua.edu.cn/alpine#g' /etc/apk/repositories; \
fi && \
apk update && apk add --no-cache git
# Clone the frontend repository # Clone the frontend repository
RUN git clone https://github.com/lejianwen/rustdesk-api-web . RUN git clone https://github.com/lejianwen/rustdesk-api-web .
# Install npm dependencies and build the frontend # Install required tools without caching index to minimize image size
RUN npm install && npm run build RUN if [ "$COUNTRY" = "CN" ] ; then \
echo "It is in China, updating NPM_CONFIG_REGISTRY"; \
export NPM_CONFIG_REGISTRY="https://mirrors.huaweicloud.com/repository/npm/"; \
fi && \
npm install && npm run build
# Stage 2: Final Image # Stage 2: Final Image
FROM alpine:latest FROM alpine:latest
@@ -47,15 +60,21 @@ FROM alpine:latest
WORKDIR /app WORKDIR /app
# Install necessary runtime dependencies # Install necessary runtime dependencies
RUN apk add --no-cache tzdata file # Install required tools without caching index to minimize image size
ARG COUNTRY
RUN if [ "$COUNTRY" = "CN" ] ; then \
echo "It is in China, updating the repositories"; \
sed -i 's#https\?://dl-cdn.alpinelinux.org/alpine#https://mirrors.tuna.tsinghua.edu.cn/alpine#g' /etc/apk/repositories; \
fi && \
apk update && apk add --no-cache tzdata file
# Copy the built application and resources from the builder stage # Copy the built application and resources from the builder stage
COPY --from=builder /app/release /app/ COPY --from=builder-backend /app/release /app/
COPY --from=builder /app/conf /app/conf/ COPY --from=builder-backend /app/conf /app/conf/
COPY --from=builder /app/resources /app/resources/ COPY --from=builder-backend /app/resources /app/resources/
COPY --from=builder /app/docs /app/docs/ COPY --from=builder-backend /app/docs /app/docs/
# Copy frontend build from builder2 stage # 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 # Ensure the binary is correctly built and linked
RUN file /app/apimain && \ RUN file /app/apimain && \

View File

@@ -19,7 +19,7 @@
- 登录 - 登录
- 地址簿 - 地址簿
- 群组 - 群组
- 授权登录,支持`github``google`登录,支持`web后台`授权登录 - 授权登录,支持`github`, `google``OIDC` 登录,支持`web后台`授权登录
- i18n - i18n
- Web Admin - Web Admin
- 用户管理 - 用户管理
@@ -92,7 +92,7 @@
#### 登录 #### 登录
- 添加了`github``google`授权登录需要在后台配置好就可以用了具体可看后台OAuth配置 - 添加了`github`, `google` 以及`OIDC`授权登录需要在后台配置好就可以用了具体可看后台OAuth配置
- 添加了web后台授权登录,点击后直接登录后台就自动登录客户端了 - 添加了web后台授权登录,点击后直接登录后台就自动登录客户端了
![pc_login](docs/pc_login.png) ![pc_login](docs/pc_login.png)
@@ -124,8 +124,10 @@
4. 可以直接打开webclient方便使用也可以分享给游客游客可以直接通过webclient远程到设备 4. 可以直接打开webclient方便使用也可以分享给游客游客可以直接通过webclient远程到设备
![web_webclient](docs/admin_webclient.png) ![web_webclient](docs/admin_webclient.png)
5. Oauth,暂时只支持了`Github``Google`, 需要创建一个`OAuth App`,然后配置到后台 5. Oauth,支持了`Github`, `Google` 以及 `OIDC`, 需要创建一个`OAuth App`,然后配置到后台
![web_admin_oauth](docs/web_admin_oauth.png) ![web_admin_oauth](docs/web_admin_oauth.png)
- 对于`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` - `github oauth app`在`Settings`->`Developer settings`->`OAuth Apps`->`New OAuth App`
中创建,地址 [https://github.com/settings/developers](https://github.com/settings/developers) 中创建,地址 [https://github.com/settings/developers](https://github.com/settings/developers)
- `Authorization callback URL`填写`http://<your server[:port]>/api/oauth/callback` - `Authorization callback URL`填写`http://<your server[:port]>/api/oauth/callback`
@@ -157,6 +159,7 @@
lang: "en" lang: "en"
app: app:
web-client: 1 # 1:启用 0:禁用 web-client: 1 # 1:启用 0:禁用
register: false #是否开启注册
gin: gin:
api-addr: "0.0.0.0:21114" api-addr: "0.0.0.0:21114"
mode: "release" mode: "release"
@@ -194,6 +197,7 @@ proxy:
| TZ | 时区 | Asia/Shanghai | | TZ | 时区 | Asia/Shanghai |
| RUSTDESK_API_LANG | 语言 | `en`,`zh-CN` | | RUSTDESK_API_LANG | 语言 | `en`,`zh-CN` |
| RUSTDESK_API_APP_WEB_CLIENT | 是否启用web-client; 1:启用,0:不启用; 默认启用 | 1 | | RUSTDESK_API_APP_WEB_CLIENT | 是否启用web-client; 1:启用,0:不启用; 默认启用 | 1 |
| RUSTDESK_API_APP_REGISTER | 是否开启注册; `true`, `false` 默认`false` | `false` |
| -----GIN配置----- | ---------- | ---------- | | -----GIN配置----- | ---------- | ---------- |
| RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表以`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 | | RUSTDESK_API_GIN_TRUST_PROXY | 信任的代理IP列表以`,`分割,默认信任所有 | 192.168.1.2,192.168.1.3 |
| -----------GORM配置---------------- | ------------------------------------ | --------------------------- | | -----------GORM配置---------------- | ------------------------------------ | --------------------------- |

View File

@@ -18,7 +18,7 @@ desktop software that provides self-hosted solutions.
- Login - Login
- Address Book - Address Book
- Groups - 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 - i18n
- Web Admin - Web Admin
- User Management - User Management
@@ -93,7 +93,7 @@ Basic implementation of the PC client's primary interfaces.Supports the Personal
#### Login #### 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. configuration section for details.
- Added authorization login for the web admin panel. - 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. 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.
![web_webclient](docs/en_img/admin_webclient.png) ![web_webclient](docs/en_img/admin_webclient.png)
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. the admin panel.
![web_admin_oauth](docs/en_img/web_admin_oauth.png) ![web_admin_oauth](docs/en_img/web_admin_oauth.png)
- 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` - Create a `GitHub OAuth App`
at `Settings` -> `Developer settings` -> `OAuth Apps` -> `New OAuth App` [here](https://github.com/settings/developers). 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`, - Set the `Authorization callback URL` to `http://<your server[:port]>/api/oauth/callback`,
@@ -163,6 +165,7 @@ installation are `admin` `admin`, please change the password immediately.
lang: "en" lang: "en"
app: app:
web-client: 1 # web client route 1:open 0:close web-client: 1 # web client route 1:open 0:close
register: false #register enable
gin: gin:
api-addr: "0.0.0.0:21114" api-addr: "0.0.0.0:21114"
mode: "release" mode: "release"
@@ -200,6 +203,7 @@ The prefix for variable names is `RUSTDESK_API`. If environment variables exist,
| TZ | timezone | Asia/Shanghai | | TZ | timezone | Asia/Shanghai |
| RUSTDESK_API_LANG | Language | `en`,`zh-CN` | | RUSTDESK_API_LANG | Language | `en`,`zh-CN` |
| RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, deault 1 | 1 | | RUSTDESK_API_APP_WEB_CLIENT | web client on/off; 1: on, 0 off, deault 1 | 1 |
| RUSTDESK_API_APP_REGISTER | register enable; `true`, `false`; default:`false` | `false` |
| ----- GIN Configuration ----- | --------------------------------------- | ----------------------------- | | ----- GIN Configuration ----- | --------------------------------------- | ----------------------------- |
| RUSTDESK_API_GIN_TRUST_PROXY | Trusted proxy IPs, separated by commas. | 192.168.1.2,192.168.1.3 | | RUSTDESK_API_GIN_TRUST_PROXY | Trusted proxy IPs, separated by commas. | 192.168.1.2,192.168.1.3 |
| ----- GORM Configuration ----- | --------------------------------------- | ----------------------------- | | ----- GORM Configuration ----- | --------------------------------------- | ----------------------------- |

View File

@@ -101,7 +101,7 @@ func main() {
} }
func DatabaseAutoUpdate() { func DatabaseAutoUpdate() {
version := 243 version := 244
db := global.DB db := global.DB

View File

@@ -1,6 +1,7 @@
lang: "zh-CN" lang: "zh-CN"
app: app:
web-client: 1 # 1:启用 0:禁用 web-client: 1 # 1:启用 0:禁用
register: false #是否开启注册
gin: gin:
api-addr: "0.0.0.0:21114" api-addr: "0.0.0.0:21114"
mode: "release" #release,debug,test mode: "release" #release,debug,test
@@ -19,7 +20,8 @@ rustdesk:
id-server: "192.168.1.66:21116" id-server: "192.168.1.66:21116"
relay-server: "192.168.1.66:21117" relay-server: "192.168.1.66:21117"
api-server: "http://127.0.0.1:21114" api-server: "http://127.0.0.1:21114"
key: "123456789" key: ""
key-file: "./conf/data/id_ed25519.pub"
personal: 1 personal: 1
logger: logger:
path: "./runtime/log.txt" path: "./runtime/log.txt"

View File

@@ -15,7 +15,8 @@ const (
) )
type App struct { type App struct {
WebClient int `mapstructure:"web-client"` WebClient int `mapstructure:"web-client"`
Register bool `mapstructure:"register"`
} }
type Config struct { type Config struct {
@@ -62,6 +63,7 @@ func Init(rowVal interface{}) *viper.Viper {
if err := v.Unmarshal(rowVal); err != nil { if err := v.Unmarshal(rowVal); err != nil {
fmt.Println(err) fmt.Println(err)
} }
LoadKeyFile(&rowVal.(*Config).Rustdesk)
return v return v
} }

View File

@@ -1,9 +1,30 @@
package config package config
import (
"os"
)
type Rustdesk struct { type Rustdesk struct {
IdServer string `mapstructure:"id-server"` IdServer string `mapstructure:"id-server"`
RelayServer string `mapstructure:"relay-server"` RelayServer string `mapstructure:"relay-server"`
ApiServer string `mapstructure:"api-server"` ApiServer string `mapstructure:"api-server"`
Key string `mapstructure:"key"` Key string `mapstructure:"key"`
KeyFile string `mapstructure:"key-file"`
Personal int `mapstructure:"personal"` Personal int `mapstructure:"personal"`
} }
func LoadKeyFile(rustdesk *Rustdesk) {
// Load key file
if rustdesk.Key != "" {
return
}
if rustdesk.KeyFile != "" {
// Load key from file
b, err := os.ReadFile(rustdesk.KeyFile)
if err != nil {
return
}
rustdesk.Key = string(b)
return
}
}

View File

@@ -3,6 +3,8 @@ services:
build: build:
context: . context: .
dockerfile: Dockerfile.dev dockerfile: Dockerfile.dev
args:
COUNTRY: CN
# image: lejianwen/rustdesk-api # image: lejianwen/rustdesk-api
container_name: rustdesk-api container_name: rustdesk-api
environment: environment:

35
docker-dev.sh Executable file
View File

@@ -0,0 +1,35 @@
#!/bin/bash
set -e
# Define Docker Compose file and cache option
COMPOSE_FILE_NAME="docker-compose-dev.yaml"
CACHE=""
# Uncomment the next line to enable no-cache option
# CACHE="--no-cache"
# Define the base Docker Compose command
DCS="docker compose -f ${COMPOSE_FILE_NAME}"
# Function to build and start services
build_and_run() {
echo "Building services..."
if ! $DCS build ${CACHE}; then
echo "Error: Failed to build services"
exit 1
fi
echo "Starting services..."
if ! $DCS up -d; then
echo "Error: Failed to start services"
exit 1
fi
echo "Services started successfully"
echo "If you want to stop the services, run"
echo "docker compose -f ${COMPOSE_FILE_NAME} down"
echo "If you want to see the logs, run"
echo "docker compose -f ${COMPOSE_FILE_NAME} logs -f"
}
# Execute build and start function
build_and_run

View File

@@ -353,17 +353,20 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "创建地址簿集合", "description": "创建地址簿名称",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "创建地址簿集合", "tags": [
"地址簿名称"
],
"summary": "创建地址簿名称",
"parameters": [ "parameters": [
{ {
"description": "地址簿集合信息", "description": "地址簿名称信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
@@ -407,17 +410,20 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "地址簿集合删除", "description": "地址簿名称删除",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合删除", "tags": [
"地址簿名称"
],
"summary": "地址簿名称删除",
"parameters": [ "parameters": [
{ {
"description": "地址簿集合信息", "description": "地址簿名称信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
@@ -449,14 +455,17 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "地址簿集合详情", "description": "地址簿名称详情",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合详情", "tags": [
"地址簿名称"
],
"summary": "地址簿名称详情",
"parameters": [ "parameters": [
{ {
"type": "integer", "type": "integer",
@@ -501,14 +510,17 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "地址簿集合列表", "description": "地址簿名称列表",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合列表", "tags": [
"地址簿名称"
],
"summary": "地址簿名称列表",
"parameters": [ "parameters": [
{ {
"type": "integer", "type": "integer",
@@ -570,17 +582,20 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "地址簿集合编辑", "description": "地址簿名称编辑",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合编辑", "tags": [
"地址簿名称"
],
"summary": "地址簿名称编辑",
"parameters": [ "parameters": [
{ {
"description": "地址簿集合信息", "description": "地址簿名称信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
@@ -624,17 +639,20 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "创建地址簿集合规则", "description": "创建地址簿规则",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "创建地址簿集合规则", "tags": [
"地址簿规则"
],
"summary": "创建地址簿规则",
"parameters": [ "parameters": [
{ {
"description": "地址簿集合规则信息", "description": "地址簿规则信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
@@ -678,17 +696,20 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "地址簿集合规则删除", "description": "地址簿规则删除",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合规则删除", "tags": [
"地址簿规则"
],
"summary": "地址簿规则删除",
"parameters": [ "parameters": [
{ {
"description": "地址簿集合规则信息", "description": "地址簿规则信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
@@ -720,14 +741,17 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "地址簿集合规则详情", "description": "地址簿规则详情",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合规则详情", "tags": [
"地址簿规则"
],
"summary": "地址簿规则详情",
"parameters": [ "parameters": [
{ {
"type": "integer", "type": "integer",
@@ -772,14 +796,17 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "地址簿集合规则列表", "description": "地址簿规则列表",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合规则列表", "tags": [
"地址簿规则"
],
"summary": "地址簿规则列表",
"parameters": [ "parameters": [
{ {
"type": "integer", "type": "integer",
@@ -847,17 +874,20 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "地址簿集合规则编辑", "description": "地址簿规则编辑",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合规则编辑", "tags": [
"地址簿规则"
],
"summary": "地址簿规则编辑",
"parameters": [ "parameters": [
{ {
"description": "地址簿集合规则信息", "description": "地址簿规则信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
@@ -1453,7 +1483,39 @@ const docTemplateadmin = `{
} }
} }
}, },
"/admin/loginLog/delete": { "/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/login_log/delete": {
"post": { "post": {
"security": [ "security": [
{ {
@@ -1498,7 +1560,7 @@ const docTemplateadmin = `{
} }
} }
}, },
"/admin/loginLog/detail/{id}": { "/admin/login_log/detail/{id}": {
"get": { "get": {
"security": [ "security": [
{ {
@@ -1553,7 +1615,7 @@ const docTemplateadmin = `{
} }
} }
}, },
"/admin/loginLog/list": { "/admin/login_log/list": {
"get": { "get": {
"security": [ "security": [
{ {
@@ -1922,6 +1984,108 @@ 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/batchDelete": {
"post": {
"security": [
{
"token": []
}
],
"description": "批量设备删除",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"设备"
],
"summary": "批量设备删除",
"parameters": [
{
"description": "设备id",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/admin.PeerBatchDeleteForm"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/peer/create": { "/admin/peer/create": {
"post": { "post": {
"security": [ "security": [
@@ -1986,7 +2150,7 @@ const docTemplateadmin = `{
"token": [] "token": []
} }
], ],
"description": "批量设备删除", "description": "设备删除",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
@@ -1996,15 +2160,15 @@ const docTemplateadmin = `{
"tags": [ "tags": [
"设备" "设备"
], ],
"summary": "批量设备删除", "summary": "设备删除",
"parameters": [ "parameters": [
{ {
"description": "设备id", "description": "设备信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/admin.PeerBatchDeleteForm" "$ref": "#/definitions/admin.PeerForm"
} }
} }
], ],
@@ -2127,6 +2291,12 @@ const docTemplateadmin = `{
"description": "主机名", "description": "主机名",
"name": "hostname", "name": "hostname",
"in": "query" "in": "query"
},
{
"type": "string",
"description": "uuids 用逗号分隔",
"name": "uuids",
"in": "query"
} }
], ],
"responses": { "responses": {
@@ -2998,6 +3168,117 @@ const docTemplateadmin = `{
} }
} }
} }
},
"/admin/user_token/delete": {
"post": {
"security": [
{
"token": []
}
],
"description": "登录凭证删除",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"登录凭证"
],
"summary": "登录凭证删除",
"parameters": [
{
"description": "登录凭证信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.UserToken"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/user_token/list": {
"get": {
"security": [
{
"token": []
}
],
"description": "登录凭证列表",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"登录凭证"
],
"summary": "登录凭证列表",
"parameters": [
{
"type": "integer",
"description": "页码",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "页大小",
"name": "page_size",
"in": "query"
},
{
"type": "integer",
"description": "用户ID",
"name": "user_id",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.UserTokenList"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
} }
}, },
"definitions": { "definitions": {
@@ -3712,6 +3993,9 @@ const docTemplateadmin = `{
"user_id": { "user_id": {
"type": "integer" "type": "integer"
}, },
"user_token_id": {
"type": "integer"
},
"uuid": { "uuid": {
"type": "string" "type": "string"
} }
@@ -3979,6 +4263,57 @@ const docTemplateadmin = `{
} }
} }
}, },
"model.UserToken": {
"type": "object",
"properties": {
"created_at": {
"type": "string"
},
"expired_at": {
"type": "integer"
},
"id": {
"type": "integer"
},
"token": {
"type": "string"
},
"updated_at": {
"type": "string"
},
"user_id": {
"type": "integer"
}
}
},
"model.UserTokenList": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/model.UserToken"
}
},
"page": {
"type": "integer"
},
"page_size": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
},
"response.ErrorResponse": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
}
},
"response.Response": { "response.Response": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@@ -346,17 +346,20 @@
"token": [] "token": []
} }
], ],
"description": "创建地址簿集合", "description": "创建地址簿名称",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "创建地址簿集合", "tags": [
"地址簿名称"
],
"summary": "创建地址簿名称",
"parameters": [ "parameters": [
{ {
"description": "地址簿集合信息", "description": "地址簿名称信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
@@ -400,17 +403,20 @@
"token": [] "token": []
} }
], ],
"description": "地址簿集合删除", "description": "地址簿名称删除",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合删除", "tags": [
"地址簿名称"
],
"summary": "地址簿名称删除",
"parameters": [ "parameters": [
{ {
"description": "地址簿集合信息", "description": "地址簿名称信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
@@ -442,14 +448,17 @@
"token": [] "token": []
} }
], ],
"description": "地址簿集合详情", "description": "地址簿名称详情",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合详情", "tags": [
"地址簿名称"
],
"summary": "地址簿名称详情",
"parameters": [ "parameters": [
{ {
"type": "integer", "type": "integer",
@@ -494,14 +503,17 @@
"token": [] "token": []
} }
], ],
"description": "地址簿集合列表", "description": "地址簿名称列表",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合列表", "tags": [
"地址簿名称"
],
"summary": "地址簿名称列表",
"parameters": [ "parameters": [
{ {
"type": "integer", "type": "integer",
@@ -563,17 +575,20 @@
"token": [] "token": []
} }
], ],
"description": "地址簿集合编辑", "description": "地址簿名称编辑",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合编辑", "tags": [
"地址簿名称"
],
"summary": "地址簿名称编辑",
"parameters": [ "parameters": [
{ {
"description": "地址簿集合信息", "description": "地址簿名称信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
@@ -617,17 +632,20 @@
"token": [] "token": []
} }
], ],
"description": "创建地址簿集合规则", "description": "创建地址簿规则",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "创建地址簿集合规则", "tags": [
"地址簿规则"
],
"summary": "创建地址簿规则",
"parameters": [ "parameters": [
{ {
"description": "地址簿集合规则信息", "description": "地址簿规则信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
@@ -671,17 +689,20 @@
"token": [] "token": []
} }
], ],
"description": "地址簿集合规则删除", "description": "地址簿规则删除",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合规则删除", "tags": [
"地址簿规则"
],
"summary": "地址簿规则删除",
"parameters": [ "parameters": [
{ {
"description": "地址簿集合规则信息", "description": "地址簿规则信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
@@ -713,14 +734,17 @@
"token": [] "token": []
} }
], ],
"description": "地址簿集合规则详情", "description": "地址簿规则详情",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合规则详情", "tags": [
"地址簿规则"
],
"summary": "地址簿规则详情",
"parameters": [ "parameters": [
{ {
"type": "integer", "type": "integer",
@@ -765,14 +789,17 @@
"token": [] "token": []
} }
], ],
"description": "地址簿集合规则列表", "description": "地址簿规则列表",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合规则列表", "tags": [
"地址簿规则"
],
"summary": "地址簿规则列表",
"parameters": [ "parameters": [
{ {
"type": "integer", "type": "integer",
@@ -840,17 +867,20 @@
"token": [] "token": []
} }
], ],
"description": "地址簿集合规则编辑", "description": "地址簿规则编辑",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
"produces": [ "produces": [
"application/json" "application/json"
], ],
"summary": "地址簿集合规则编辑", "tags": [
"地址簿规则"
],
"summary": "地址簿规则编辑",
"parameters": [ "parameters": [
{ {
"description": "地址簿集合规则信息", "description": "地址簿规则信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
@@ -1446,7 +1476,39 @@
} }
} }
}, },
"/admin/loginLog/delete": { "/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/login_log/delete": {
"post": { "post": {
"security": [ "security": [
{ {
@@ -1491,7 +1553,7 @@
} }
} }
}, },
"/admin/loginLog/detail/{id}": { "/admin/login_log/detail/{id}": {
"get": { "get": {
"security": [ "security": [
{ {
@@ -1546,7 +1608,7 @@
} }
} }
}, },
"/admin/loginLog/list": { "/admin/login_log/list": {
"get": { "get": {
"security": [ "security": [
{ {
@@ -1915,6 +1977,108 @@
} }
} }
}, },
"/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/batchDelete": {
"post": {
"security": [
{
"token": []
}
],
"description": "批量设备删除",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"设备"
],
"summary": "批量设备删除",
"parameters": [
{
"description": "设备id",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/admin.PeerBatchDeleteForm"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/peer/create": { "/admin/peer/create": {
"post": { "post": {
"security": [ "security": [
@@ -1979,7 +2143,7 @@
"token": [] "token": []
} }
], ],
"description": "批量设备删除", "description": "设备删除",
"consumes": [ "consumes": [
"application/json" "application/json"
], ],
@@ -1989,15 +2153,15 @@
"tags": [ "tags": [
"设备" "设备"
], ],
"summary": "批量设备删除", "summary": "设备删除",
"parameters": [ "parameters": [
{ {
"description": "设备id", "description": "设备信息",
"name": "body", "name": "body",
"in": "body", "in": "body",
"required": true, "required": true,
"schema": { "schema": {
"$ref": "#/definitions/admin.PeerBatchDeleteForm" "$ref": "#/definitions/admin.PeerForm"
} }
} }
], ],
@@ -2120,6 +2284,12 @@
"description": "主机名", "description": "主机名",
"name": "hostname", "name": "hostname",
"in": "query" "in": "query"
},
{
"type": "string",
"description": "uuids 用逗号分隔",
"name": "uuids",
"in": "query"
} }
], ],
"responses": { "responses": {
@@ -2991,6 +3161,117 @@
} }
} }
} }
},
"/admin/user_token/delete": {
"post": {
"security": [
{
"token": []
}
],
"description": "登录凭证删除",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"登录凭证"
],
"summary": "登录凭证删除",
"parameters": [
{
"description": "登录凭证信息",
"name": "body",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/model.UserToken"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/admin/user_token/list": {
"get": {
"security": [
{
"token": []
}
],
"description": "登录凭证列表",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"登录凭证"
],
"summary": "登录凭证列表",
"parameters": [
{
"type": "integer",
"description": "页码",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "页大小",
"name": "page_size",
"in": "query"
},
{
"type": "integer",
"description": "用户ID",
"name": "user_id",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/response.Response"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/model.UserTokenList"
}
}
}
]
}
},
"500": {
"description": "Internal Server Error",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
} }
}, },
"definitions": { "definitions": {
@@ -3705,6 +3986,9 @@
"user_id": { "user_id": {
"type": "integer" "type": "integer"
}, },
"user_token_id": {
"type": "integer"
},
"uuid": { "uuid": {
"type": "string" "type": "string"
} }
@@ -3972,6 +4256,57 @@
} }
} }
}, },
"model.UserToken": {
"type": "object",
"properties": {
"created_at": {
"type": "string"
},
"expired_at": {
"type": "integer"
},
"id": {
"type": "integer"
},
"token": {
"type": "string"
},
"updated_at": {
"type": "string"
},
"user_id": {
"type": "integer"
}
}
},
"model.UserTokenList": {
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"$ref": "#/definitions/model.UserToken"
}
},
"page": {
"type": "integer"
},
"page_size": {
"type": "integer"
},
"total": {
"type": "integer"
}
}
},
"response.ErrorResponse": {
"type": "object",
"properties": {
"error": {
"type": "string"
}
}
},
"response.Response": { "response.Response": {
"type": "object", "type": "object",
"properties": { "properties": {

View File

@@ -476,6 +476,8 @@ definitions:
type: string type: string
user_id: user_id:
type: integer type: integer
user_token_id:
type: integer
uuid: uuid:
type: string type: string
type: object type: object
@@ -653,6 +655,39 @@ definitions:
total: total:
type: integer type: integer
type: object type: object
model.UserToken:
properties:
created_at:
type: string
expired_at:
type: integer
id:
type: integer
token:
type: string
updated_at:
type: string
user_id:
type: integer
type: object
model.UserTokenList:
properties:
list:
items:
$ref: '#/definitions/model.UserToken'
type: array
page:
type: integer
page_size:
type: integer
total:
type: integer
type: object
response.ErrorResponse:
properties:
error:
type: string
type: object
response.Response: response.Response:
properties: properties:
code: code:
@@ -868,9 +903,9 @@ paths:
post: post:
consumes: consumes:
- application/json - application/json
description: 创建地址簿集合 description: 创建地址簿名称
parameters: parameters:
- description: 地址簿集合信息 - description: 地址簿名称信息
in: body in: body
name: body name: body
required: true required: true
@@ -894,14 +929,16 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 创建地址簿集合 summary: 创建地址簿名称
tags:
- 地址簿名称
/admin/address_book_collection/delete: /admin/address_book_collection/delete:
post: post:
consumes: consumes:
- application/json - application/json
description: 地址簿集合删除 description: 地址簿名称删除
parameters: parameters:
- description: 地址簿集合信息 - description: 地址簿名称信息
in: body in: body
name: body name: body
required: true required: true
@@ -920,12 +957,14 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 地址簿集合删除 summary: 地址簿名称删除
tags:
- 地址簿名称
/admin/address_book_collection/detail/{id}: /admin/address_book_collection/detail/{id}:
get: get:
consumes: consumes:
- application/json - application/json
description: 地址簿集合详情 description: 地址簿名称详情
parameters: parameters:
- description: ID - description: ID
in: path in: path
@@ -950,12 +989,14 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 地址簿集合详情 summary: 地址簿名称详情
tags:
- 地址簿名称
/admin/address_book_collection/list: /admin/address_book_collection/list:
get: get:
consumes: consumes:
- application/json - application/json
description: 地址簿集合列表 description: 地址簿名称列表
parameters: parameters:
- description: 页码 - description: 页码
in: query in: query
@@ -991,14 +1032,16 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 地址簿集合列表 summary: 地址簿名称列表
tags:
- 地址簿名称
/admin/address_book_collection/update: /admin/address_book_collection/update:
post: post:
consumes: consumes:
- application/json - application/json
description: 地址簿集合编辑 description: 地址簿名称编辑
parameters: parameters:
- description: 地址簿集合信息 - description: 地址簿名称信息
in: body in: body
name: body name: body
required: true required: true
@@ -1022,14 +1065,16 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 地址簿集合编辑 summary: 地址簿名称编辑
tags:
- 地址簿名称
/admin/address_book_collection_rule/create: /admin/address_book_collection_rule/create:
post: post:
consumes: consumes:
- application/json - application/json
description: 创建地址簿集合规则 description: 创建地址簿规则
parameters: parameters:
- description: 地址簿集合规则信息 - description: 地址簿规则信息
in: body in: body
name: body name: body
required: true required: true
@@ -1053,14 +1098,16 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 创建地址簿集合规则 summary: 创建地址簿规则
tags:
- 地址簿规则
/admin/address_book_collection_rule/delete: /admin/address_book_collection_rule/delete:
post: post:
consumes: consumes:
- application/json - application/json
description: 地址簿集合规则删除 description: 地址簿规则删除
parameters: parameters:
- description: 地址簿集合规则信息 - description: 地址簿规则信息
in: body in: body
name: body name: body
required: true required: true
@@ -1079,12 +1126,14 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 地址簿集合规则删除 summary: 地址簿规则删除
tags:
- 地址簿规则
/admin/address_book_collection_rule/detail/{id}: /admin/address_book_collection_rule/detail/{id}:
get: get:
consumes: consumes:
- application/json - application/json
description: 地址簿集合规则详情 description: 地址簿规则详情
parameters: parameters:
- description: ID - description: ID
in: path in: path
@@ -1109,12 +1158,14 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 地址簿集合规则详情 summary: 地址簿规则详情
tags:
- 地址簿规则
/admin/address_book_collection_rule/list: /admin/address_book_collection_rule/list:
get: get:
consumes: consumes:
- application/json - application/json
description: 地址簿集合规则列表 description: 地址簿规则列表
parameters: parameters:
- description: 页码 - description: 页码
in: query in: query
@@ -1154,14 +1205,16 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 地址簿集合规则列表 summary: 地址簿规则列表
tags:
- 地址簿规则
/admin/address_book_collection_rule/update: /admin/address_book_collection_rule/update:
post: post:
consumes: consumes:
- application/json - application/json
description: 地址簿集合规则编辑 description: 地址簿规则编辑
parameters: parameters:
- description: 地址簿集合规则信息 - description: 地址簿规则信息
in: body in: body
name: body name: body
required: true required: true
@@ -1185,7 +1238,9 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 地址簿集合规则编辑 summary: 地址簿规则编辑
tags:
- 地址簿规则
/admin/app-config: /admin/app-config:
get: get:
consumes: consumes:
@@ -1520,7 +1575,28 @@ paths:
summary: 登录 summary: 登录
tags: tags:
- 登录 - 登录
/admin/loginLog/delete: /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/login_log/delete:
post: post:
consumes: consumes:
- application/json - application/json
@@ -1548,7 +1624,7 @@ paths:
summary: 登录日志删除 summary: 登录日志删除
tags: tags:
- 登录日志 - 登录日志
/admin/loginLog/detail/{id}: /admin/login_log/detail/{id}:
get: get:
consumes: consumes:
- application/json - application/json
@@ -1580,7 +1656,7 @@ paths:
summary: 登录日志详情 summary: 登录日志详情
tags: tags:
- 登录日志 - 登录日志
/admin/loginLog/list: /admin/login_log/list:
get: get:
consumes: consumes:
- application/json - application/json
@@ -1799,6 +1875,69 @@ 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/batchDelete:
post:
consumes:
- application/json
description: 批量设备删除
parameters:
- description: 设备id
in: body
name: body
required: true
schema:
$ref: '#/definitions/admin.PeerBatchDeleteForm'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 批量设备删除
tags:
- 设备
/admin/peer/create: /admin/peer/create:
post: post:
consumes: consumes:
@@ -1836,14 +1975,14 @@ paths:
post: post:
consumes: consumes:
- application/json - application/json
description: 批量设备删除 description: 设备删除
parameters: parameters:
- description: 设备id - description: 设备信息
in: body in: body
name: body name: body
required: true required: true
schema: schema:
$ref: '#/definitions/admin.PeerBatchDeleteForm' $ref: '#/definitions/admin.PeerForm'
produces: produces:
- application/json - application/json
responses: responses:
@@ -1857,7 +1996,7 @@ paths:
$ref: '#/definitions/response.Response' $ref: '#/definitions/response.Response'
security: security:
- token: [] - token: []
summary: 批量设备删除 summary: 设备删除
tags: tags:
- 设备 - 设备
/admin/peer/detail/{id}: /admin/peer/detail/{id}:
@@ -1918,6 +2057,10 @@ paths:
in: query in: query
name: hostname name: hostname
type: string type: string
- description: uuids 用逗号分隔
in: query
name: uuids
type: string
produces: produces:
- application/json - application/json
responses: responses:
@@ -2437,6 +2580,73 @@ paths:
summary: 修改密码 summary: 修改密码
tags: tags:
- 用户 - 用户
/admin/user_token/delete:
post:
consumes:
- application/json
description: 登录凭证删除
parameters:
- description: 登录凭证信息
in: body
name: body
required: true
schema:
$ref: '#/definitions/model.UserToken'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 登录凭证删除
tags:
- 登录凭证
/admin/user_token/list:
get:
consumes:
- application/json
description: 登录凭证列表
parameters:
- description: 页码
in: query
name: page
type: integer
- description: 页大小
in: query
name: page_size
type: integer
- description: 用户ID
in: query
name: user_id
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/response.Response'
- properties:
data:
$ref: '#/definitions/model.UserTokenList'
type: object
"500":
description: Internal Server Error
schema:
$ref: '#/definitions/response.Response'
security:
- token: []
summary: 登录凭证列表
tags:
- 登录凭证
securityDefinitions: securityDefinitions:
BearerAuth: BearerAuth:
in: header in: header

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

View File

@@ -14,10 +14,10 @@ import (
type AddressBookCollection struct { type AddressBookCollection struct {
} }
// Detail 地址簿集合 // Detail 地址簿名称
// @AddressBookCollections 地址簿集合 // @Tags 地址簿名称
// @Summary 地址簿集合详情 // @Summary 地址簿名称详情
// @Description 地址簿集合详情 // @Description 地址簿名称详情
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param id path int true "ID" // @Param id path int true "ID"
@@ -42,13 +42,13 @@ func (abc *AddressBookCollection) Detail(c *gin.Context) {
return return
} }
// Create 创建地址簿集合 // Create 创建地址簿名称
// @AddressBookCollections 地址簿集合 // @Tags 地址簿名称
// @Summary 创建地址簿集合 // @Summary 创建地址簿名称
// @Description 创建地址簿集合 // @Description 创建地址簿名称
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param body body model.AddressBookCollection true "地址簿集合信息" // @Param body body model.AddressBookCollection true "地址簿名称信息"
// @Success 200 {object} response.Response{data=model.AddressBookCollection} // @Success 200 {object} response.Response{data=model.AddressBookCollection}
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /admin/address_book_collection/create [post] // @Router /admin/address_book_collection/create [post]
@@ -79,9 +79,9 @@ func (abc *AddressBookCollection) Create(c *gin.Context) {
} }
// List 列表 // List 列表
// @AddressBookCollections 地址簿集合 // @Tags 地址簿名称
// @Summary 地址簿集合列表 // @Summary 地址簿名称列表
// @Description 地址簿集合列表 // @Description 地址簿名称列表
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param page query int false "页码" // @Param page query int false "页码"
@@ -111,12 +111,12 @@ func (abc *AddressBookCollection) List(c *gin.Context) {
} }
// Update 编辑 // Update 编辑
// @AddressBookCollections 地址簿集合 // @Tags 地址簿名称
// @Summary 地址簿集合编辑 // @Summary 地址簿名称编辑
// @Description 地址簿集合编辑 // @Description 地址簿名称编辑
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param body body model.AddressBookCollection true "地址簿集合信息" // @Param body body model.AddressBookCollection true "地址簿名称信息"
// @Success 200 {object} response.Response{data=model.AddressBookCollection} // @Success 200 {object} response.Response{data=model.AddressBookCollection}
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /admin/address_book_collection/update [post] // @Router /admin/address_book_collection/update [post]
@@ -151,12 +151,12 @@ func (abc *AddressBookCollection) Update(c *gin.Context) {
} }
// Delete 删除 // Delete 删除
// @AddressBookCollections 地址簿集合 // @Tags 地址簿名称
// @Summary 地址簿集合删除 // @Summary 地址簿名称删除
// @Description 地址簿集合删除 // @Description 地址簿名称删除
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param body body model.AddressBookCollection true "地址簿集合信息" // @Param body body model.AddressBookCollection true "地址簿名称信息"
// @Success 200 {object} response.Response // @Success 200 {object} response.Response
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /admin/address_book_collection/delete [post] // @Router /admin/address_book_collection/delete [post]

View File

@@ -15,9 +15,9 @@ type AddressBookCollectionRule struct {
} }
// List 列表 // List 列表
// @AddressBookCollectionRule 地址簿集合规则 // @Tags 地址簿规则
// @Summary 地址簿集合规则列表 // @Summary 地址簿规则列表
// @Description 地址簿集合规则列表 // @Description 地址簿规则列表
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param page query int false "页码" // @Param page query int false "页码"
@@ -51,10 +51,10 @@ func (abcr *AddressBookCollectionRule) List(c *gin.Context) {
response.Success(c, res) response.Success(c, res)
} }
// Detail 地址簿集合规则 // Detail 地址簿规则
// @AddressBookCollectionRule 地址簿集合规则 // @Tags 地址簿规则
// @Summary 地址簿集合规则详情 // @Summary 地址簿规则详情
// @Description 地址簿集合规则详情 // @Description 地址簿规则详情
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param id path int true "ID" // @Param id path int true "ID"
@@ -79,13 +79,13 @@ func (abcr *AddressBookCollectionRule) Detail(c *gin.Context) {
return return
} }
// Create 创建地址簿集合规则 // Create 创建地址簿规则
// @AddressBookCollectionRule 地址簿集合规则 // @Tags 地址簿规则
// @Summary 创建地址簿集合规则 // @Summary 创建地址簿规则
// @Description 创建地址簿集合规则 // @Description 创建地址簿规则
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param body body model.AddressBookCollectionRule true "地址簿集合规则信息" // @Param body body model.AddressBookCollectionRule true "地址簿规则信息"
// @Success 200 {object} response.Response{data=model.AddressBookCollection} // @Success 200 {object} response.Response{data=model.AddressBookCollection}
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /admin/address_book_collection_rule/create [post] // @Router /admin/address_book_collection_rule/create [post]
@@ -169,12 +169,12 @@ func (abcr *AddressBookCollectionRule) CheckForm(u *model.User, t *model.Address
} }
// Update 编辑 // Update 编辑
// @AddressBookCollectionRule 地址簿集合规则 // @Tags 地址簿规则
// @Summary 地址簿集合规则编辑 // @Summary 地址簿规则编辑
// @Description 地址簿集合规则编辑 // @Description 地址簿规则编辑
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param body body model.AddressBookCollectionRule true "地址簿集合规则信息" // @Param body body model.AddressBookCollectionRule true "地址簿规则信息"
// @Success 200 {object} response.Response{data=model.AddressBookCollection} // @Success 200 {object} response.Response{data=model.AddressBookCollection}
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /admin/address_book_collection_rule/update [post] // @Router /admin/address_book_collection_rule/update [post]
@@ -210,12 +210,12 @@ func (abcr *AddressBookCollectionRule) Update(c *gin.Context) {
} }
// Delete 删除 // Delete 删除
// @AddressBookCollectionRule 地址簿集合规则 // @Tags 地址簿规则
// @Summary 地址簿集合规则删除 // @Summary 地址簿规则删除
// @Description 地址簿集合规则删除 // @Description 地址簿规则删除
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param body body model.AddressBookCollectionRule true "地址簿集合规则信息" // @Param body body model.AddressBookCollectionRule true "地址簿规则信息"
// @Success 200 {object} response.Response // @Success 200 {object} response.Response
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /admin/address_book_collection_rule/delete [post] // @Router /admin/address_book_collection_rule/delete [post]

View File

@@ -2,13 +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"
"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 {
@@ -50,10 +53,10 @@ func (ct *Login) Login(c *gin.Context) {
ut := service.AllService.UserService.Login(u, &model.LoginLog{ ut := service.AllService.UserService.Login(u, &model.LoginLog{
UserId: u.Id, UserId: u.Id,
Client: "webadmin", Client: model.LoginLogClientWebAdmin,
Uuid: "", Uuid: "", //must be empty
Ip: c.ClientIP(), Ip: c.ClientIP(),
Type: "account", Type: model.LoginLogTypeAccount,
Platform: f.Platform, Platform: f.Platform,
}) })
@@ -82,3 +85,90 @@ func (ct *Login) Logout(c *gin.Context) {
} }
response.Success(c, nil) 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, gin.H{
"ops": ops,
"register": global.Config.App.Register,
})
}
// 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,
})
}

View File

@@ -23,7 +23,7 @@ type LoginLog struct {
// @Param id path int true "ID" // @Param id path int true "ID"
// @Success 200 {object} response.Response{data=model.LoginLog} // @Success 200 {object} response.Response{data=model.LoginLog}
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /admin/loginLog/detail/{id} [get] // @Router /admin/login_log/detail/{id} [get]
// @Security token // @Security token
func (ct *LoginLog) Detail(c *gin.Context) { func (ct *LoginLog) Detail(c *gin.Context) {
id := c.Param("id") id := c.Param("id")
@@ -48,7 +48,7 @@ func (ct *LoginLog) Detail(c *gin.Context) {
// @Param user_id query int false "用户ID" // @Param user_id query int false "用户ID"
// @Success 200 {object} response.Response{data=model.LoginLogList} // @Success 200 {object} response.Response{data=model.LoginLogList}
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /admin/loginLog/list [get] // @Router /admin/login_log/list [get]
// @Security token // @Security token
func (ct *LoginLog) List(c *gin.Context) { func (ct *LoginLog) List(c *gin.Context) {
query := &admin.LoginLogQuery{} query := &admin.LoginLogQuery{}
@@ -78,7 +78,7 @@ func (ct *LoginLog) List(c *gin.Context) {
// @Param body body model.LoginLog true "登录日志信息" // @Param body body model.LoginLog true "登录日志信息"
// @Success 200 {object} response.Response // @Success 200 {object} response.Response
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /admin/loginLog/delete [post] // @Router /admin/login_log/delete [post]
// @Security token // @Security token
func (ct *LoginLog) Delete(c *gin.Context) { func (ct *LoginLog) Delete(c *gin.Context) {
f := &model.LoginLog{} f := &model.LoginLog{}

View File

@@ -102,7 +102,7 @@ func (o *Oauth) BindConfirm(c *gin.Context) {
return return
} }
u := service.AllService.UserService.CurUser(c) 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 { if err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "BindFail")) response.Fail(c, 101, response.TranslateMsg(c, "BindFail"))
return return

View File

@@ -79,6 +79,7 @@ func (ct *Peer) Create(c *gin.Context) {
// @Param time_ago query int false "时间" // @Param time_ago query int false "时间"
// @Param id query string false "ID" // @Param id query string false "ID"
// @Param hostname query string false "主机名" // @Param hostname query string false "主机名"
// @Param uuids query string false "uuids 用逗号分隔"
// @Success 200 {object} response.Response{data=model.PeerList} // @Success 200 {object} response.Response{data=model.PeerList}
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /admin/peer/list [get] // @Router /admin/peer/list [get]
@@ -104,6 +105,9 @@ func (ct *Peer) List(c *gin.Context) {
if query.Hostname != "" { if query.Hostname != "" {
tx.Where("hostname like ?", "%"+query.Hostname+"%") tx.Where("hostname like ?", "%"+query.Hostname+"%")
} }
if query.Uuids != "" {
tx.Where("uuid in (?)", query.Uuids)
}
}) })
response.Success(c, res) response.Success(c, res)
} }
@@ -188,7 +192,7 @@ func (ct *Peer) Delete(c *gin.Context) {
// @Param body body admin.PeerBatchDeleteForm true "设备id" // @Param body body admin.PeerBatchDeleteForm true "设备id"
// @Success 200 {object} response.Response // @Success 200 {object} response.Response
// @Failure 500 {object} response.Response // @Failure 500 {object} response.Response
// @Router /admin/peer/delete [post] // @Router /admin/peer/batchDelete [post]
// @Security token // @Security token
func (ct *Peer) BatchDelete(c *gin.Context) { func (ct *Peer) BatchDelete(c *gin.Context) {
f := &admin.PeerBatchDeleteForm{} f := &admin.PeerBatchDeleteForm{}

View File

@@ -5,6 +5,7 @@ import (
"Gwen/http/request/admin" "Gwen/http/request/admin"
"Gwen/http/response" "Gwen/http/response"
adResp "Gwen/http/response/admin" adResp "Gwen/http/response/admin"
"Gwen/model"
"Gwen/service" "Gwen/service"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"gorm.io/gorm" "gorm.io/gorm"
@@ -247,10 +248,14 @@ func (ct *User) ChangeCurPwd(c *gin.Context) {
return return
} }
u := service.AllService.UserService.CurUser(c) u := service.AllService.UserService.CurUser(c)
oldPwd := service.AllService.UserService.EncryptPassword(f.OldPassword) // If the password is not empty, the old password is verified
if u.Password != oldPwd { // otherwise, the old password is not verified
response.Fail(c, 101, response.TranslateMsg(c, "OldPasswordError")) if !service.AllService.UserService.IsPasswordEmptyByUser(u) {
return oldPwd := service.AllService.UserService.EncryptPassword(f.OldPassword)
if u.Password != oldPwd {
response.Fail(c, 101, response.TranslateMsg(c, "OldPasswordError"))
return
}
} }
err := service.AllService.UserService.UpdatePassword(u, f.NewPassword) err := service.AllService.UserService.UpdatePassword(u, f.NewPassword)
if err != nil { if err != nil {
@@ -323,3 +328,40 @@ func (ct *User) GroupUsers(c *gin.Context) {
} }
response.Success(c, data) response.Success(c, data)
} }
// Register
func (ct *User) Register(c *gin.Context) {
if !global.Config.App.Register {
response.Fail(c, 101, response.TranslateMsg(c, "RegisterClosed"))
return
}
f := &admin.RegisterForm{}
if err := c.ShouldBindJSON(f); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
errList := global.Validator.ValidStruct(c, f)
if len(errList) > 0 {
response.Fail(c, 101, errList[0])
return
}
u := service.AllService.UserService.Register(f.Username, f.Password)
if u == nil || u.Id == 0 {
response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed"))
return
}
// 注册成功后自动登录
ut := service.AllService.UserService.Login(u, &model.LoginLog{
UserId: u.Id,
Client: model.LoginLogClientWebAdmin,
Uuid: "",
Ip: c.ClientIP(),
Type: model.LoginLogTypeAccount,
})
response.Success(c, &adResp.LoginPayload{
Token: ut.Token,
Username: u.Username,
RouteNames: service.AllService.UserService.RouteNames(u),
Nickname: u.Nickname,
})
}

View File

@@ -0,0 +1,83 @@
package admin
import (
"Gwen/global"
"Gwen/http/request/admin"
"Gwen/http/response"
"Gwen/model"
"Gwen/service"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
type UserToken struct {
}
// List 列表
// @Tags 登录凭证
// @Summary 登录凭证列表
// @Description 登录凭证列表
// @Accept json
// @Produce json
// @Param page query int false "页码"
// @Param page_size query int false "页大小"
// @Param user_id query int false "用户ID"
// @Success 200 {object} response.Response{data=model.UserTokenList}
// @Failure 500 {object} response.Response
// @Router /admin/user_token/list [get]
// @Security token
func (ct *UserToken) List(c *gin.Context) {
query := &admin.LoginTokenQuery{}
if err := c.ShouldBindQuery(query); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
res := service.AllService.UserService.TokenList(query.Page, query.PageSize, func(tx *gorm.DB) {
if query.UserId > 0 {
tx.Where("user_id = ?", query.UserId)
}
tx.Order("id desc")
})
response.Success(c, res)
}
// Delete 删除
// @Tags 登录凭证
// @Summary 登录凭证删除
// @Description 登录凭证删除
// @Accept json
// @Produce json
// @Param body body model.UserToken true "登录凭证信息"
// @Success 200 {object} response.Response
// @Failure 500 {object} response.Response
// @Router /admin/user_token/delete [post]
// @Security token
func (ct *UserToken) Delete(c *gin.Context) {
f := &model.UserToken{}
if err := c.ShouldBindJSON(f); err != nil {
response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
return
}
id := f.Id
errList := global.Validator.ValidVar(c, id, "required,gt=0")
if len(errList) > 0 {
response.Fail(c, 101, errList[0])
return
}
l := service.AllService.UserService.TokenInfoById(f.Id)
u := service.AllService.UserService.CurUser(c)
if !service.AllService.UserService.IsAdmin(u) && l.UserId != u.Id {
response.Fail(c, 101, response.TranslateMsg(c, "NoAccess"))
return
}
if l.Id > 0 {
err := service.AllService.UserService.DeleteToken(l)
if err == nil {
response.Success(c, nil)
return
}
response.Fail(c, 101, err.Error())
return
}
response.Fail(c, 101, response.TranslateMsg(c, "ItemNotFound"))
}

View File

@@ -54,7 +54,7 @@ func (l *Login) Login(c *gin.Context) {
//根据refer判断是webclient还是app //根据refer判断是webclient还是app
ref := c.GetHeader("referer") ref := c.GetHeader("referer")
if ref != "" { if ref != "" {
f.DeviceInfo.Type = "webclient" f.DeviceInfo.Type = model.LoginLogClientWeb
} }
ut := service.AllService.UserService.Login(u, &model.LoginLog{ ut := service.AllService.UserService.Login(u, &model.LoginLog{

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
@@ -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 // OidcAuthQuery
// @Tags Oauth // @Tags Oauth
// @Summary OidcAuthQuery // @Summary OidcAuthQuery
@@ -69,33 +123,10 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
// @Failure 500 {object} response.ErrorResponse // @Failure 500 {object} response.ErrorResponse
// @Router /oidc/auth-query [get] // @Router /oidc/auth-query [get]
func (o *Oauth) OidcAuthQuery(c *gin.Context) { func (o *Oauth) OidcAuthQuery(c *gin.Context) {
q := &api.OidcAuthQuery{} u, ut := o.OidcAuthQueryPre(c)
err := c.ShouldBindQuery(q) if u == nil || ut == nil {
if err != nil {
response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
return 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{ c.JSON(http.StatusOK, apiResp.LoginRes{
AccessToken: ut.Token, AccessToken: ut.Token,
Type: "access_token", Type: "access_token",
@@ -129,7 +160,11 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
ty := v.Op ty := v.Op
ac := v.Action ac := v.Action
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)
@@ -137,187 +172,100 @@ 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)) } else if ty == model.OauthTypeGoogle {
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 {
code := c.Query("code") code := c.Query("code")
err, userData := service.AllService.OauthService.GoogleCallback(code) err, userData := service.AllService.OauthService.GoogleCallback(code)
if err != nil { if err != nil {
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 { } else if ty == model.OauthTypeOidc {
//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 {
code := c.Query("code") code := c.Query("code")
err, userData := service.AllService.OauthService.OidcCallback(code) err, userData := service.AllService.OauthService.OidcCallback(code)
if err != nil { if err != nil {
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
if ac == service.OauthActionTypeBind { } else {
//fmt.Println("bind", ty, userData) c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ParamsError"))
utr := service.AllService.OauthService.UserThirdInfo(ty, userData.Sub) return
if utr.UserId > 0 { }
c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser")) if ac == service.OauthActionTypeBind {
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, "还未绑定用户,请先绑定")
v.ThirdName = userData.PreferredUsername //fmt.Println("bind", ty, userData)
v.ThirdOpenId = userData.Sub utr := service.AllService.OauthService.UserThirdInfo(ty, openid)
v.ThirdEmail = userData.Email if utr.UserId > 0 {
url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser"))
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"))
return 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"))
} }

View File

@@ -11,3 +11,7 @@ type LoginLogQuery struct {
IsMy int `form:"is_my"` IsMy int `form:"is_my"`
PageQuery PageQuery
} }
type LoginTokenQuery struct {
UserId int `form:"user_id"`
PageQuery
}

View File

@@ -38,6 +38,7 @@ type PeerQuery struct {
TimeAgo int `json:"time_ago" form:"time_ago"` TimeAgo int `json:"time_ago" form:"time_ago"`
Id string `json:"id" form:"id"` Id string `json:"id" form:"id"`
Hostname string `json:"hostname" form:"hostname"` Hostname string `json:"hostname" form:"hostname"`
Uuids string `json:"uuids" form:"uuids"`
} }
type SimpleDataQuery struct { type SimpleDataQuery struct {

View File

@@ -59,3 +59,9 @@ type GroupUsersQuery struct {
IsMy int `json:"is_my"` IsMy int `json:"is_my"`
UserId uint `json:"user_id"` UserId uint `json:"user_id"`
} }
type RegisterForm struct {
Username string `json:"username" validate:"required,gte=4,lte=10"`
Password string `json:"password" validate:"required,gte=4,lte=20"`
ConfirmPassword string `json:"confirm_password" validate:"required,gte=4,lte=20"`
}

View File

@@ -17,7 +17,7 @@ func Init(g *gin.Engine) {
adg := g.Group("/api/admin") adg := g.Group("/api/admin")
LoginBind(adg) LoginBind(adg)
adg.POST("/user/register", (&admin.User{}).Register)
adg.Use(middleware.AdminAuth()) adg.Use(middleware.AdminAuth())
//FileBind(adg) //FileBind(adg)
UserBind(adg) UserBind(adg)
@@ -30,10 +30,10 @@ func Init(g *gin.Engine) {
AuditBind(adg) AuditBind(adg)
AddressBookCollectionBind(adg) AddressBookCollectionBind(adg)
AddressBookCollectionRuleBind(adg) AddressBookCollectionRuleBind(adg)
UserTokenBind(adg)
rs := &admin.Rustdesk{} rs := &admin.Rustdesk{}
adg.GET("/server-config", rs.ServerConfig) adg.GET("/server-config", rs.ServerConfig)
adg.GET("/app-config", rs.AppConfig) adg.GET("/app-config", rs.AppConfig)
//访问静态文件 //访问静态文件
//g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/upload")) //g.StaticFS("/upload", http.Dir(global.Config.Gin.ResourcesPath+"/upload"))
} }
@@ -41,6 +41,9 @@ func LoginBind(rg *gin.RouterGroup) {
cont := &admin.Login{} cont := &admin.Login{}
rg.POST("/login", cont.Login) rg.POST("/login", cont.Login)
rg.POST("/logout", cont.Logout) 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) { func UserBind(rg *gin.RouterGroup) {
@@ -105,6 +108,8 @@ func AddressBookBind(rg *gin.RouterGroup) {
} }
func PeerBind(rg *gin.RouterGroup) { func PeerBind(rg *gin.RouterGroup) {
aR := rg.Group("/peer") aR := rg.Group("/peer")
aR.POST("/simpleData", (&admin.Peer{}).SimpleData)
aR.Use(middleware.AdminPrivilege())
{ {
cont := &admin.Peer{} cont := &admin.Peer{}
aR.GET("/list", cont.List) aR.GET("/list", cont.List)
@@ -112,10 +117,7 @@ func PeerBind(rg *gin.RouterGroup) {
aR.POST("/create", cont.Create) aR.POST("/create", cont.Create)
aR.POST("/update", cont.Update) aR.POST("/update", cont.Update)
aR.POST("/delete", cont.Delete) aR.POST("/delete", cont.Delete)
aR.POST("/simpleData", cont.SimpleData) aR.POST("/batchDelete", cont.BatchDelete)
arp := aR.Use(middleware.AdminPrivilege())
arp.POST("/batchDelete", cont.BatchDelete)
} }
} }
@@ -179,6 +181,12 @@ func AddressBookCollectionRuleBind(rg *gin.RouterGroup) {
aR.POST("/delete", cont.Delete) aR.POST("/delete", cont.Delete)
} }
} }
func UserTokenBind(rg *gin.RouterGroup) {
aR := rg.Group("/user_token").Use(middleware.AdminPrivilege())
cont := &admin.UserToken{}
aR.GET("/list", cont.List)
aR.POST("/delete", cont.Delete)
}
/* /*
func FileBind(rg *gin.RouterGroup) { func FileBind(rg *gin.RouterGroup) {

View File

@@ -2,16 +2,22 @@ package model
type LoginLog struct { type LoginLog struct {
IdModel IdModel
UserId uint `json:"user_id"` UserId uint `json:"user_id" gorm:"default:0;not null;"`
Client string `json:"client"` //webadmin,webclient,app, Client string `json:"client"` //webadmin,webclient,app,
Uuid string `json:"uuid"` Uuid string `json:"uuid"`
Ip string `json:"ip"` Ip string `json:"ip"`
Type string `json:"type"` //account,oauth Type string `json:"type"` //account,oauth
Platform string `json:"platform"` //windows,linux,mac,android,ios Platform string `json:"platform"` //windows,linux,mac,android,ios
UserTokenId uint `json:"user_token_id" gorm:"default:0;not null;"`
TimeModel TimeModel
} }
const (
LoginLogClientWebAdmin = "webadmin"
LoginLogClientWeb = "webclient"
LoginLogClientApp = "app"
)
const ( const (
LoginLogTypeAccount = "account" LoginLogTypeAccount = "account"
LoginLogTypeOauth = "oauth" LoginLogTypeOauth = "oauth"

View File

@@ -7,3 +7,8 @@ type UserToken struct {
ExpiredAt int64 `json:"expired_at" gorm:"default:0;not null;"` ExpiredAt int64 `json:"expired_at" gorm:"default:0;not null;"`
TimeModel TimeModel
} }
type UserTokenList struct {
UserTokens []UserToken `json:"list"`
Pagination
}

View File

@@ -119,3 +119,7 @@ other = "Default Group"
description = "Share group" description = "Share group"
one = "Share Group" one = "Share Group"
other = "Share Group" other = "Share Group"
[RegisterClosed]
description = "Register closed."
one = "Register closed."
other = "Register closed."

View File

@@ -121,3 +121,8 @@ other = "기본 그룹"
description = "Share group." description = "Share group."
one = "공유 그룹" one = "공유 그룹"
other = "공유 그룹" other = "공유 그룹"
[RegisterClosed]
description = "Register closed."
one = "가입이 종료되었습니다."
other = "가입이 종료되었습니다."

View File

@@ -127,3 +127,8 @@ other = "Группа по умолчанию"
description = "Share group." description = "Share group."
one = "Общая группа" one = "Общая группа"
other = "Общая группа" other = "Общая группа"
[RegisterClosed]
description = "Register closed."
one = "Регистрация закрыта."
other = "Регистрация закрыта."

View File

@@ -121,3 +121,7 @@ other = "默认组"
description = "Share group." description = "Share group."
one = "共享组" one = "共享组"
other = "共享组" other = "共享组"
[RegisterClosed]
description = "Register closed."
one = "注册已关闭。"
other = "注册已关闭。"

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.")
@@ -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 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取用户信息 // InfoById 根据id取用户信息
func (os *OauthService) InfoById(id uint) *model.Oauth { func (os *OauthService) InfoById(id uint) *model.Oauth {
u := &model.Oauth{} u := &model.Oauth{}

View File

@@ -70,6 +70,7 @@ func (us *UserService) Login(u *model.User, llog *model.LoginLog) *model.UserTok
ExpiredAt: time.Now().Add(time.Hour * 24 * 7).Unix(), ExpiredAt: time.Now().Add(time.Hour * 24 * 7).Unix(),
} }
global.DB.Create(ut) global.DB.Create(ut)
llog.UserTokenId = ut.UserId
global.DB.Create(llog) global.DB.Create(llog)
if llog.Uuid != "" { if llog.Uuid != "" {
AllService.PeerService.UuidBindUserId(llog.Uuid, u.Id) AllService.PeerService.UuidBindUserId(llog.Uuid, u.Id)
@@ -148,8 +149,37 @@ func (us *UserService) Create(u *model.User) error {
func (us *UserService) Logout(u *model.User, token string) 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 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 { 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 更新 // Update 更新
@@ -252,14 +282,14 @@ func (us *UserService) RegisterByOauth(thirdType, thirdName, uid string) *model.
Username: username, Username: username,
GroupId: 1, GroupId: 1,
} }
global.DB.Create(u) tx.Create(u)
if u.Id == 0 { if u.Id == 0 {
tx.Rollback() tx.Rollback()
return u return u
} }
ut.UserId = u.Id ut.UserId = u.Id
global.DB.Create(ut) tx.Create(ut)
tx.Commit() tx.Commit()
return u return u
@@ -294,3 +324,60 @@ func (us *UserService) FindLatestUserIdFromLoginLogByUuid(uuid string) uint {
global.DB.Where("uuid = ?", uuid).Order("id desc").First(llog) global.DB.Where("uuid = ?", uuid).Order("id desc").First(llog)
return llog.UserId return llog.UserId
} }
// IsPasswordEmptyById 根据用户id判断密码是否为空主要用于第三方登录的自动注册
func (us *UserService) IsPasswordEmptyById(id uint) bool {
u := &model.User{}
if global.DB.Where("id = ?", id).First(u).Error != nil {
return false
}
return u.Password == ""
}
// IsPasswordEmptyByUsername 根据用户id判断密码是否为空主要用于第三方登录的自动注册
func (us *UserService) IsPasswordEmptyByUsername(username string) bool {
u := &model.User{}
if global.DB.Where("username = ?", username).First(u).Error != nil {
return false
}
return u.Password == ""
}
// IsPasswordEmptyByUser 判断密码是否为空,主要用于第三方登录的自动注册
func (us *UserService) IsPasswordEmptyByUser(u *model.User) bool {
return us.IsPasswordEmptyById(u.Id)
}
func (us *UserService) Register(username string, password string) *model.User {
u := &model.User{
Username: username,
Password: us.EncryptPassword(password),
GroupId: 1,
}
global.DB.Create(u)
return u
}
func (us *UserService) TokenList(page uint, size uint, f func(tx *gorm.DB)) *model.UserTokenList {
res := &model.UserTokenList{}
res.Page = int64(page)
res.PageSize = int64(size)
tx := global.DB.Model(&model.UserToken{})
if f != nil {
f(tx)
}
tx.Count(&res.Total)
tx.Scopes(Paginate(page, size))
tx.Find(&res.UserTokens)
return res
}
func (us *UserService) TokenInfoById(id uint) *model.UserToken {
ut := &model.UserToken{}
global.DB.Where("id = ?", id).First(ut)
return ut
}
func (us *UserService) DeleteToken(l *model.UserToken) error {
return global.DB.Delete(l).Error
}