Просмотр исходного кода

Merge branch 'master' into resetEmptyPassWD

Tao Chen 1 год назад
Родитель
Сommit
5488babfb3

+ 2 - 0
README.md

@@ -159,6 +159,7 @@
159 159
 lang: "en"
160 160
 app:
161 161
   web-client: 1  # 1:启用 0:禁用
162
+  register: false #是否开启注册
162 163
 gin:
163 164
   api-addr: "0.0.0.0:21114"
164 165
   mode: "release"
@@ -196,6 +197,7 @@ proxy:
196 197
 | TZ                                 | 时区                                   | Asia/Shanghai               |
197 198
 | RUSTDESK_API_LANG                  | 语言                                   | `en`,`zh-CN`                |
198 199
 | RUSTDESK_API_APP_WEB_CLIENT        | 是否启用web-client; 1:启用,0:不启用; 默认启用     | 1                           |
200
+| RUSTDESK_API_APP_REGISTER          | 是否开启注册; `true`, `false`  默认`false`   | `false`                     |
199 201
 | -----GIN配置-----                    | ----------                           | ----------                  |
200 202
 | RUSTDESK_API_GIN_TRUST_PROXY       | 信任的代理IP列表,以`,`分割,默认信任所有              | 192.168.1.2,192.168.1.3     |
201 203
 | -----------GORM配置----------------  | ------------------------------------ | --------------------------- |

+ 2 - 0
README_EN.md

@@ -165,6 +165,7 @@ installation are `admin` `admin`, please change the password immediately.
165 165
 lang: "en"
166 166
 app:
167 167
   web-client: 1  # web client route 1:open 0:close  
168
+  register: false #register enable
168 169
 gin:
169 170
   api-addr: "0.0.0.0:21114"
170 171
   mode: "release"
@@ -202,6 +203,7 @@ The prefix for variable names is `RUSTDESK_API`. If environment variables exist,
202 203
 | TZ                                 | timezone                                                  | Asia/Shanghai                 |
203 204
 | RUSTDESK_API_LANG                  | Language                                                  | `en`,`zh-CN`                  |
204 205
 | RUSTDESK_API_APP_WEB_CLIENT        | web client on/off; 1: on, 0 off, deault 1                 | 1                             |
206
+| RUSTDESK_API_APP_REGISTER          | register enable; `true`, `false`; default:`false`         | `false`                       |
205 207
 | ----- GIN Configuration -----      | ---------------------------------------                   | ----------------------------- |
206 208
 | RUSTDESK_API_GIN_TRUST_PROXY       | Trusted proxy IPs, separated by commas.                   | 192.168.1.2,192.168.1.3       |
207 209
 | ----- GORM Configuration -----     | ---------------------------------------                   | ----------------------------- |

+ 1 - 1
cmd/apimain.go

@@ -101,7 +101,7 @@ func main() {
101 101
 }
102 102
 
103 103
 func DatabaseAutoUpdate() {
104
-	version := 242
104
+	version := 243
105 105
 
106 106
 	db := global.DB
107 107
 

+ 1 - 0
conf/config.yaml

@@ -1,6 +1,7 @@
1 1
 lang: "zh-CN"
2 2
 app:
3 3
   web-client: 1  # 1:启用 0:禁用
4
+  register: false #是否开启注册
4 5
 gin:
5 6
   api-addr: "0.0.0.0:21114"
6 7
   mode: "release" #release,debug,test

+ 2 - 1
config/config.go

@@ -15,7 +15,8 @@ const (
15 15
 )
16 16
 
17 17
 type App struct {
18
-	WebClient int `mapstructure:"web-client"`
18
+	WebClient int  `mapstructure:"web-client"`
19
+	Register  bool `mapstructure:"register"`
19 20
 }
20 21
 
21 22
 type Config struct {

+ 20 - 0
docker-compose-dev.yaml

@@ -0,0 +1,20 @@
1
+services:
2
+  rustdesk-api:
3
+    build: 
4
+      context: .
5
+      dockerfile: Dockerfile.dev
6
+    # image: lejianwen/rustdesk-api
7
+    container_name: rustdesk-api
8
+    environment:
9
+      - TZ=Asia/Shanghai
10
+      - RUSTDESK_API_RUSTDESK_ID_SERVER=192.168.1.66:21116
11
+      - RUSTDESK_API_RUSTDESK_RELAY_SERVER=192.168.1.66:21117
12
+      - RUSTDESK_API_RUSTDESK_API_SERVER=http://127.0.0.1:21114
13
+      - RUSTDESK_API_RUSTDESK_KEY=123456789
14
+    ports:
15
+      - 21114:21114
16
+    volumes:
17
+      - ./data/rustdesk/api:/app/data #将数据库挂载出来方便备份
18
+      - ./conf:/app/conf # config
19
+      # - ./resources:/app/resources # 静态资源
20
+    restart: unless-stopped

+ 3 - 6
docker-compose.yaml

@@ -1,9 +1,6 @@
1 1
 services:
2 2
   rustdesk-api:
3
-    build: 
4
-      context: .
5
-      dockerfile: Dockerfile.dev
6
-    # image: lejianwen/rustdesk-api
3
+    image: lejianwen/rustdesk-api
7 4
     container_name: rustdesk-api
8 5
     environment:
9 6
       - TZ=Asia/Shanghai
@@ -14,7 +11,7 @@ services:
14 11
     ports:
15 12
       - 21114:21114
16 13
     volumes:
17
-      - ./data/rustdesk/api:/app/data #将数据库挂载出来方便备份
18
-      - ./conf:/app/conf # config
14
+      - ./data/rustdesk/api:/app/data # database
15
+      # - ./conf:/app/conf # config
19 16
       # - ./resources:/app/resources # 静态资源
20 17
     restart: unless-stopped

+ 112 - 0
docs/admin/admin_docs.go

@@ -1453,6 +1453,38 @@ const docTemplateadmin = `{
1453 1453
                 }
1454 1454
             }
1455 1455
         },
1456
+        "/admin/login-options": {
1457
+            "post": {
1458
+                "description": "登录选项",
1459
+                "consumes": [
1460
+                    "application/json"
1461
+                ],
1462
+                "produces": [
1463
+                    "application/json"
1464
+                ],
1465
+                "tags": [
1466
+                    "登录"
1467
+                ],
1468
+                "summary": "登录选项",
1469
+                "responses": {
1470
+                    "200": {
1471
+                        "description": "OK",
1472
+                        "schema": {
1473
+                            "type": "array",
1474
+                            "items": {
1475
+                                "type": "string"
1476
+                            }
1477
+                        }
1478
+                    },
1479
+                    "500": {
1480
+                        "description": "Internal Server Error",
1481
+                        "schema": {
1482
+                            "$ref": "#/definitions/response.ErrorResponse"
1483
+                        }
1484
+                    }
1485
+                }
1486
+            }
1487
+        },
1456 1488
         "/admin/loginLog/delete": {
1457 1489
             "post": {
1458 1490
                 "security": [
@@ -1922,6 +1954,63 @@ const docTemplateadmin = `{
1922 1954
                 }
1923 1955
             }
1924 1956
         },
