diff --git a/api/dms/service/v1/configuration.go b/api/dms/service/v1/configuration.go index f2c4b184..c503edcd 100644 --- a/api/dms/service/v1/configuration.go +++ b/api/dms/service/v1/configuration.go @@ -11,6 +11,7 @@ type GetOauth2ConfigurationResData struct { ServerAuthUrl string `json:"server_auth_url"` ServerTokenUrl string `json:"server_token_url"` ServerUserIdUrl string `json:"server_user_id_url"` + ServerLogoutUrl string `json:"server_logout_url"` Scopes []string `json:"scopes"` AccessTokenTag string `json:"access_token_tag"` UserIdTag string `json:"user_id_tag"` @@ -32,20 +33,22 @@ type Oauth2ConfigurationReq struct { Oauth2Configuration Oauth2Configuration `json:"oauth2" validate:"required"` } type Oauth2Configuration struct { - EnableOauth2 *bool `json:"enable_oauth2"` - SkipCheckState *bool `json:"skip_check_state"` - AutoCreateUser *bool `json:"auto_create_user"` - ClientID *string `json:"client_id"` - ClientKey *string `json:"client_key"` - ClientHost *string `json:"client_host"` - ServerAuthUrl *string `json:"server_auth_url"` - ServerTokenUrl *string `json:"server_token_url"` - ServerUserIdUrl *string `json:"server_user_id_url"` - Scopes *[]string `json:"scopes"` - AccessTokenTag *string `json:"access_token_tag"` - UserIdTag *string `json:"user_id_tag"` - UserEmailTag *string `json:"user_email_tag"` - UserWeChatTag *string `json:"user_wechat_tag"` + EnableOauth2 *bool `json:"enable_oauth2"` + SkipCheckState *bool `json:"skip_check_state"` + AutoCreateUser *bool `json:"auto_create_user"` + AutoCreateUserPWD *string `json:"auto_create_user_pwd"` + ClientID *string `json:"client_id"` + ClientKey *string `json:"client_key"` + ClientHost *string `json:"client_host"` + ServerAuthUrl *string `json:"server_auth_url"` + ServerTokenUrl *string `json:"server_token_url"` + ServerUserIdUrl *string `json:"server_user_id_url"` + ServerLogoutUrl *string `json:"server_logout_url"` + Scopes *[]string `json:"scopes"` + AccessTokenTag *string `json:"access_token_tag"` + UserIdTag *string `json:"user_id_tag"` + UserEmailTag *string `json:"user_email_tag"` + UserWeChatTag *string `json:"user_wechat_tag"` // Maximum: 28 LoginTip *string `json:"login_tip" validate:"max=28"` } @@ -68,6 +71,7 @@ type BindOauth2UserReq struct { UserName string `json:"user_name" form:"user_name" validate:"required"` Pwd string `json:"pwd" form:"pwd" validate:"required"` Oauth2Token string `json:"oauth2_token" form:"oauth2_token" validate:"required"` + IdToken string `json:"id_token" form:"id_token"` } // swagger:model BindOauth2UserReply diff --git a/api/dms/service/v1/session.go b/api/dms/service/v1/session.go index 6c932f32..dd3781aa 100644 --- a/api/dms/service/v1/session.go +++ b/api/dms/service/v1/session.go @@ -29,6 +29,18 @@ type AddSessionReply struct { base.GenericResp } +// swagger:model DelSessionReply +type DelSessionReply struct { + // Del session reply + Data struct { + // Session token + Location string `json:"location"` + } `json:"data"` + + // Generic reply + base.GenericResp +} + // swagger:parameters GetUserBySession type GetUserBySessionReq struct { UserUid string `json:"user_uid" validate:"required"` diff --git a/api/swagger.json b/api/swagger.json index c98c9184..89d62249 100644 --- a/api/swagger.json +++ b/api/swagger.json @@ -3969,9 +3969,9 @@ "operationId": "DelSession", "responses": { "200": { - "description": "GenericResp", + "description": "DelSessionReply", "schema": { - "$ref": "#/definitions/GenericResp" + "$ref": "#/definitions/DelSessionReply" } }, "default": { @@ -6019,6 +6019,35 @@ }, "x-go-package": "github.com/actiontech/dms/api/dms/service/v1" }, + "DelSessionReply": { + "type": "object", + "properties": { + "code": { + "description": "code", + "type": "integer", + "format": "int64", + "x-go-name": "Code" + }, + "data": { + "description": "Del session reply", + "type": "object", + "properties": { + "location": { + "description": "Session token", + "type": "string", + "x-go-name": "Location" + } + }, + "x-go-name": "Data" + }, + "message": { + "description": "message", + "type": "string", + "x-go-name": "Message" + } + }, + "x-go-package": "github.com/actiontech/dms/api/dms/service/v1" + }, "FeishuConfigurationResData": { "type": "object", "properties": { @@ -6520,6 +6549,10 @@ "type": "string", "x-go-name": "ServerAuthUrl" }, + "server_logout_url": { + "type": "string", + "x-go-name": "ServerLogoutUrl" + }, "server_token_url": { "type": "string", "x-go-name": "ServerTokenUrl" @@ -8856,6 +8889,10 @@ "type": "boolean", "x-go-name": "AutoCreateUser" }, + "auto_create_user_pwd": { + "type": "string", + "x-go-name": "AutoCreateUserPWD" + }, "client_host": { "type": "string", "x-go-name": "ClientHost" @@ -8888,6 +8925,10 @@ "type": "string", "x-go-name": "ServerAuthUrl" }, + "server_logout_url": { + "type": "string", + "x-go-name": "ServerLogoutUrl" + }, "server_token_url": { "type": "string", "x-go-name": "ServerTokenUrl" diff --git a/api/swagger.yaml b/api/swagger.yaml index 1a14e01e..a2939214 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -1121,6 +1121,28 @@ definitions: x-go-name: DBServiceUid type: object x-go-package: github.com/actiontech/dms/api/dms/service/v1 + DelSessionReply: + properties: + code: + description: code + format: int64 + type: integer + x-go-name: Code + data: + description: Del session reply + properties: + location: + description: Session token + type: string + x-go-name: Location + type: object + x-go-name: Data + message: + description: message + type: string + x-go-name: Message + type: object + x-go-package: github.com/actiontech/dms/api/dms/service/v1 FeishuConfigurationResData: properties: app_id: @@ -1502,6 +1524,9 @@ definitions: server_auth_url: type: string x-go-name: ServerAuthUrl + server_logout_url: + type: string + x-go-name: ServerLogoutUrl server_token_url: type: string x-go-name: ServerTokenUrl @@ -3406,6 +3431,9 @@ definitions: auto_create_user: type: boolean x-go-name: AutoCreateUser + auto_create_user_pwd: + type: string + x-go-name: AutoCreateUserPWD client_host: type: string x-go-name: ClientHost @@ -3430,6 +3458,9 @@ definitions: server_auth_url: type: string x-go-name: ServerAuthUrl + server_logout_url: + type: string + x-go-name: ServerLogoutUrl server_token_url: type: string x-go-name: ServerTokenUrl @@ -7391,9 +7422,9 @@ paths: operationId: DelSession responses: "200": - description: GenericResp + description: DelSessionReply schema: - $ref: '#/definitions/GenericResp' + $ref: '#/definitions/DelSessionReply' default: description: GenericResp schema: diff --git a/internal/apiserver/service/dms_controller.go b/internal/apiserver/service/dms_controller.go index 95542851..a85ac8a5 100644 --- a/internal/apiserver/service/dms_controller.go +++ b/internal/apiserver/service/dms_controller.go @@ -1,7 +1,9 @@ package service import ( + "bytes" "context" + "encoding/json" "errors" "fmt" "io" @@ -566,9 +568,18 @@ func (a *DMSController) AddSession(c echo.Context) error { // del a session. // // responses: -// 200: body:GenericResp +// 200: body:DelSessionReply // default: body:GenericResp func (a *DMSController) DelSession(c echo.Context) error { + uid, err := jwt.GetUserUidStrFromContext(c) + if err != nil { + return NewErrResp(c, err, apiError.BadRequestErr) + } + redirectUri, err := a.DMS.Oauth2ConfigurationUsecase.Logout(c.Request().Context(), uid) + if err != nil { + return NewErrResp(c, err, apiError.DMSServiceErr) + } + cookie, err := c.Cookie(constant.DMSToken) if err != nil { return NewErrResp(c, err, apiError.DMSServiceErr) @@ -577,7 +588,18 @@ func (a *DMSController) DelSession(c echo.Context) error { cookie.Path = "/" c.SetCookie(cookie) a.CloudbeaverService.Logout(cookie.Value) - return NewOkResp(c) + + reply := &aV1.DelSessionReply{Data: struct { + Location string `json:"location"` + }{Location: redirectUri}} + buf := &bytes.Buffer{} + enc := json.NewEncoder(buf) + enc.SetEscapeHTML(false) // 避免将location中的 & 编码为 \u0026 + if err = enc.Encode(reply); err != nil { + return NewErrResp(c, err, apiError.APIServerErr) + } + + return c.JSONBlob(http.StatusOK, buf.Bytes()) } // swagger:route GET /v1/dms/sessions/user Session GetUserBySession diff --git a/internal/apiserver/service/router.go b/internal/apiserver/service/router.go index 6266c548..f37f8c76 100644 --- a/internal/apiserver/service/router.go +++ b/internal/apiserver/service/router.go @@ -5,6 +5,7 @@ import ( "compress/gzip" "fmt" "io" + "net/http" "strings" dmsMiddleware "github.com/actiontech/dms/internal/apiserver/middleware" @@ -305,7 +306,7 @@ func (s *APIServer) installMiddleware() error { s.echo.Use(echojwt.WithConfig(echojwt.Config{ Skipper: middleware.Skipper(func(c echo.Context) bool { logger := log.NewHelper(log.With(pkgLog.NewKLogWrapper(s.logger), "middleware", "jwt")) - if strings.HasSuffix(c.Request().RequestURI, dmsV1.SessionRouterGroup) || + if strings.HasSuffix(c.Request().RequestURI, dmsV1.SessionRouterGroup) && c.Request().Method != http.MethodDelete || strings.HasPrefix(c.Request().RequestURI, "/v1/dms/oauth2" /* TODO 使用统一方法skip */) || strings.HasPrefix(c.Request().RequestURI, "/v1/dms/personalization/logo") || strings.HasPrefix(c.Request().RequestURI, "/v1/dms/configurations/license" /* TODO 使用统一方法skip */) || diff --git a/internal/dms/biz/oauth2_configuration.go b/internal/dms/biz/oauth2_configuration.go index 009e7500..7bab935d 100644 --- a/internal/dms/biz/oauth2_configuration.go +++ b/internal/dms/biz/oauth2_configuration.go @@ -15,23 +15,26 @@ import ( type Oauth2Configuration struct { Base - UID string - EnableOauth2 bool - SkipCheckState bool - AutoCreateUser bool - ClientID string - ClientKey string - ClientSecret string - ClientHost string - ServerAuthUrl string - ServerTokenUrl string - ServerUserIdUrl string - Scopes []string - AccessTokenTag string - UserIdTag string - UserEmailTag string - UserWeChatTag string - LoginTip string + UID string + EnableOauth2 bool + SkipCheckState bool + AutoCreateUser bool + AutoCreateUserPWD string + AutoCreateUserSecret string + ClientID string + ClientKey string + ClientSecret string + ClientHost string + ServerAuthUrl string + ServerTokenUrl string + ServerUserIdUrl string + ServerLogoutUrl string + Scopes []string + AccessTokenTag string + UserIdTag string + UserEmailTag string + UserWeChatTag string + LoginTip string } func initOauth2Configuration() (*Oauth2Configuration, error) { //nolint diff --git a/internal/dms/biz/oauth2_configuration_ce.go b/internal/dms/biz/oauth2_configuration_ce.go index 3dc7d0a6..8f758790 100644 --- a/internal/dms/biz/oauth2_configuration_ce.go +++ b/internal/dms/biz/oauth2_configuration_ce.go @@ -9,7 +9,7 @@ import ( var errNotSupportOauth2 = errors.New("oauth2 related functions are enterprise version functions") -func (d *Oauth2ConfigurationUsecase) UpdateOauth2Configuration(ctx context.Context, enableOauth2, skipCheckState, autoCreateUser *bool, clientID, clientKey, clientHost, serverAuthUrl, serverTokenUrl, serverUserIdUrl, +func (d *Oauth2ConfigurationUsecase) UpdateOauth2Configuration(ctx context.Context, enableOauth2, skipCheckState, autoCreateUser *bool, autoCreateUserPWD, clientID, clientKey, clientHost, serverAuthUrl, serverTokenUrl, serverUserIdUrl, serverLogoutUrl, accessTokenTag, userIdTag, userWechatTag, userEmailTag, loginTip *string, scopes *[]string) error { return errNotSupportOauth2 @@ -27,6 +27,10 @@ func (d *Oauth2ConfigurationUsecase) GenerateCallbackUri(ctx context.Context, st return "", "", errNotSupportOauth2 } -func (d *Oauth2ConfigurationUsecase) BindOauth2User(ctx context.Context, oauth2Token, userName, password string) (token string, err error) { +func (d *Oauth2ConfigurationUsecase) BindOauth2User(ctx context.Context, oauth2Token, idToken, userName, password string) (token string, err error) { return "", errNotSupportOauth2 } + +func (d *Oauth2ConfigurationUsecase) Logout(ctx context.Context, uid string) (string, error) { + return "", nil +} diff --git a/internal/dms/biz/user.go b/internal/dms/biz/user.go index 24c4c96d..b2e2e7aa 100644 --- a/internal/dms/biz/user.go +++ b/internal/dms/biz/user.go @@ -76,6 +76,7 @@ type User struct { Password string ThirdPartyUserID string ThirdPartyUserInfo string + ThirdPartyIdToken string Email string Phone string WxID string @@ -144,6 +145,7 @@ func newUser(args *CreateUserArgs) (*User, error) { UserAuthenticationType: args.UserAuthenticationType, ThirdPartyUserID: args.ThirdPartyUserID, ThirdPartyUserInfo: args.ThirdPartyUserInfo, + ThirdPartyIdToken: args.ThirdPartyIdToken, Stat: UserStatOK, }, nil } @@ -422,6 +424,7 @@ type CreateUserArgs struct { Password string ThirdPartyUserID string ThirdPartyUserInfo string + ThirdPartyIdToken string Email string Phone string WxID string diff --git a/internal/dms/service/configuration.go b/internal/dms/service/configuration.go index 690b6b58..ca6c6da0 100644 --- a/internal/dms/service/configuration.go +++ b/internal/dms/service/configuration.go @@ -39,6 +39,7 @@ func (d *DMSService) GetOauth2Configuration(ctx context.Context) (reply *dmsV1.G ServerAuthUrl: oauth2C.ServerAuthUrl, ServerTokenUrl: oauth2C.ServerTokenUrl, ServerUserIdUrl: oauth2C.ServerUserIdUrl, + ServerLogoutUrl: oauth2C.ServerLogoutUrl, Scopes: oauth2C.Scopes, AccessTokenTag: oauth2C.AccessTokenTag, UserIdTag: oauth2C.UserIdTag, @@ -84,12 +85,14 @@ func (d *DMSService) UpdateOauth2Configuration(ctx context.Context, req *dmsV1.O oauth2Configuration.EnableOauth2, oauth2Configuration.SkipCheckState, oauth2Configuration.AutoCreateUser, + oauth2Configuration.AutoCreateUserPWD, oauth2Configuration.ClientID, oauth2Configuration.ClientKey, oauth2Configuration.ClientHost, oauth2Configuration.ServerAuthUrl, oauth2Configuration.ServerTokenUrl, oauth2Configuration.ServerUserIdUrl, + oauth2Configuration.ServerLogoutUrl, oauth2Configuration.AccessTokenTag, oauth2Configuration.UserIdTag, oauth2Configuration.UserWeChatTag, @@ -132,7 +135,7 @@ func (d *DMSService) BindOauth2User(ctx context.Context, bindOauth2User *dmsV1.B d.log.Infof("BindOauth2User;error=%v", err) }() - token, err := d.Oauth2ConfigurationUsecase.BindOauth2User(ctx, bindOauth2User.Oauth2Token, bindOauth2User.UserName, bindOauth2User.Pwd) + token, err := d.Oauth2ConfigurationUsecase.BindOauth2User(ctx, bindOauth2User.Oauth2Token, bindOauth2User.IdToken, bindOauth2User.UserName, bindOauth2User.Pwd) if err != nil { return nil, err } diff --git a/internal/dms/storage/convert.go b/internal/dms/storage/convert.go index 1925a2bf..f5fd18c3 100644 --- a/internal/dms/storage/convert.go +++ b/internal/dms/storage/convert.go @@ -157,6 +157,7 @@ func convertBizUser(u *biz.User) (*model.User, error) { Name: u.Name, ThirdPartyUserID: u.ThirdPartyUserID, ThirdPartyUserInfo: u.ThirdPartyUserInfo, + ThirdPartyIdToken: u.ThirdPartyIdToken, Password: encrypted, Email: u.Email, Phone: u.Phone, @@ -232,6 +233,7 @@ func convertModelUser(u *model.User) (*biz.User, error) { UID: u.UID, ThirdPartyUserID: u.ThirdPartyUserID, ThirdPartyUserInfo: u.ThirdPartyUserInfo, + ThirdPartyIdToken: u.ThirdPartyIdToken, Name: u.Name, Email: u.Email, Phone: u.Phone, @@ -596,27 +598,35 @@ func convertBizOauth2Configuration(b *biz.Oauth2Configuration) (*model.Oauth2Con if err != nil { return nil, err } + pwd, err := pkgAes.AesEncrypt(b.AutoCreateUserPWD) + if err != nil { + return nil, err + } b.ClientSecret = data + b.AutoCreateUserSecret = pwd return &model.Oauth2Configuration{ Model: model.Model{ UID: b.UID, }, - EnableOauth2: b.EnableOauth2, - SkipCheckState: b.SkipCheckState, - AutoCreateUser: b.AutoCreateUser, - ClientID: b.ClientID, - ClientKey: b.ClientKey, - ClientSecret: b.ClientSecret, - ClientHost: b.ClientHost, - ServerAuthUrl: b.ServerAuthUrl, - ServerTokenUrl: b.ServerTokenUrl, - ServerUserIdUrl: b.ServerUserIdUrl, - Scopes: strings.Join(b.Scopes, ","), - AccessTokenTag: b.AccessTokenTag, - UserIdTag: b.UserIdTag, - LoginTip: b.LoginTip, - UserWeChatTag: b.UserWeChatTag, - UserEmailTag: b.UserEmailTag, + EnableOauth2: b.EnableOauth2, + SkipCheckState: b.SkipCheckState, + AutoCreateUser: b.AutoCreateUser, + AutoCreateUserPWD: b.AutoCreateUserPWD, + AutoCreateUserSecret: b.AutoCreateUserSecret, + ClientID: b.ClientID, + ClientKey: b.ClientKey, + ClientSecret: b.ClientSecret, + ClientHost: b.ClientHost, + ServerAuthUrl: b.ServerAuthUrl, + ServerTokenUrl: b.ServerTokenUrl, + ServerUserIdUrl: b.ServerUserIdUrl, + ServerLogoutUrl: b.ServerLogoutUrl, + Scopes: strings.Join(b.Scopes, ","), + AccessTokenTag: b.AccessTokenTag, + UserIdTag: b.UserIdTag, + LoginTip: b.LoginTip, + UserWeChatTag: b.UserWeChatTag, + UserEmailTag: b.UserEmailTag, }, nil } @@ -629,25 +639,36 @@ func convertModelOauth2Configuration(m *model.Oauth2Configuration) (*biz.Oauth2C m.ClientKey = data } } + if m.AutoCreateUserPWD == "" { + data, err := pkgAes.AesDecrypt(m.AutoCreateUserSecret) + if err != nil { + return nil, err + } else { + m.AutoCreateUserPWD = data + } + } p := &biz.Oauth2Configuration{ - Base: convertBase(m.Model), - UID: m.UID, - EnableOauth2: m.EnableOauth2, - SkipCheckState: m.SkipCheckState, - AutoCreateUser: m.AutoCreateUser, - ClientID: m.ClientID, - ClientKey: m.ClientKey, - ClientSecret: m.ClientSecret, - ClientHost: m.ClientHost, - ServerAuthUrl: m.ServerAuthUrl, - ServerTokenUrl: m.ServerTokenUrl, - ServerUserIdUrl: m.ServerUserIdUrl, - Scopes: strings.Split(m.Scopes, ","), - AccessTokenTag: m.AccessTokenTag, - UserIdTag: m.UserIdTag, - LoginTip: m.LoginTip, - UserWeChatTag: m.UserWeChatTag, - UserEmailTag: m.UserEmailTag, + Base: convertBase(m.Model), + UID: m.UID, + EnableOauth2: m.EnableOauth2, + SkipCheckState: m.SkipCheckState, + AutoCreateUser: m.AutoCreateUser, + AutoCreateUserPWD: m.AutoCreateUserPWD, + AutoCreateUserSecret: m.AutoCreateUserSecret, + ClientID: m.ClientID, + ClientKey: m.ClientKey, + ClientSecret: m.ClientSecret, + ClientHost: m.ClientHost, + ServerAuthUrl: m.ServerAuthUrl, + ServerTokenUrl: m.ServerTokenUrl, + ServerUserIdUrl: m.ServerUserIdUrl, + ServerLogoutUrl: m.ServerLogoutUrl, + Scopes: strings.Split(m.Scopes, ","), + AccessTokenTag: m.AccessTokenTag, + UserIdTag: m.UserIdTag, + LoginTip: m.LoginTip, + UserWeChatTag: m.UserWeChatTag, + UserEmailTag: m.UserEmailTag, } return p, nil } diff --git a/internal/dms/storage/model/model.go b/internal/dms/storage/model/model.go index 5d515efd..9bf3ab37 100644 --- a/internal/dms/storage/model/model.go +++ b/internal/dms/storage/model/model.go @@ -112,6 +112,7 @@ type User struct { Name string `json:"name" gorm:"size:200;column:name"` ThirdPartyUserID string `json:"third_party_user_id" gorm:"size:255;column:third_party_user_id"` // used to retrieve sqle user based on third-party user ID ThirdPartyUserInfo string `json:"third_party_user_info" gorm:"type:text;column:third_party_user_info"` // used to save original third-party user information + ThirdPartyIdToken string `json:"third_party_id_token" gorm:"type:text;column:third_party_id_token"` // used to call OIDC Logout Email string `json:"email" gorm:"size:255;column:email"` Phone string `json:"phone" gorm:"size:255;column:phone"` WeChatID string `json:"wechat_id" gorm:"size:255;column:wechat_id"` @@ -242,22 +243,25 @@ type Plugin struct { // Oauth2Configuration store oauth2 server configuration. type Oauth2Configuration struct { Model - EnableOauth2 bool `json:"enable_oauth2" gorm:"column:enable_oauth2"` - SkipCheckState bool `json:"skip_check_state" gorm:"column:skip_check_state"` - AutoCreateUser bool `json:"auto_create_user" gorm:"auto_create_user"` - ClientID string `json:"client_id" gorm:"size:255;column:client_id"` - ClientKey string `json:"-" gorm:"-"` - ClientSecret string `json:"client_secret" gorm:"size:255;client_secret"` - ClientHost string `json:"client_host" gorm:"size:255;column:client_host"` - ServerAuthUrl string `json:"server_auth_url" gorm:"size:255;column:server_auth_url"` - ServerTokenUrl string `json:"server_token_url" gorm:"size:255;column:server_token_url"` - ServerUserIdUrl string `json:"server_user_id_url" gorm:"size:255;column:server_user_id_url"` - Scopes string `json:"scopes" gorm:"size:255;column:scopes"` - AccessTokenTag string `json:"access_token_tag" gorm:"size:255;column:access_token_tag"` - UserIdTag string `json:"user_id_tag" gorm:"size:255;column:user_id_tag"` - UserWeChatTag string `json:"user_wechat_tag" gorm:"size:255;column:user_wechat_tag"` - UserEmailTag string `json:"user_email_tag" gorm:"size:255;column:user_email_tag"` - LoginTip string `json:"login_tip" gorm:"size:255;column:login_tip; default:'使用第三方账户登录'"` + EnableOauth2 bool `json:"enable_oauth2" gorm:"column:enable_oauth2"` + SkipCheckState bool `json:"skip_check_state" gorm:"column:skip_check_state"` + AutoCreateUser bool `json:"auto_create_user" gorm:"auto_create_user"` + AutoCreateUserPWD string `json:"-" gorm:"-"` + AutoCreateUserSecret string `json:"auto_create_user_pwd" gorm:"size:255;column:auto_create_user_pwd"` + ClientID string `json:"client_id" gorm:"size:255;column:client_id"` + ClientKey string `json:"-" gorm:"-"` + ClientSecret string `json:"client_secret" gorm:"size:255;client_secret"` + ClientHost string `json:"client_host" gorm:"size:255;column:client_host"` + ServerAuthUrl string `json:"server_auth_url" gorm:"size:255;column:server_auth_url"` + ServerTokenUrl string `json:"server_token_url" gorm:"size:255;column:server_token_url"` + ServerUserIdUrl string `json:"server_user_id_url" gorm:"size:255;column:server_user_id_url"` + ServerLogoutUrl string `json:"server_logout_url" gorm:"size:255;column:server_logout_url"` + Scopes string `json:"scopes" gorm:"size:255;column:scopes"` + AccessTokenTag string `json:"access_token_tag" gorm:"size:255;column:access_token_tag"` + UserIdTag string `json:"user_id_tag" gorm:"size:255;column:user_id_tag"` + UserWeChatTag string `json:"user_wechat_tag" gorm:"size:255;column:user_wechat_tag"` + UserEmailTag string `json:"user_email_tag" gorm:"size:255;column:user_email_tag"` + LoginTip string `json:"login_tip" gorm:"size:255;column:login_tip; default:'使用第三方账户登录'"` } // LDAPConfiguration store ldap server configuration.