From 02c06bc93c44e2381c72295742b25c48ba790e92 Mon Sep 17 00:00:00 2001 From: Steve0x2a Date: Sat, 22 Jan 2022 19:36:44 +0800 Subject: [PATCH] feat: add baidu support as idp (#438) * feat: add baidu support as idp Signed-off-by: Steve0x2a * fix: add license Signed-off-by: Steve0x2a --- idp/baidu.go | 115 +++++++++++++++++++++++++++++++ idp/provider.go | 2 + object/user.go | 1 + web/src/Setting.js | 1 + web/src/auth/BaiduLoginButton.js | 32 +++++++++ web/src/auth/LoginPage.js | 3 + web/src/auth/Provider.js | 6 ++ 7 files changed, 160 insertions(+) create mode 100644 idp/baidu.go create mode 100644 web/src/auth/BaiduLoginButton.js diff --git a/idp/baidu.go b/idp/baidu.go new file mode 100644 index 00000000..5bab691a --- /dev/null +++ b/idp/baidu.go @@ -0,0 +1,115 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package idp + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + + "golang.org/x/oauth2" +) + +type BaiduIdProvider struct { + Client *http.Client + Config *oauth2.Config +} + +func NewBaiduIdProvider(clientId string, clientSecret string, redirectUrl string) *BaiduIdProvider { + idp := &BaiduIdProvider{} + + config := idp.getConfig() + config.ClientID = clientId + config.ClientSecret = clientSecret + config.RedirectURL = redirectUrl + idp.Config = config + + return idp +} + +func (idp *BaiduIdProvider) SetHttpClient(client *http.Client) { + idp.Client = client +} + +func (idp *BaiduIdProvider) getConfig() *oauth2.Config { + var endpoint = oauth2.Endpoint{ + AuthURL: "https://openapi.baidu.com/oauth/2.0/authorize", + TokenURL: "https://openapi.baidu.com/oauth/2.0/token", + } + + var config = &oauth2.Config{ + Scopes: []string{"email"}, + Endpoint: endpoint, + } + + return config +} + +func (idp *BaiduIdProvider) GetToken(code string) (*oauth2.Token, error) { + ctx := context.WithValue(context.Background(), oauth2.HTTPClient, idp.Client) + return idp.Config.Exchange(ctx, code) +} + +/* +{ + "userid":"2097322476", + "username":"wl19871011", + "realname":"阳光", + "userdetail":"喜欢自由", + "birthday":"1987-01-01", + "marriage":"恋爱", + "sex":"男", + "blood":"O", + "constellation":"射手", + "figure":"小巧", + "education":"大学/专科", + "trade":"计算机/电子产品", + "job":"未知", + "birthday_year":"1987", + "birthday_month":"01", + "birthday_day":"01", +} +*/ + +type BaiduUserInfo struct { + OpenId string `json:"openid"` + Username string `json:"username"` + Portrait string `json:"portrait"` +} + +func (idp *BaiduIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) { + resp, err := idp.Client.Get(fmt.Sprintf("https://openapi.baidu.com/rest/2.0/passport/users/getInfo?access_token=%s", token.AccessToken)) + if err != nil { + return nil, err + } + + data, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + baiduUser := BaiduUserInfo{} + if err = json.Unmarshal(data, &baiduUser); err != nil { + return nil, err + } + + userInfo := UserInfo{ + Id: baiduUser.OpenId, + Username: baiduUser.Username, + AvatarUrl: fmt.Sprintf("https://himg.bdimg.com/sys/portrait/item/%s", baiduUser.Portrait), + } + return &userInfo, nil +} diff --git a/idp/provider.go b/idp/provider.go index 747e3808..04a3dd4f 100644 --- a/idp/provider.go +++ b/idp/provider.go @@ -60,6 +60,8 @@ func GetIdProvider(providerType string, clientId string, clientSecret string, re return NewLarkIdProvider(clientId, clientSecret, redirectUrl) } else if providerType == "GitLab" { return NewGitlabIdProvider(clientId, clientSecret, redirectUrl) + } else if providerType == "Baidu" { + return NewBaiduIdProvider(clientId, clientSecret, redirectUrl) } else if isGothSupport(providerType) { return NewGothIdProvider(providerType, clientId, clientSecret, redirectUrl) } diff --git a/object/user.go b/object/user.go index 5e0299ae..5cafed64 100644 --- a/object/user.go +++ b/object/user.go @@ -79,6 +79,7 @@ type User struct { Wecom string `xorm:"wecom varchar(100)" json:"wecom"` Lark string `xorm:"lark varchar(100)" json:"lark"` Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"` + Baidu string `xorm:"baidu varchar(100)" json:"baidu"` Apple string `xorm:"apple varchar(100)" json:"apple"` AzureAD string `xorm:"azuread varchar(100)" json:"azuread"` Slack string `xorm:"slack varchar(100)" json:"slack"` diff --git a/web/src/Setting.js b/web/src/Setting.js index 1e17d001..86b21860 100644 --- a/web/src/Setting.js +++ b/web/src/Setting.js @@ -398,6 +398,7 @@ export function getProviderTypeOptions(category) { {id: 'WeCom', name: 'WeCom'}, {id: 'Lark', name: 'Lark'}, {id: 'GitLab', name: 'GitLab'}, + {id: 'Baidu', name: 'Baidu'}, {id: 'Apple', name: 'Apple'}, {id: 'AzureAD', name: 'AzureAD'}, {id: 'Slack', name: 'Slack'}, diff --git a/web/src/auth/BaiduLoginButton.js b/web/src/auth/BaiduLoginButton.js new file mode 100644 index 00000000..5aeddc16 --- /dev/null +++ b/web/src/auth/BaiduLoginButton.js @@ -0,0 +1,32 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import {createButton} from "react-social-login-buttons"; +import {StaticBaseUrl} from "../Setting"; + +function Icon({ width = 24, height = 24, color }) { + return Sign in with Baidu; +} + +const config = { + text: "Sign in with Baidu", + icon: Icon, + iconFormat: name => `fa fa-${name}`, + style: {background: "#ffffff", color: "#000000"}, + activeStyle: {background: "#ededee"}, +}; + +const BaiduLoginButton = createButton(config); + +export default BaiduLoginButton; diff --git a/web/src/auth/LoginPage.js b/web/src/auth/LoginPage.js index d84fec4b..d7a671c1 100644 --- a/web/src/auth/LoginPage.js +++ b/web/src/auth/LoginPage.js @@ -34,6 +34,7 @@ import LinkedInLoginButton from "./LinkedInLoginButton"; import WeComLoginButton from "./WeComLoginButton"; import LarkLoginButton from "./LarkLoginButton"; import GitLabLoginButton from "./GitLabLoginButton"; +import BaiduLoginButton from "./BaiduLoginButton"; import AppleLoginButton from "./AppleLoginButton" import AzureADLoginButton from "./AzureADLoginButton"; import SlackLoginButton from "./SlackLoginButton"; @@ -183,6 +184,8 @@ class LoginPage extends React.Component { return } else if (type === "GitLab") { return + } else if (type === "Baidu") { + return } else if (type === "Apple") { return } else if (type === "AzureAD") { diff --git a/web/src/auth/Provider.js b/web/src/auth/Provider.js index d300b77f..f5a6f1ee 100644 --- a/web/src/auth/Provider.js +++ b/web/src/auth/Provider.js @@ -69,6 +69,10 @@ const authInfo = { scope: "read_user+profile", endpoint: "https://gitlab.com/oauth/authorize", }, + Baidu: { + scope: "basic", + endpoint: "http://openapi.baidu.com/oauth/2.0/authorize", + }, Apple: { scope: "name%20email", endpoint: "https://appleid.apple.com/auth/authorize", @@ -227,6 +231,8 @@ export function getAuthUrl(application, provider, method) { return `${endpoint}?app_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}`; } else if (provider.type === "GitLab") { return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`; + } else if (provider.type === "Baidu") { + return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&display=popup`; } else if (provider.type === "Apple") { return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&response_mode=form_post`; } else if (provider.type === "AzureAD") {