1957
+        "/admin/oidc/auth": {
1958
+            "post": {
1959
+                "description": "OidcAuth",
1960
+                "consumes": [
1961
+                    "application/json"
1962
+                ],
1963
+                "produces": [
1964
+                    "application/json"
1965
+                ],
1966
+                "tags": [
1967
+                    "Oauth"
1968
+                ],
1969
+                "summary": "OidcAuth",
1970
+                "responses": {}
1971
+            }
1972
+        },
1973
+        "/admin/oidc/auth-query": {
1974
+            "get": {
1975
+                "description": "OidcAuthQuery",
1976
+                "consumes": [
1977
+                    "application/json"
1978
+                ],
1979
+                "produces": [
1980
+                    "application/json"
1981
+                ],
1982
+                "tags": [
1983
+                    "Oauth"
1984
+                ],
1985
+                "summary": "OidcAuthQuery",
1986
+                "responses": {
1987
+                    "200": {
1988
+                        "description": "OK",
1989
+                        "schema": {
1990
+                            "allOf": [
1991
+                                {
1992
+                                    "$ref": "#/definitions/response.Response"
1993
+                                },
1994
+                                {
1995
+                                    "type": "object",
1996
+                                    "properties": {
1997
+                                        "data": {
1998
+                                            "$ref": "#/definitions/admin.LoginPayload"
1999
+                                        }
2000
+                                    }
2001
+                                }
2002
+                            ]
2003
+                        }
2004
+                    },
2005
+                    "500": {
2006
+                        "description": "Internal Server Error",
2007
+                        "schema": {
2008
+                            "$ref": "#/definitions/response.Response"
2009
+                        }
2010
+                    }
2011
+                }
2012
+            }
2013
+        },
1925 2014
         "/admin/peer/create": {
1926 2015
             "post": {
1927 2016
                 "security": [
@@ -3164,11 +3253,17 @@ const docTemplateadmin = `{
3164 3253
                 "id": {
3165 3254
                     "type": "integer"
3166 3255
                 },
3256
+                "issuer": {
3257
+                    "type": "string"
3258
+                },
3167 3259
                 "op": {
3168 3260
                     "type": "string"
3169 3261
                 },
3170 3262
                 "redirect_url": {
3171 3263
                     "type": "string"
3264
+                },
3265
+                "scopes": {
3266
+                    "type": "string"
3172 3267
                 }
3173 3268
             }
3174 3269
         },
@@ -3749,12 +3844,18 @@ const docTemplateadmin = `{
3749 3844
                 "id": {
3750 3845
                     "type": "integer"
3751 3846
                 },
3847
+                "issuer": {
3848
+                    "type": "string"
3849
+                },
3752 3850
                 "op": {
3753 3851
                     "type": "string"
3754 3852
                 },
3755 3853
                 "redirect_url": {
3756 3854
                     "type": "string"
3757 3855
                 },
3856
+                "scopes": {
3857
+                    "type": "string"
3858
+                },
3758 3859
                 "updated_at": {
3759 3860
                     "type": "string"
3760 3861
                 }
@@ -3795,6 +3896,9 @@ const docTemplateadmin = `{
3795 3896
                 "id": {
3796 3897
                     "type": "string"
3797 3898
                 },
3899
+                "last_online_ip": {
3900
+                    "type": "string"
3901
+                },
3798 3902
                 "last_online_time": {
3799 3903
                     "type": "integer"
3800 3904
                 },
@@ -3964,6 +4068,14 @@ const docTemplateadmin = `{
3964 4068
                 }
3965 4069
             }
3966 4070
         },
4071
+        "response.ErrorResponse": {
4072
+            "type": "object",
4073
+            "properties": {
4074
+                "error": {
4075
+                    "type": "string"
4076
+                }
4077
+            }
4078
+        },
3967 4079
         "response.Response": {
3968 4080
             "type": "object",
3969 4081
             "properties": {

+ 112 - 0
docs/admin/admin_swagger.json

@@ -1446,6 +1446,38 @@
1446 1446
                 }
1447 1447
             }
1448 1448
         },
1449
+        "/admin/login-options": {
1450
+            "post": {
1451
+                "description": "登录选项",
1452
+                "consumes": [
1453
+                    "application/json"
1454
+                ],
1455
+                "produces": [
1456
+                    "application/json"
1457
+                ],
1458
+                "tags": [
1459
+                    "登录"
1460
+                ],
1461
+                "summary": "登录选项",
1462
+                "responses": {
1463
+                    "200": {
1464
+                        "description": "OK",
1465
+                        "schema": {
1466
+                            "type": "array",
1467
+                            "items": {
1468
+                                "type": "string"
1469
+                            }
1470
+                        }
1471
+                    },
1472
+                    "500": {
1473
+                        "description": "Internal Server Error",
1474
+                        "schema": {
1475
+                            "$ref": "#/definitions/response.ErrorResponse"
1476
+                        }
1477
+                    }
1478
+                }
1479
+            }
1480
+        },
1449 1481
         "/admin/loginLog/delete": {
1450 1482
             "post": {
1451 1483
                 "security": [
@@ -1915,6 +1947,63 @@
1915 1947
                 }
1916 1948
             }
1917 1949
         },
1950
+        "/admin/oidc/auth": {
1951
+            "post": {
1952
+                "description": "OidcAuth",
1953
+                "consumes": [
1954
+                    "application/json"
1955
+                ],
1956
+                "produces": [
1957
+                    "application/json"
1958
+                ],
1959
+                "tags": [
1960
+                    "Oauth"
1961
+                ],
1962
+                "summary": "OidcAuth",
1963
+                "responses": {}
1964
+            }
1965
+        },
1966
+        "/admin/oidc/auth-query": {
1967
+            "get": {
1968
+                "description": "OidcAuthQuery",
1969
+                "consumes": [
1970
+                    "application/json"
1971
+                ],
1972
+                "produces": [
1973
+                    "application/json"
1974
+                ],
1975
+                "tags": [
1976
+                    "Oauth"
1977
+                ],
1978
+                "summary": "OidcAuthQuery",
1979
+                "responses": {
1980
+                    "200": {
1981
+                        "description": "OK",
1982
+                        "schema": {
1983
+                            "allOf": [
1984
+                                {
1985
+                                    "$ref": "#/definitions/response.Response"
1986
+                                },
1987
+                                {
1988
+                                    "type": "object",
1989
+                                    "properties": {
1990
+                                        "data": {
1991
+                                            "$ref": "#/definitions/admin.LoginPayload"
1992
+                                        }
1993
+                                    }
1994
+                                }
1995
+                            ]
1996
+                        }
1997
+                    },
1998
+                    "500": {
1999
+                        "description": "Internal Server Error",
2000
+                        "schema": {
2001
+                            "$ref": "#/definitions/response.Response"
2002
+                        }
2003
+                    }
2004
+                }
2005
+            }
2006
+        },
1918 2007
         "/admin/peer/create": {
1919 2008
             "post": {
1920 2009
                 "security": [
@@ -3157,11 +3246,17 @@
3157 3246
                 "id": {
3158 3247
                     "type": "integer"
3159 3248
                 },
3249
+                "issuer": {
3250
+                    "type": "string"
3251
+                },
3160 3252
                 "op": {
3161 3253
                     "type": "string"
3162 3254
                 },
3163 3255
                 "redirect_url": {
3164 3256
                     "type": "string"
3257
+                },
3258
+                "scopes": {
3259
+                    "type": "string"
3165 3260
                 }
3166 3261
             }
3167 3262
         },
@@ -3742,12 +3837,18 @@
3742 3837
                 "id": {
3743 3838
                     "type": "integer"
3744 3839
                 },
3840
+                "issuer": {
3841
+                    "type": "string"
3842
+                },
3745 3843
                 "op": {
3746 3844
                     "type": "string"
3747 3845
                 },
3748 3846
                 "redirect_url": {
3749 3847
                     "type": "string"
3750 3848
                 },
3849
+                "scopes": {
3850
+                    "type": "string"
3851
+                },
3751 3852
                 "updated_at": {
3752 3853
                     "type": "string"
3753 3854
                 }
@@ -3788,6 +3889,9 @@
3788 3889
                 "id": {
3789 3890
                     "type": "string"
3790 3891
                 },
3892
+                "last_online_ip": {
3893
+                    "type": "string"
3894
+                },
3791 3895
                 "last_online_time": {
3792 3896
                     "type": "integer"
3793 3897
                 },
@@ -3957,6 +4061,14 @@
3957 4061
                 }
3958 4062
             }
3959 4063
         },
4064
+        "response.ErrorResponse": {
4065
+            "type": "object",
4066
+            "properties": {
4067
+                "error": {
4068
+                    "type": "string"
4069
+                }
4070
+            }
4071
+        },
3960 4072
         "response.Response": {
3961 4073
             "type": "object",
3962 4074
             "properties": {

+ 71 - 0
docs/admin/admin_swagger.yaml

@@ -105,10 +105,14 @@ definitions:
105 105
         type: string
106 106
       id:
107 107
         type: integer
108
+      issuer:
109
+        type: string
108 110
       op:
109 111
         type: string
110 112
       redirect_url:
111 113
         type: string
114
+      scopes:
115
+        type: string
112 116
     required:
113 117
     - client_id
114 118
     - client_secret
@@ -500,10 +504,14 @@ definitions:
500 504
         type: string
501 505
       id:
502 506
         type: integer
507
+      issuer:
508
+        type: string
503 509
       op:
504 510
         type: string
505 511
       redirect_url:
506 512
         type: string
513
+      scopes:
514
+        type: string
507 515
       updated_at:
508 516
         type: string
509 517
     type: object
@@ -530,6 +538,8 @@ definitions:
530 538
         type: string
531 539
       id:
532 540
         type: string
541
+      last_online_ip:
542
+        type: string
533 543
       last_online_time:
534 544
         type: integer
535 545
       memory:
@@ -643,6 +653,11 @@ definitions:
643 653
       total:
644 654
         type: integer
645 655
     type: object
656
+  response.ErrorResponse:
657
+    properties:
658
+      error:
659
+        type: string
660
+    type: object
646 661
   response.Response:
647 662
     properties:
648 663
       code:
@@ -1510,6 +1525,27 @@ paths:
1510 1525
       summary: 登录
1511 1526
       tags:
1512 1527
       - 登录
1528
+  /admin/login-options:
1529
+    post:
1530
+      consumes:
1531
+      - application/json
1532
+      description: 登录选项
1533
+      produces:
1534
+      - application/json
1535
+      responses:
1536
+        "200":
1537
+          description: OK
1538
+          schema:
1539
+            items:
1540
+              type: string
1541
+            type: array
1542
+        "500":
1543
+          description: Internal Server Error
1544
+          schema:
1545
+            $ref: '#/definitions/response.ErrorResponse'
1546
+      summary: 登录选项
1547
+      tags:
1548
+      - 登录
1513 1549
   /admin/loginLog/delete:
1514 1550
     post:
1515 1551
       consumes:
@@ -1789,6 +1825,41 @@ paths:
1789 1825
       summary: Oauth编辑
1790 1826
       tags:
1791 1827
       - Oauth
1828
+  /admin/oidc/auth:
1829
+    post:
1830
+      consumes:
1831
+      - application/json
1832
+      description: OidcAuth
1833
+      produces:
1834
+      - application/json
1835
+      responses: {}
1836
+      summary: OidcAuth
1837
+      tags:
1838
+      - Oauth
1839
+  /admin/oidc/auth-query:
1840
+    get:
1841
+      consumes:
1842
+      - application/json
1843
+      description: OidcAuthQuery
1844
+      produces:
1845
+      - application/json
1846
+      responses:
1847
+        "200":
1848
+          description: OK
1849
+          schema:
1850
+            allOf:
1851
+            - $ref: '#/definitions/response.Response'
1852
+            - properties:
1853
+                data:
1854
+                  $ref: '#/definitions/admin.LoginPayload'
1855
+              type: object
1856
+        "500":
1857
+          description: Internal Server Error
1858
+          schema:
1859
+            $ref: '#/definitions/response.Response'
1860
+      summary: OidcAuthQuery
1861
+      tags:
1862
+      - Oauth
1792 1863
   /admin/peer/create:
1793 1864
     post:
1794 1865
       consumes:

+ 1 - 1
docs/api/api_docs.go

@@ -834,7 +834,7 @@ const docTemplateapi = `{
834 834
             }
835 835
         },
836 836
         "/login-options": {
837
-            "post": {
837
+            "get": {
838 838
                 "description": "登录选项",
839 839
                 "consumes": [
840 840
                     "application/json"

+ 1 - 1
docs/api/api_swagger.json

@@ -827,7 +827,7 @@
827 827
             }
828 828
         },
829 829
         "/login-options": {
830
-            "post": {
830
+            "get": {
831 831
                 "description": "登录选项",
832 832
                 "consumes": [
833 833
                     "application/json"

+ 1 - 1
docs/api/api_swagger.yaml

@@ -715,7 +715,7 @@ paths:
715 715
       tags:
716 716
       - 登录
717 717
   /login-options:
718
-    post:
718
+    get:
719 719
       consumes:
720 720
       - application/json
721 721
       description: 登录选项

+ 22 - 17
http/controller/admin/login.go

@@ -2,15 +2,16 @@ package admin
2 2
 
3 3
 import (
4 4
 	"Gwen/global"
5
+	"Gwen/http/controller/api"
5 6
 	"Gwen/http/request/admin"
7
+	apiReq "Gwen/http/request/api"
6 8
 	"Gwen/http/response"
7 9
 	adResp "Gwen/http/response/admin"
8
-	apiReq "Gwen/http/request/api"
9
-	"Gwen/http/controller/api"
10 10
 	"Gwen/model"
11 11
 	"Gwen/service"
12 12
 	"fmt"
13 13
 	"github.com/gin-gonic/gin"
14
+	"gorm.io/gorm"
14 15
 )
15 16
 
16 17
 type Login struct {
@@ -85,7 +86,6 @@ func (ct *Login) Logout(c *gin.Context) {
85 86
 	response.Success(c, nil)
86 87
 }
87 88
 
88
-
89 89
 // LoginOptions
90 90
 // @Tags 登录
91 91
 // @Summary 登录选项
@@ -95,13 +95,20 @@ func (ct *Login) Logout(c *gin.Context) {
95 95
 // @Success 200 {object} []string
96 96
 // @Failure 500 {object} response.ErrorResponse
97 97
 // @Router /admin/login-options [post]
98
-// 直接调用/api/login的LoginOptions方法
99 98
 func (ct *Login) LoginOptions(c *gin.Context) {
100
-	l := &api.Login{}
101
-    l.LoginOptions(c)
99
+	res := service.AllService.OauthService.List(1, 100, func(tx *gorm.DB) {
100
+		tx.Select("op").Order("id")
101
+	})
102
+	var ops []string
103
+	for _, v := range res.Oauths {
104
+		ops = append(ops, v.Op)
105
+	}
106
+	response.Success(c, gin.H{
107
+		"ops":      ops,
108
+		"register": global.Config.App.Register,
109
+	})
102 110
 }
103 111
 
104
-
105 112
 // OidcAuth
106 113
 // @Tags Oauth
107 114
 // @Summary OidcAuth
@@ -126,13 +133,13 @@ func (ct *Login) OidcAuth(c *gin.Context) {
126 133
 	}
127 134
 
128 135
 	service.AllService.OauthService.SetOauthCache(code, &service.OauthCacheItem{
129
-		Action: service.OauthActionTypeLogin,
130
-		Op:     	f.Op,
131
-		Id: 		f.Id,
136
+		Action:     service.OauthActionTypeLogin,
137
+		Op:         f.Op,
138
+		Id:         f.Id,
132 139
 		DeviceType: "webadmin",
133 140
 		// DeviceOs: ct.Platform(c),
134
-		DeviceOs: 	f.DeviceInfo.Os,
135
-		Uuid: 		f.Uuid,
141
+		DeviceOs: f.DeviceInfo.Os,
142
+		Uuid:     f.Uuid,
136 143
 	}, 5*60)
137 144
 
138 145
 	response.Success(c, gin.H{
@@ -141,8 +148,6 @@ func (ct *Login) OidcAuth(c *gin.Context) {
141 148
 	})
142 149
 }
143 150
 
144
-
145
-
146 151
 // OidcAuthQuery
147 152
 // @Tags Oauth
148 153
 // @Summary OidcAuthQuery
@@ -158,12 +163,12 @@ func (ct *Login) OidcAuthQuery(c *gin.Context) {
158 163
 	if ut == nil {
159 164
 		return
160 165
 	}
161
-	fmt.Println("u:", u)
162
-	fmt.Println("ut:", ut)
166
+	//fmt.Println("u:", u)
167
+	//fmt.Println("ut:", ut)
163 168
 	response.Success(c, &adResp.LoginPayload{
164 169
 		Token:      ut.Token,
165 170
 		Username:   u.Username,
166 171
 		RouteNames: service.AllService.UserService.RouteNames(u),
167 172
 		Nickname:   u.Nickname,
168 173
 	})
169
-}
174
+}

+ 1 - 1
http/controller/admin/oauth.go

@@ -102,7 +102,7 @@ func (o *Oauth) BindConfirm(c *gin.Context) {
102 102
 		return
103 103
 	}
104 104
 	u := service.AllService.UserService.CurUser(c)
105
-	err = service.AllService.OauthService.BindGithubUser(v.ThirdOpenId, v.ThirdOpenId, u.Id)
105
+	err = service.AllService.OauthService.BindOauthUser(v.Op, v.ThirdOpenId, v.ThirdName, u.Id)
106 106
 	if err != nil {
107 107
 		response.Fail(c, 101, response.TranslateMsg(c, "BindFail"))
108 108
 		return

+ 38 - 0
http/controller/admin/user.go

@@ -5,6 +5,7 @@ import (
5 5
 	"Gwen/http/request/admin"
6 6
 	"Gwen/http/response"
7 7
 	adResp "Gwen/http/response/admin"
8
+	"Gwen/model"
8 9
 	"Gwen/service"
9 10
 	"github.com/gin-gonic/gin"
10 11
 	"gorm.io/gorm"
@@ -327,3 +328,40 @@ func (ct *User) GroupUsers(c *gin.Context) {
327 328
 	}
328 329
 	response.Success(c, data)
329 330
 }
331
+
332
+// Register
333
+func (ct *User) Register(c *gin.Context) {
334
+	if !global.Config.App.Register {
335
+		response.Fail(c, 101, response.TranslateMsg(c, "RegisterClosed"))
336
+		return
337
+	}
338
+	f := &admin.RegisterForm{}
339
+	if err := c.ShouldBindJSON(f); err != nil {
340
+		response.Fail(c, 101, response.TranslateMsg(c, "ParamsError")+err.Error())
341
+		return
342
+	}
343
+	errList := global.Validator.ValidStruct(c, f)
344
+	if len(errList) > 0 {
345
+		response.Fail(c, 101, errList[0])
346
+		return
347
+	}
348
+	u := service.AllService.UserService.Register(f.Username, f.Password)
349
+	if u == nil || u.Id == 0 {
350
+		response.Fail(c, 101, response.TranslateMsg(c, "OperationFailed"))
351
+		return
352
+	}
353
+	// 注册成功后自动登录
354
+	ut := service.AllService.UserService.Login(u, &model.LoginLog{
355
+		UserId: u.Id,
356
+		Client: model.LoginLogClientWebAdmin,
357
+		Uuid:   "",
358
+		Ip:     c.ClientIP(),
359
+		Type:   model.LoginLogTypeAccount,
360
+	})
361
+	response.Success(c, &adResp.LoginPayload{
362
+		Token:      ut.Token,
363
+		Username:   u.Username,
364
+		RouteNames: service.AllService.UserService.RouteNames(u),
365
+		Nickname:   u.Nickname,
366
+	})
367
+}

+ 1 - 1
http/controller/api/login.go

@@ -81,7 +81,7 @@ func (l *Login) Login(c *gin.Context) {
81 81
 // @Produce  json
82 82
 // @Success 200 {object} []string
83 83
 // @Failure 500 {object} response.ErrorResponse
84
-// @Router /login-options [post]
84
+// @Router /login-options [get]
85 85
 func (l *Login) LoginOptions(c *gin.Context) {
86 86
 	oauthOks := []string{}
87 87
 	err, _ := service.AllService.OauthService.GetOauthConfig(model.OauthTypeGithub)

+ 79 - 178
http/controller/api/ouath.go

@@ -32,6 +32,7 @@ func (o *Oauth) OidcAuth(c *gin.Context) {
32 32
 		response.Error(c, response.TranslateMsg(c, "ParamsError")+err.Error())
33 33
 		return
34 34
 	}
35
+	//fmt.Println(f)
35 36
 	if f.Op != model.OauthTypeWebauth && f.Op != model.OauthTypeGoogle && f.Op != model.OauthTypeGithub && f.Op != model.OauthTypeOidc {
36 37
 		response.Error(c, response.TranslateMsg(c, "ParamsError"))
37 38
 		return
@@ -79,7 +80,7 @@ func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken)
79 80
 
80 81
 	// 如果 UserId 为 0,说明还在授权中
81 82
 	if v.UserId == 0 {
82
-		c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress"})
83
+		c.JSON(http.StatusOK, gin.H{"message": "Authorization in progress, please login and bind"})
83 84
 		return nil, nil
84 85
 	}
85 86
 
@@ -123,6 +124,9 @@ func (o *Oauth) OidcAuthQueryPre(c *gin.Context) (*model.User, *model.UserToken)
123 124
 // @Router /oidc/auth-query [get]
124 125
 func (o *Oauth) OidcAuthQuery(c *gin.Context) {
125 126
 	u, ut := o.OidcAuthQueryPre(c)
127
+	if u == nil || ut == nil {
128
+		return
129
+	}
126 130
 	c.JSON(http.StatusOK, apiResp.LoginRes{
127 131
 		AccessToken: ut.Token,
128 132
 		Type:        "access_token",
@@ -157,7 +161,10 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
157 161
 	ty := v.Op
158 162
 	ac := v.Action
159 163
 	var u *model.User
164
+	openid := ""
165
+	thirdName := ""
160 166
 	//fmt.Println("ty ac ", ty, ac)
167
+
161 168
 	if ty == model.OauthTypeGithub {
162 169
 		code := c.Query("code")
163 170
 		err, userData := service.AllService.OauthService.GithubCallback(code)
@@ -165,59 +172,8 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
165 172
 			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
166 173
 			return
167 174
 		}
168
-		if ac == service.OauthActionTypeBind {
169
-			//fmt.Println("bind", ty, userData)
170
-			utr := service.AllService.OauthService.UserThirdInfo(ty, strconv.Itoa(userData.Id))
171
-			if utr.UserId > 0 {
172
-				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser"))
173
-				return
174
-			}
175
-			//绑定
176
-			u = service.AllService.UserService.InfoById(v.UserId)
177
-			if u == nil {
178
-				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
179
-				return
180
-			}
181
-			//绑定github
182
-			err = service.AllService.OauthService.BindGithubUser(strconv.Itoa(userData.Id), userData.Login, v.UserId)
183
-			if err != nil {
184
-				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail"))
185
-				return
186
-			}
187
-			c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess"))
188
-			return
189
-		} else if ac == service.OauthActionTypeLogin {
190
-			//登录
191
-			if v.UserId != 0 {
192
-				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
193
-				return
194
-			}
195
-			u = service.AllService.UserService.InfoByGithubId(strconv.Itoa(userData.Id))
196
-			if u == nil {
197
-				oa := service.AllService.OauthService.InfoByOp(ty)
198
-				if !*oa.AutoRegister {
199
-					//c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定")
200
-					v.ThirdName = userData.Login
201
-					v.ThirdOpenId = strconv.Itoa(userData.Id)
202
-					url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey
203
-					c.Redirect(http.StatusFound, url)
204
-					return
205
-				}
206
-
207
-				//自动注册
208
-				u = service.AllService.UserService.RegisterByGithub(userData.Login, strconv.Itoa(userData.Id))
209
-				if u.Id == 0 {
210
-					c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed"))
211
-					return
212
-				}
213
-			}
214
-
215
-			// v.UserId = u.Id
216
-			// service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
217
-			// c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
218
-			// return
219
-		}
220
-
175
+		openid = strconv.Itoa(userData.Id)
176
+		thirdName = userData.Login
221 177
 	} else if ty == model.OauthTypeGoogle {
222 178
 		code := c.Query("code")
223 179
 		err, userData := service.AllService.OauthService.GoogleCallback(code)
@@ -225,60 +181,9 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
225 181
 			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
226 182
 			return
227 183
 		}
184
+		openid = userData.Email
228 185
 		//将空格替换成_
229
-		googleName := strings.Replace(userData.Name, " ", "_", -1)
230
-		if ac == service.OauthActionTypeBind {
231
-			//fmt.Println("bind", ty, userData)
232
-			utr := service.AllService.OauthService.UserThirdInfo(ty, userData.Email)
233
-			if utr.UserId > 0 {
234
-				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser"))
235
-				return
236
-			}
237
-			//绑定
238
-			u = service.AllService.UserService.InfoById(v.UserId)
239
-			if u == nil {
240
-				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
241
-				return
242
-			}
243
-			//绑定
244
-			err = service.AllService.OauthService.BindGoogleUser(userData.Email, googleName, v.UserId)
245
-			if err != nil {
246
-				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail"))
247
-				return
248
-			}
249
-			c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess"))
250
-			return
251
-		} else if ac == service.OauthActionTypeLogin {
252
-			if v.UserId != 0 {
253
-				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
254
-				return
255
-			}
256
-			u = service.AllService.UserService.InfoByGoogleEmail(userData.Email)
257
-			if u == nil {
258
-				oa := service.AllService.OauthService.InfoByOp(ty)
259
-				if !*oa.AutoRegister {
260
-					//c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定")
261
-
262
-					v.ThirdName = googleName
263
-					v.ThirdOpenId = userData.Email
264
-					url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey
265
-					c.Redirect(http.StatusFound, url)
266
-					return
267
-				}
268
-
269
-				//自动注册
270
-				u = service.AllService.UserService.RegisterByGoogle(googleName, userData.Email)
271
-				if u.Id == 0 {
272
-					c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed"))
273
-					return
274
-				}
275
-			}
276
-
277
-			// v.UserId = u.Id
278
-			// service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
279
-			// c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
280
-			// return
281
-		}
186
+		thirdName = strings.Replace(userData.Name, " ", "_", -1)
282 187
 	} else if ty == model.OauthTypeOidc {
283 188
 		code := c.Query("code")
284 189
 		err, userData := service.AllService.OauthService.OidcCallback(code)
@@ -286,85 +191,81 @@ func (o *Oauth) OauthCallback(c *gin.Context) {
286 191
 			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthFailed")+response.TranslateMsg(c, err.Error()))
287 192
 			return
288 193
 		}
289
-		//将空格替换成_
290
-		// OidcName := strings.Replace(userData.Name, " ", "_", -1)
291
-		if ac == service.OauthActionTypeBind {
292
-			//fmt.Println("bind", ty, userData)
293
-			utr := service.AllService.OauthService.UserThirdInfo(ty, userData.Sub)
294
-			if utr.UserId > 0 {
295
-				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser"))
296
-				return
297
-			}
298
-			//绑定
299
-			u = service.AllService.UserService.InfoById(v.UserId)
300
-			if u == nil {
301
-				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
302
-				return
303
-			}
304
-			//绑定, user preffered_username as username
305
-			err = service.AllService.OauthService.BindOidcUser(userData.Sub, userData.PreferredUsername, v.UserId)
306
-			if err != nil {
307
-				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail"))
308
-				return
309
-			}
310
-			c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess"))
194
+		openid = userData.Sub
195
+		thirdName = userData.PreferredUsername
196
+	} else {
197
+		c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ParamsError"))
198
+		return
199
+	}
200
+	if ac == service.OauthActionTypeBind {
201
+
202
+		//fmt.Println("bind", ty, userData)
203
+		utr := service.AllService.OauthService.UserThirdInfo(ty, openid)
204
+		if utr.UserId > 0 {
205
+			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBindOtherUser"))
311 206
 			return
312
-		} else if ac == service.OauthActionTypeLogin {
313
-			if v.UserId != 0 {
314
-				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
207
+		}
208
+		//绑定
209
+		u = service.AllService.UserService.InfoById(v.UserId)
210
+		if u == nil {
211
+			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ItemNotFound"))
212
+			return
213
+		}
214
+		//绑定
215
+		err := service.AllService.OauthService.BindOauthUser(ty, openid, thirdName, v.UserId)
216
+		if err != nil {
217
+			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "BindFail"))
218
+			return
219
+		}
220
+		c.String(http.StatusOK, response.TranslateMsg(c, "BindSuccess"))
221
+		return
222
+
223
+	} else if ac == service.OauthActionTypeLogin {
224
+		//登录
225
+		if v.UserId != 0 {
226
+			c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthHasBeenSuccess"))
227
+			return
228
+		}
229
+		u = service.AllService.UserService.InfoByGithubId(openid)
230
+		if u == nil {
231
+			oa := service.AllService.OauthService.InfoByOp(ty)
232
+			if !*oa.AutoRegister {
233
+				//c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定")
234
+				v.ThirdName = thirdName
235
+				v.ThirdOpenId = openid
236
+				url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey
237
+				c.Redirect(http.StatusFound, url)
315 238
 				return
316 239
 			}
317
-			u = service.AllService.UserService.InfoByOidcSub(userData.Sub)
318
-			if u == nil {
319
-				oa := service.AllService.OauthService.InfoByOp(ty)
320
-				if !*oa.AutoRegister {
321
-					//c.String(http.StatusInternalServerError, "还未绑定用户,请先绑定")
322
-
323
-					v.ThirdName = userData.PreferredUsername
324
-					v.ThirdOpenId = userData.Sub
325
-					v.ThirdEmail = userData.Email
326
-					url := global.Config.Rustdesk.ApiServer + "/_admin/#/oauth/bind/" + cacheKey
327
-					c.Redirect(http.StatusFound, url)
328
-					return
329
-				}
330 240
 
331
-				//自动注册
332
-				u = service.AllService.UserService.RegisterByOidc(userData.PreferredUsername, userData.Sub)
333
-				if u.Id == 0 {
334
-					c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed"))
335
-					return
336
-				}
241
+			//自动注册
242
+			u = service.AllService.UserService.RegisterByOauth(ty, thirdName, openid)
243
+			if u.Id == 0 {
244
+				c.String(http.StatusInternalServerError, response.TranslateMsg(c, "OauthRegisterFailed"))
245
+				return
337 246
 			}
338
-
339
-			// v.UserId = u.Id
340
-			// service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
341
-			// c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
342
-			// return
343 247
 		}
344
-	}
345
-	// 如果u为空,说明没有绑定用户
346
-	if u == nil {
347
-		c.String(http.StatusInternalServerError, response.TranslateMsg(c, "SystemError"))
248
+		v.UserId = u.Id
249
+		service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
250
+		// 如果是webadmin,登录成功后跳转到webadmin
251
+		if v.DeviceType == "webadmin" {
252
+			/*service.AllService.UserService.Login(u, &model.LoginLog{
253
+				UserId:   u.Id,
254
+				Client:   "webadmin",
255
+				Uuid:     "", //must be empty
256
+				Ip:       c.ClientIP(),
257
+				Type:     model.LoginLogTypeOauth,
258
+				Platform: v.DeviceOs,
259
+			})*/
260
+			url := global.Config.Rustdesk.ApiServer + "/_admin/#/"
261
+			c.Redirect(http.StatusFound, url)
262
+			return
263
+		}
264
+		c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
348 265
 		return
349
-	}
350
-	// 认证成功,设置缓存
351
-	v.UserId = u.Id
352
-	service.AllService.OauthService.SetOauthCache(cacheKey, v, 0)
353
-	// 如果是webadmin,登录成功后跳转到webadmin
354
-	if v.DeviceType == "webadmin" {
355
-		service.AllService.UserService.Login(u, &model.LoginLog{
356
-			UserId:   u.Id,
357
-			Client:   "webadmin",
358
-			Uuid:     "",//must be empty
359
-			Ip:       c.ClientIP(),
360
-			Type:     "account",
361
-			Platform: v.DeviceOs,
362
-		})
363
-		url := global.Config.Rustdesk.ApiServer + "/_admin/#/"
364
-		c.Redirect(http.StatusFound, url)
266
+	} else {
267
+		c.String(http.StatusInternalServerError, response.TranslateMsg(c, "ParamsError"))
365 268
 		return
366 269
 	}
367
-	c.String(http.StatusOK, response.TranslateMsg(c, "OauthSuccess"))
368
-	return
369 270
 
370 271
 }

+ 6 - 0
http/request/admin/user.go

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

+ 1 - 1
http/router/admin.go

@@ -17,7 +17,7 @@ func Init(g *gin.Engine) {
17 17
 
18 18
 	adg := g.Group("/api/admin")
19 19
 	LoginBind(adg)
20
-
20
+	adg.POST("/user/register", (&admin.User{}).Register)
21 21
 	adg.Use(middleware.AdminAuth())
22 22
 	//FileBind(adg)
23 23
 	UserBind(adg)

+ 6 - 0
model/loginLog.go

@@ -12,6 +12,12 @@ type LoginLog struct {
12 12
 	TimeModel
13 13
 }
14 14
 
15
+const (
16
+	LoginLogClientWebAdmin = "webadmin"
17
+	LoginLogClientWeb      = "webclient"
18
+	LoginLogClientApp      = "app"
19
+)
20
+
15 21
 const (
16 22
 	LoginLogTypeAccount = "account"
17 23
 	LoginLogTypeOauth   = "oauth"

+ 4 - 0
resources/i18n/en.toml

@@ -119,3 +119,7 @@ other = "Default Group"
119 119
 description = "Share group"
120 120
 one = "Share Group"
121 121
 other = "Share Group"
122
+[RegisterClosed]
123
+description = "Register closed."
124
+one = "Register closed."
125
+other = "Register closed."

+ 5 - 0
resources/i18n/ko.toml

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

+ 5 - 0
resources/i18n/ru.toml

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

+ 4 - 0
resources/i18n/zh_CN.toml

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

+ 22 - 22
service/oauth.go

@@ -15,9 +15,9 @@ import (
15 15
 	"net/http"
16 16
 	"net/url"
17 17
 	"strconv"
18
+	"strings"
18 19
 	"sync"
19 20
 	"time"
20
-	"strings"
21 21
 )
22 22
 
23 23
 // Define a struct to parse the .well-known/openid-configuration response
@@ -88,10 +88,10 @@ type GoogleUserdata struct {
88 88
 	VerifiedEmail bool   `json:"verified_email"`
89 89
 }
90 90
 type OidcUserdata struct {
91
-	Sub			  string `json:"sub"`
92
-	Email         string `json:"email"`
93
-	VerifiedEmail bool   `json:"email_verified"`
94
-	Name          string `json:"name"`
91
+	Sub               string `json:"sub"`
92
+	Email             string `json:"email"`
93
+	VerifiedEmail     bool   `json:"email_verified"`
94
+	Name              string `json:"name"`
95 95
 	PreferredUsername string `json:"preferred_username"`
96 96
 }
97 97
 
@@ -156,27 +156,27 @@ func (os *OauthService) BeginAuth(op string) (error error, code, url string) {
156 156
 
157 157
 // Method to fetch OIDC configuration dynamically
158 158
 func FetchOidcConfig(issuer string) (error, OidcEndpoint) {
159
-    configURL := strings.TrimSuffix(issuer, "/") + "/.well-known/openid-configuration"
159
+	configURL := strings.TrimSuffix(issuer, "/") + "/.well-known/openid-configuration"
160 160
 
161
-    // Get the HTTP client (with or without proxy based on configuration)
162
-    client := getHTTPClientWithProxy()
161
+	// Get the HTTP client (with or without proxy based on configuration)
162
+	client := getHTTPClientWithProxy()
163 163
 
164
-    resp, err := client.Get(configURL)
165
-    if err != nil {
166
-        return errors.New("failed to fetch OIDC configuration"), OidcEndpoint{}
167
-    }
168
-    defer resp.Body.Close()
164
+	resp, err := client.Get(configURL)
165
+	if err != nil {
166
+		return errors.New("failed to fetch OIDC configuration"), OidcEndpoint{}
167
+	}
168
+	defer resp.Body.Close()
169 169
 
170
-    if resp.StatusCode != http.StatusOK {
171
-        return errors.New("OIDC configuration not found, status code: %d"), OidcEndpoint{}
172
-    }
170
+	if resp.StatusCode != http.StatusOK {
171
+		return errors.New("OIDC configuration not found, status code: %d"), OidcEndpoint{}
172
+	}
173 173
 
174
-    var endpoint OidcEndpoint
175
-    if err := json.NewDecoder(resp.Body).Decode(&endpoint); err != nil {
176
-        return errors.New("failed to parse OIDC configuration"), OidcEndpoint{}
177
-    }
174
+	var endpoint OidcEndpoint
175
+	if err := json.NewDecoder(resp.Body).Decode(&endpoint); err != nil {
176
+		return errors.New("failed to parse OIDC configuration"), OidcEndpoint{}
177
+	}
178 178
 
179
-    return nil, endpoint
179
+	return nil, endpoint
180 180
 }
181 181
 
182 182
 // GetOauthConfig retrieves the OAuth2 configuration based on the provider type
@@ -253,6 +253,7 @@ func (os *OauthService) getOidcConfig() (error, *oauth2.Config) {
253 253
 }
254 254
 
255 255
 func getHTTPClientWithProxy() *http.Client {
256
+	//todo add timeout
256 257
 	if global.Config.Proxy.Enable {
257 258
 		if global.Config.Proxy.Host == "" {
258 259
 			global.Logger.Warn("Proxy is enabled but proxy host is empty.")
@@ -446,7 +447,6 @@ func (os *OauthService) DeleteUserByUserId(userid uint) error {
446 447
 	return global.DB.Where("user_id = ?", userid).Delete(&model.UserThird{}).Error
447 448
 }
448 449
 
449
-
450 450
 // InfoById 根据id取用户信息
451 451
 func (os *OauthService) InfoById(id uint) *model.Oauth {
452 452
 	u := &model.Oauth{}

+ 39 - 11
service/user.go

@@ -151,15 +151,34 @@ func (us *UserService) Logout(u *model.User, token string) error {
151 151
 
152 152
 // Delete 删除用户和oauth信息
153 153
 func (us *UserService) Delete(u *model.User) error {
154
-    // 删除用户
155
-    if err := global.DB.Delete(u).Error; err != nil {
156
-        return err
157
-    }
158
-    // 删除关联的 OAuth 信息
159
-    if err := AllService.OauthService.DeleteUserByUserId(u.Id); err != nil {
160
-        return err
161
-    }
162
-    return nil
154
+	tx := global.DB.Begin()
155
+	// 删除用户
156
+	if err := tx.Delete(u).Error; err != nil {
157
+		tx.Rollback()
158
+		return err
159
+	}
160
+	// 删除关联的 OAuth 信息
161
+	if err := tx.Where("user_id = ?", u.Id).Delete(&model.UserThird{}).Error; err != nil {
162
+		tx.Rollback()
163
+		return err
164
+	}
165
+	//  删除关联的ab
166
+	if err := tx.Where("user_id = ?", u.Id).Delete(&model.AddressBook{}).Error; err != nil {
167
+		tx.Rollback()
168
+		return err
169
+	}
170
+	//  删除关联的abc
171
+	if err := tx.Where("user_id = ?", u.Id).Delete(&model.AddressBookCollection{}).Error; err != nil {
172
+		tx.Rollback()
173
+		return err
174
+	}
175
+	//  删除关联的abcr
176
+	if err := tx.Where("user_id = ?", u.Id).Delete(&model.AddressBookCollectionRule{}).Error; err != nil {
177
+		tx.Rollback()
178
+		return err
179
+	}
180
+	tx.Commit()
181
+	return nil
163 182
 }
164 183
 
165 184
 // Update 更新
@@ -262,14 +281,14 @@ func (us *UserService) RegisterByOauth(thirdType, thirdName, uid string) *model.
262 281
 		Username: username,
263 282
 		GroupId:  1,
264 283
 	}
265
-	global.DB.Create(u)
284
+	tx.Create(u)
266 285
 	if u.Id == 0 {
267 286
 		tx.Rollback()
268 287
 		return u
269 288
 	}
270 289
 
271 290
 	ut.UserId = u.Id
272
-	global.DB.Create(ut)
291
+	tx.Create(ut)
273 292
 
274 293
 	tx.Commit()
275 294
 	return u
@@ -328,3 +347,12 @@ func (us *UserService) IsPasswordEmptyByUser(u *model.User) bool {
328 347
 	return us.IsPasswordEmptyById(u.Id)
329 348
 }
330 349
 
350
+func (us *UserService) Register(username string, password string) *model.User {
351
+	u := &model.User{
352
+		Username: username,
353
+		Password: us.EncryptPassword(password),
354
+		GroupId:  1,
355
+	}
356
+	global.DB.Create(u)
357
+	return u
358
+}