mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-21 10:03:50 +08:00
Compare commits
16 Commits
Author | SHA1 | Date | |
---|---|---|---|
2023795f3c | |||
8d13bf7e27 | |||
29aa379fb2 | |||
7a95b9c1d5 | |||
0fc0ba0c76 | |||
24459d852e | |||
e3f5bf93b2 | |||
879ca6a488 | |||
544cd40a08 | |||
99f7883c7d | |||
88b0fb6e52 | |||
fa9b49e25b | |||
cd76e9372e | |||
04b9e05244 | |||
a78b2de7b2 | |||
d0952ae908 |
@ -179,6 +179,20 @@ func (c *ApiController) GetOAuthToken() {
|
|||||||
if clientId == "" && clientSecret == "" {
|
if clientId == "" && clientSecret == "" {
|
||||||
clientId, clientSecret, _ = c.Ctx.Request.BasicAuth()
|
clientId, clientSecret, _ = c.Ctx.Request.BasicAuth()
|
||||||
}
|
}
|
||||||
|
if clientId == "" {
|
||||||
|
// If clientID is empty, try to read data from RequestBody
|
||||||
|
var tokenRequest TokenRequest
|
||||||
|
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &tokenRequest); err == nil {
|
||||||
|
clientId = tokenRequest.ClientId
|
||||||
|
clientSecret = tokenRequest.ClientSecret
|
||||||
|
grantType = tokenRequest.GrantType
|
||||||
|
code = tokenRequest.Code
|
||||||
|
verifier = tokenRequest.Verifier
|
||||||
|
scope = tokenRequest.Scope
|
||||||
|
username = tokenRequest.Username
|
||||||
|
password = tokenRequest.Password
|
||||||
|
}
|
||||||
|
}
|
||||||
host := c.Ctx.Request.Host
|
host := c.Ctx.Request.Host
|
||||||
|
|
||||||
c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host)
|
c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host)
|
||||||
@ -204,6 +218,18 @@ func (c *ApiController) RefreshToken() {
|
|||||||
clientSecret := c.Input().Get("client_secret")
|
clientSecret := c.Input().Get("client_secret")
|
||||||
host := c.Ctx.Request.Host
|
host := c.Ctx.Request.Host
|
||||||
|
|
||||||
|
if clientId == "" {
|
||||||
|
// If clientID is empty, try to read data from RequestBody
|
||||||
|
var tokenRequest TokenRequest
|
||||||
|
if err := json.Unmarshal(c.Ctx.Input.RequestBody, &tokenRequest); err == nil {
|
||||||
|
clientId = tokenRequest.ClientId
|
||||||
|
clientSecret = tokenRequest.ClientSecret
|
||||||
|
grantType = tokenRequest.GrantType
|
||||||
|
scope = tokenRequest.Scope
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
c.Data["json"] = object.RefreshToken(grantType, refreshToken, scope, clientId, clientSecret, host)
|
c.Data["json"] = object.RefreshToken(grantType, refreshToken, scope, clientId, clientSecret, host)
|
||||||
c.ServeJSON()
|
c.ServeJSON()
|
||||||
}
|
}
|
||||||
|
26
controllers/types.go
Normal file
26
controllers/types.go
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2022 The Casdoor 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 controllers
|
||||||
|
|
||||||
|
type TokenRequest struct {
|
||||||
|
GrantType string `json:"grant_type"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
ClientId string `json:"client_id"`
|
||||||
|
ClientSecret string `json:"client_secret"`
|
||||||
|
Verifier string `json:"code_verifier"`
|
||||||
|
Scope string `json:"scope"`
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
@ -11,6 +11,8 @@ services:
|
|||||||
- db
|
- db
|
||||||
environment:
|
environment:
|
||||||
RUNNING_IN_DOCKER: "true"
|
RUNNING_IN_DOCKER: "true"
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
volumes:
|
volumes:
|
||||||
- ./conf:/conf/
|
- ./conf:/conf/
|
||||||
db:
|
db:
|
||||||
|
1
go.sum
1
go.sum
@ -381,6 +381,7 @@ golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACk
|
|||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200604202706-70a84ac30bf9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 h1:BkypuErRT9A9I/iljuaG3/zdMjd/J6m8tKKJQtGfSdA=
|
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954 h1:BkypuErRT9A9I/iljuaG3/zdMjd/J6m8tKKJQtGfSdA=
|
||||||
|
292
idp/alipay.go
Normal file
292
idp/alipay.go
Normal file
@ -0,0 +1,292 @@
|
|||||||
|
// Copyright 2022 The Casdoor 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 (
|
||||||
|
"crypto"
|
||||||
|
"crypto/rand"
|
||||||
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
|
"encoding/json"
|
||||||
|
"encoding/pem"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AlipayIdProvider struct {
|
||||||
|
Client *http.Client
|
||||||
|
Config *oauth2.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAlipayIdProvider ...
|
||||||
|
func NewAlipayIdProvider(clientId string, clientSecret string, redirectUrl string) *AlipayIdProvider {
|
||||||
|
idp := &AlipayIdProvider{}
|
||||||
|
|
||||||
|
config := idp.getConfig(clientId, clientSecret, redirectUrl)
|
||||||
|
idp.Config = config
|
||||||
|
|
||||||
|
return idp
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHttpClient ...
|
||||||
|
func (idp *AlipayIdProvider) SetHttpClient(client *http.Client) {
|
||||||
|
idp.Client = client
|
||||||
|
}
|
||||||
|
|
||||||
|
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||||
|
func (idp *AlipayIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||||
|
var endpoint = oauth2.Endpoint{
|
||||||
|
AuthURL: "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm",
|
||||||
|
TokenURL: "https://openapi.alipay.com/gateway.do",
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = &oauth2.Config{
|
||||||
|
Scopes: []string{"", ""},
|
||||||
|
Endpoint: endpoint,
|
||||||
|
ClientID: clientId,
|
||||||
|
ClientSecret: clientSecret,
|
||||||
|
RedirectURL: redirectUrl,
|
||||||
|
}
|
||||||
|
|
||||||
|
return config
|
||||||
|
}
|
||||||
|
|
||||||
|
type AlipayAccessToken struct {
|
||||||
|
Response AlipaySystemOauthTokenResponse `json:"alipay_system_oauth_token_response"`
|
||||||
|
Sign string `json:"sign"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AlipaySystemOauthTokenResponse struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
AlipayUserId string `json:"alipay_user_id"`
|
||||||
|
ExpiresIn int `json:"expires_in"`
|
||||||
|
ReExpiresIn int `json:"re_expires_in"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
UserId string `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetToken use code to get access_token
|
||||||
|
func (idp *AlipayIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||||
|
pTokenParams := &struct {
|
||||||
|
ClientId string `json:"app_id"`
|
||||||
|
CharSet string `json:"charset"`
|
||||||
|
Code string `json:"code"`
|
||||||
|
GrantType string `json:"grant_type"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
SignType string `json:"sign_type"`
|
||||||
|
TimeStamp string `json:"timestamp"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}{idp.Config.ClientID, "utf-8", code, "authorization_code", "alipay.system.oauth.token", "RSA2", time.Now().Format("2006-01-02 15:04:05"), "1.0"}
|
||||||
|
|
||||||
|
data, err := idp.postWithBody(pTokenParams, idp.Config.Endpoint.TokenURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
pToken := &AlipayAccessToken{}
|
||||||
|
err = json.Unmarshal(data, pToken)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
token := &oauth2.Token{
|
||||||
|
AccessToken: pToken.Response.AccessToken,
|
||||||
|
Expiry: time.Unix(time.Now().Unix()+int64(pToken.Response.ExpiresIn), 0),
|
||||||
|
}
|
||||||
|
return token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"alipay_user_info_share_response":{
|
||||||
|
"code":"10000",
|
||||||
|
"msg":"Success",
|
||||||
|
"avatar":"https:\/\/tfs.alipayobjects.com\/images\/partner\/T1.QxFXk4aXXXXXXXX",
|
||||||
|
"nick_name":"zhangsan",
|
||||||
|
"user_id":"2099222233334444"
|
||||||
|
},
|
||||||
|
"sign":"m8rWJeqfoa5tDQRRVnPhRHcpX7NZEgjIPTPF1QBxos6XXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
type AlipayUserResponse struct {
|
||||||
|
AlipayUserInfoShareResponse AlipayUserInfoShareResponse `json:"alipay_user_info_share_response"`
|
||||||
|
Sign string `json:"sign"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AlipayUserInfoShareResponse struct {
|
||||||
|
Code string `json:"code"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Avatar string `json:"avatar"`
|
||||||
|
NickName string `json:"nick_name"`
|
||||||
|
UserId string `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserInfo Use access_token to get UserInfo
|
||||||
|
func (idp *AlipayIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||||
|
atUserInfo := &AlipayUserResponse{}
|
||||||
|
accessToken := token.AccessToken
|
||||||
|
|
||||||
|
pTokenParams := &struct {
|
||||||
|
ClientId string `json:"app_id"`
|
||||||
|
CharSet string `json:"charset"`
|
||||||
|
AuthToken string `json:"auth_token"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
SignType string `json:"sign_type"`
|
||||||
|
TimeStamp string `json:"timestamp"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
}{idp.Config.ClientID, "utf-8", accessToken, "alipay.user.info.share", "RSA2", time.Now().Format("2006-01-02 15:04:05"), "1.0"}
|
||||||
|
data, err := idp.postWithBody(pTokenParams, idp.Config.Endpoint.TokenURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(data, atUserInfo)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
userInfo := UserInfo{
|
||||||
|
Id: atUserInfo.AlipayUserInfoShareResponse.UserId,
|
||||||
|
Username: atUserInfo.AlipayUserInfoShareResponse.NickName,
|
||||||
|
DisplayName: atUserInfo.AlipayUserInfoShareResponse.NickName,
|
||||||
|
AvatarUrl: atUserInfo.AlipayUserInfoShareResponse.Avatar,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &userInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (idp *AlipayIdProvider) postWithBody(body interface{}, targetUrl string) ([]byte, error) {
|
||||||
|
bs, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bodyJson := make(map[string]interface{})
|
||||||
|
err = json.Unmarshal(bs, &bodyJson)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
formData := url.Values{}
|
||||||
|
for k := range bodyJson {
|
||||||
|
formData.Set(k, bodyJson[k].(string))
|
||||||
|
}
|
||||||
|
|
||||||
|
sign, err := rsaSignWithRSA256(getStringToSign(formData), idp.Config.ClientSecret)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
formData.Set("sign", sign)
|
||||||
|
|
||||||
|
resp, err := idp.Client.PostForm(targetUrl, formData)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func(Body io.ReadCloser) {
|
||||||
|
err := Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}(resp.Body)
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the string to sign, see https://opendocs.alipay.com/common/02kf5q
|
||||||
|
func getStringToSign(formData url.Values) string {
|
||||||
|
keys := make([]string, 0, len(formData))
|
||||||
|
for k := range formData {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
str := ""
|
||||||
|
for _, k := range keys {
|
||||||
|
if k == "sign" || formData[k][0] == "" {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
str += "&" + k + "=" + formData[k][0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str = strings.Trim(str, "&")
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
|
||||||
|
// use privateKey to sign the content
|
||||||
|
func rsaSignWithRSA256(signContent string, privateKey string) (string, error) {
|
||||||
|
privateKey = formatPrivateKey(privateKey)
|
||||||
|
block, _ := pem.Decode([]byte(privateKey))
|
||||||
|
if block == nil {
|
||||||
|
panic("fail to parse privateKey")
|
||||||
|
}
|
||||||
|
|
||||||
|
h := sha256.New()
|
||||||
|
h.Write([]byte(signContent))
|
||||||
|
hashed := h.Sum(nil)
|
||||||
|
|
||||||
|
privateKeyRSA, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
signature, err := rsa.SignPKCS1v15(rand.Reader, privateKeyRSA.(*rsa.PrivateKey), crypto.SHA256, hashed)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString(signature), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// privateKey in database is a string, format it to PEM style
|
||||||
|
func formatPrivateKey(privateKey string) string {
|
||||||
|
// each line length is 64
|
||||||
|
preFmtPrivateKey := ""
|
||||||
|
for i := 0; ; {
|
||||||
|
if i+64 <= len(privateKey) {
|
||||||
|
preFmtPrivateKey = preFmtPrivateKey + privateKey[i:i+64] + "\n"
|
||||||
|
i += 64
|
||||||
|
} else {
|
||||||
|
preFmtPrivateKey = preFmtPrivateKey + privateKey[i:]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
privateKey = strings.Trim(preFmtPrivateKey, "\n")
|
||||||
|
|
||||||
|
// add pkcs#8 BEGIN and END
|
||||||
|
PemBegin := "-----BEGIN PRIVATE KEY-----\n"
|
||||||
|
PemEnd := "\n-----END PRIVATE KEY-----"
|
||||||
|
if !strings.HasPrefix(privateKey, PemBegin) {
|
||||||
|
privateKey = PemBegin + privateKey
|
||||||
|
}
|
||||||
|
if !strings.HasSuffix(privateKey, PemEnd) {
|
||||||
|
privateKey = privateKey + PemEnd
|
||||||
|
}
|
||||||
|
return privateKey
|
||||||
|
}
|
@ -15,11 +15,13 @@
|
|||||||
package idp
|
package idp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
@ -60,9 +62,38 @@ func (idp *GithubIdProvider) getConfig() *oauth2.Config {
|
|||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type GithubToken struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
TokenType string `json:"token_type"`
|
||||||
|
Scope string `json:"scope"`
|
||||||
|
Error string `json:"error"`
|
||||||
|
}
|
||||||
|
|
||||||
func (idp *GithubIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
func (idp *GithubIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||||
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, idp.Client)
|
params := &struct {
|
||||||
return idp.Config.Exchange(ctx, code)
|
Code string `json:"code"`
|
||||||
|
ClientId string `json:"client_id"`
|
||||||
|
ClientSecret string `json:"client_secret"`
|
||||||
|
}{code, idp.Config.ClientID, idp.Config.ClientSecret}
|
||||||
|
data, err := idp.postWithBody(params, idp.Config.Endpoint.TokenURL)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
pToken := &GithubToken{}
|
||||||
|
if err = json.Unmarshal(data, pToken); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if pToken.Error != "" {
|
||||||
|
return nil, fmt.Errorf("err: %s", pToken.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
token := &oauth2.Token{
|
||||||
|
AccessToken: pToken.AccessToken,
|
||||||
|
TokenType: "Bearer",
|
||||||
|
}
|
||||||
|
|
||||||
|
return token, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//{
|
//{
|
||||||
@ -192,3 +223,30 @@ func (idp *GithubIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
|
|||||||
}
|
}
|
||||||
return &userInfo, nil
|
return &userInfo, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (idp *GithubIdProvider) postWithBody(body interface{}, url string) ([]byte, error) {
|
||||||
|
bs, err := json.Marshal(body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
r := strings.NewReader(string(bs))
|
||||||
|
req, _ := http.NewRequest("POST", url, r)
|
||||||
|
req.Header.Set("Accept", "application/json")
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
resp, err := idp.Client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func(Body io.ReadCloser) {
|
||||||
|
err := Body.Close()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}(resp.Body)
|
||||||
|
|
||||||
|
return data, nil
|
||||||
|
}
|
||||||
|
@ -231,6 +231,10 @@ func (idp *GothIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
|||||||
value.Add("code", code)
|
value.Add("code", code)
|
||||||
}
|
}
|
||||||
accessToken, err := idp.Session.Authorize(idp.Provider, value)
|
accessToken, err := idp.Session.Authorize(idp.Provider, value)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
//Get ExpiresAt's value
|
//Get ExpiresAt's value
|
||||||
valueOfExpire := reflect.ValueOf(idp.Session).Elem().FieldByName("ExpiresAt")
|
valueOfExpire := reflect.ValueOf(idp.Session).Elem().FieldByName("ExpiresAt")
|
||||||
if valueOfExpire.IsValid() {
|
if valueOfExpire.IsValid() {
|
||||||
@ -240,7 +244,8 @@ func (idp *GothIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
|||||||
AccessToken: accessToken,
|
AccessToken: accessToken,
|
||||||
Expiry: expireAt,
|
Expiry: expireAt,
|
||||||
}
|
}
|
||||||
return &token, err
|
|
||||||
|
return &token, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (idp *GothIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
func (idp *GothIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||||
|
@ -70,6 +70,8 @@ func GetIdProvider(typ string, subType string, clientId string, clientSecret str
|
|||||||
return NewAdfsIdProvider(clientId, clientSecret, redirectUrl, hostUrl)
|
return NewAdfsIdProvider(clientId, clientSecret, redirectUrl, hostUrl)
|
||||||
} else if typ == "Baidu" {
|
} else if typ == "Baidu" {
|
||||||
return NewBaiduIdProvider(clientId, clientSecret, redirectUrl)
|
return NewBaiduIdProvider(clientId, clientSecret, redirectUrl)
|
||||||
|
} else if typ == "Alipay" {
|
||||||
|
return NewAlipayIdProvider(clientId, clientSecret, redirectUrl)
|
||||||
} else if typ == "Infoflow" {
|
} else if typ == "Infoflow" {
|
||||||
if subType == "Internal" {
|
if subType == "Internal" {
|
||||||
return NewInfoflowInternalIdProvider(clientId, clientSecret, appId, redirectUrl)
|
return NewInfoflowInternalIdProvider(clientId, clientSecret, appId, redirectUrl)
|
||||||
|
@ -76,6 +76,9 @@ func (idp *QqIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
|||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
tokenContent, err := ioutil.ReadAll(resp.Body)
|
tokenContent, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
re := regexp.MustCompile("token=(.*?)&")
|
re := regexp.MustCompile("token=(.*?)&")
|
||||||
matched := re.FindAllStringSubmatch(string(tokenContent), -1)
|
matched := re.FindAllStringSubmatch(string(tokenContent), -1)
|
||||||
@ -146,6 +149,9 @@ func (idp *QqIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
|||||||
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
openIdBody, err := ioutil.ReadAll(resp.Body)
|
openIdBody, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
re := regexp.MustCompile("\"openid\":\"(.*?)\"}")
|
re := regexp.MustCompile("\"openid\":\"(.*?)\"}")
|
||||||
matched := re.FindAllStringSubmatch(string(openIdBody), -1)
|
matched := re.FindAllStringSubmatch(string(openIdBody), -1)
|
||||||
@ -178,6 +184,7 @@ func (idp *QqIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
|||||||
|
|
||||||
userInfo := UserInfo{
|
userInfo := UserInfo{
|
||||||
Id: openId,
|
Id: openId,
|
||||||
|
Username: qqUserInfo.Nickname,
|
||||||
DisplayName: qqUserInfo.Nickname,
|
DisplayName: qqUserInfo.Nickname,
|
||||||
AvatarUrl: qqUserInfo.FigureurlQq1,
|
AvatarUrl: qqUserInfo.FigureurlQq1,
|
||||||
}
|
}
|
||||||
|
@ -111,6 +111,7 @@ type WecomInternalUserInfo struct {
|
|||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Avatar string `json:"avatar"`
|
Avatar string `json:"avatar"`
|
||||||
OpenId string `json:"open_userid"`
|
OpenId string `json:"open_userid"`
|
||||||
|
UserId string `json:"userid"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (idp *WeComInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
func (idp *WeComInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||||
@ -156,7 +157,7 @@ func (idp *WeComInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo,
|
|||||||
return nil, fmt.Errorf("userInfoResp.errcode = %d, userInfoResp.errmsg = %s", infoResp.Errcode, infoResp.Errmsg)
|
return nil, fmt.Errorf("userInfoResp.errcode = %d, userInfoResp.errmsg = %s", infoResp.Errcode, infoResp.Errmsg)
|
||||||
}
|
}
|
||||||
userInfo := UserInfo{
|
userInfo := UserInfo{
|
||||||
Id: infoResp.OpenId,
|
Id: infoResp.UserId,
|
||||||
Username: infoResp.Name,
|
Username: infoResp.Name,
|
||||||
DisplayName: infoResp.Name,
|
DisplayName: infoResp.Name,
|
||||||
Email: infoResp.Email,
|
Email: infoResp.Email,
|
||||||
|
@ -180,16 +180,15 @@ func CheckUserPassword(organization string, username string, password string) (*
|
|||||||
return nil, "the user is forbidden to sign in, please contact the administrator"
|
return nil, "the user is forbidden to sign in, please contact the administrator"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user.Ldap != "" {
|
||||||
|
//ONLY for ldap users
|
||||||
|
return checkLdapUserPassword(user, password)
|
||||||
|
} else {
|
||||||
msg := CheckPassword(user, password)
|
msg := CheckPassword(user, password)
|
||||||
if msg != "" {
|
if msg != "" {
|
||||||
//for ldap users
|
|
||||||
if user.Ldap != "" {
|
|
||||||
return checkLdapUserPassword(user, password)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, msg
|
return nil, msg
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return user, ""
|
return user, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,17 +21,19 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func InitDb() {
|
func InitDb() {
|
||||||
initBuiltInOrganization()
|
existed := initBuiltInOrganization()
|
||||||
|
if !existed {
|
||||||
initBuiltInUser()
|
initBuiltInUser()
|
||||||
initBuiltInApplication()
|
initBuiltInApplication()
|
||||||
initBuiltInCert()
|
initBuiltInCert()
|
||||||
initBuiltInLdap()
|
initBuiltInLdap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBuiltInOrganization() {
|
func initBuiltInOrganization() bool {
|
||||||
organization := getOrganization("admin", "built-in")
|
organization := getOrganization("admin", "built-in")
|
||||||
if organization != nil {
|
if organization != nil {
|
||||||
return
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
organization = &Organization{
|
organization = &Organization{
|
||||||
@ -47,6 +49,7 @@ func initBuiltInOrganization() {
|
|||||||
Tags: []string{},
|
Tags: []string{},
|
||||||
}
|
}
|
||||||
AddOrganization(organization)
|
AddOrganization(organization)
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func initBuiltInUser() {
|
func initBuiltInUser() {
|
||||||
|
@ -33,7 +33,7 @@ type Provider struct {
|
|||||||
SubType string `xorm:"varchar(100)" json:"subType"`
|
SubType string `xorm:"varchar(100)" json:"subType"`
|
||||||
Method string `xorm:"varchar(100)" json:"method"`
|
Method string `xorm:"varchar(100)" json:"method"`
|
||||||
ClientId string `xorm:"varchar(100)" json:"clientId"`
|
ClientId string `xorm:"varchar(100)" json:"clientId"`
|
||||||
ClientSecret string `xorm:"varchar(100)" json:"clientSecret"`
|
ClientSecret string `xorm:"varchar(2000)" json:"clientSecret"`
|
||||||
ClientId2 string `xorm:"varchar(100)" json:"clientId2"`
|
ClientId2 string `xorm:"varchar(100)" json:"clientId2"`
|
||||||
ClientSecret2 string `xorm:"varchar(100)" json:"clientSecret2"`
|
ClientSecret2 string `xorm:"varchar(100)" json:"clientSecret2"`
|
||||||
Cert string `xorm:"varchar(100)" json:"cert"`
|
Cert string `xorm:"varchar(100)" json:"cert"`
|
||||||
|
@ -34,6 +34,9 @@ func (application *Application) GetProviderItem(providerName string) *ProviderIt
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (pi *ProviderItem) IsProviderVisible() bool {
|
func (pi *ProviderItem) IsProviderVisible() bool {
|
||||||
|
if pi.Provider == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return pi.Provider.Category == "OAuth" || pi.Provider.Category == "SAML"
|
return pi.Provider.Category == "OAuth" || pi.Provider.Category == "SAML"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -439,14 +439,15 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
|
|||||||
TokenType: "Bearer",
|
TokenType: "Bearer",
|
||||||
}
|
}
|
||||||
AddToken(newToken)
|
AddToken(newToken)
|
||||||
|
DeleteToken(&token)
|
||||||
|
|
||||||
tokenWrapper := &TokenWrapper{
|
tokenWrapper := &TokenWrapper{
|
||||||
AccessToken: token.AccessToken,
|
AccessToken: newToken.AccessToken,
|
||||||
IdToken: token.AccessToken,
|
IdToken: newToken.AccessToken,
|
||||||
RefreshToken: token.RefreshToken,
|
RefreshToken: newToken.RefreshToken,
|
||||||
TokenType: token.TokenType,
|
TokenType: newToken.TokenType,
|
||||||
ExpiresIn: token.ExpiresIn,
|
ExpiresIn: newToken.ExpiresIn,
|
||||||
Scope: token.Scope,
|
Scope: newToken.Scope,
|
||||||
}
|
}
|
||||||
|
|
||||||
return tokenWrapper
|
return tokenWrapper
|
||||||
@ -521,7 +522,8 @@ func GetPasswordToken(application *Application, username string, password string
|
|||||||
if user == nil {
|
if user == nil {
|
||||||
return nil, errors.New("error: the user does not exist")
|
return nil, errors.New("error: the user does not exist")
|
||||||
}
|
}
|
||||||
if user.Password != password {
|
msg := CheckPassword(user, password)
|
||||||
|
if msg != "" {
|
||||||
return nil, errors.New("error: invalid username or password")
|
return nil, errors.New("error: invalid username or password")
|
||||||
}
|
}
|
||||||
if user.IsForbidden {
|
if user.IsForbidden {
|
||||||
|
@ -85,6 +85,7 @@ type User struct {
|
|||||||
Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"`
|
Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"`
|
||||||
Adfs string `xorm:"adfs varchar(100)" json:"adfs"`
|
Adfs string `xorm:"adfs varchar(100)" json:"adfs"`
|
||||||
Baidu string `xorm:"baidu varchar(100)" json:"baidu"`
|
Baidu string `xorm:"baidu varchar(100)" json:"baidu"`
|
||||||
|
Alipay string `xorm:"alipay varchar(100)" json:"alipay"`
|
||||||
Casdoor string `xorm:"casdoor varchar(100)" json:"casdoor"`
|
Casdoor string `xorm:"casdoor varchar(100)" json:"casdoor"`
|
||||||
Infoflow string `xorm:"infoflow varchar(100)" json:"infoflow"`
|
Infoflow string `xorm:"infoflow varchar(100)" json:"infoflow"`
|
||||||
Apple string `xorm:"apple varchar(100)" json:"apple"`
|
Apple string `xorm:"apple varchar(100)" json:"apple"`
|
||||||
@ -304,7 +305,7 @@ func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) boo
|
|||||||
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties"}
|
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties"}
|
||||||
}
|
}
|
||||||
if isGlobalAdmin {
|
if isGlobalAdmin {
|
||||||
columns = append(columns, "name")
|
columns = append(columns, "name", "email", "phone")
|
||||||
}
|
}
|
||||||
|
|
||||||
affected, err := adapter.Engine.ID(core.PK{owner, name}).Cols(columns...).Update(user)
|
affected, err := adapter.Engine.ID(core.PK{owner, name}).Cols(columns...).Update(user)
|
||||||
|
@ -83,6 +83,10 @@ class ProductBuyPage extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getPrice(product) {
|
||||||
|
return `${this.getCurrencySymbol(product)}${product?.price} (${this.getCurrencyText(product)})`;
|
||||||
|
}
|
||||||
|
|
||||||
getProviders(product) {
|
getProviders(product) {
|
||||||
if (this.state.providers.length === 0 || product.providers.length === 0) {
|
if (this.state.providers.length === 0 || product.providers.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
@ -207,7 +211,9 @@ class ProductBuyPage extends React.Component {
|
|||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label={i18next.t("product:Price")}>
|
<Descriptions.Item label={i18next.t("product:Price")}>
|
||||||
<span style={{fontSize: 28, color: "red", fontWeight: "bold"}}>
|
<span style={{fontSize: 28, color: "red", fontWeight: "bold"}}>
|
||||||
{`${this.getCurrencySymbol(product)}${product?.price} (${this.getCurrencyText(product)})`}
|
{
|
||||||
|
this.getPrice(product)
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label={i18next.t("product:Quantity")}><span style={{fontSize: 16}}>{product?.quantity}</span></Descriptions.Item>
|
<Descriptions.Item label={i18next.t("product:Quantity")}><span style={{fontSize: 16}}>{product?.quantity}</span></Descriptions.Item>
|
||||||
|
@ -22,6 +22,7 @@ import copy from "copy-to-clipboard";
|
|||||||
import {authConfig} from "./auth/Auth";
|
import {authConfig} from "./auth/Auth";
|
||||||
import {Helmet} from "react-helmet";
|
import {Helmet} from "react-helmet";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
import * as Conf from "./Conf";
|
||||||
|
|
||||||
export let ServerUrl = "";
|
export let ServerUrl = "";
|
||||||
|
|
||||||
@ -29,12 +30,17 @@ export let ServerUrl = "";
|
|||||||
export const StaticBaseUrl = "https://cdn.casbin.org";
|
export const StaticBaseUrl = "https://cdn.casbin.org";
|
||||||
|
|
||||||
// https://catamphetamine.gitlab.io/country-flag-icons/3x2/index.html
|
// https://catamphetamine.gitlab.io/country-flag-icons/3x2/index.html
|
||||||
export const CountryRegionData = getCountryRegionData()
|
export const CountryRegionData = getCountryRegionData();
|
||||||
|
|
||||||
export function getCountryRegionData() {
|
export function getCountryRegionData() {
|
||||||
|
let language = i18next.language;
|
||||||
|
if (language === null || language === "null") {
|
||||||
|
language = Conf.DefaultLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
var countries = require("i18n-iso-countries");
|
var countries = require("i18n-iso-countries");
|
||||||
countries.registerLocale(require("i18n-iso-countries/langs/" + i18next.language + ".json"));
|
countries.registerLocale(require("i18n-iso-countries/langs/" + language + ".json"));
|
||||||
var data = countries.getNames(i18next.language, {select: "official"});
|
var data = countries.getNames(language, {select: "official"});
|
||||||
var result = []
|
var result = []
|
||||||
for (var i in data)
|
for (var i in data)
|
||||||
result.push({code:i, name:data[i]})
|
result.push({code:i, name:data[i]})
|
||||||
@ -396,6 +402,7 @@ export function getProviderTypeOptions(category) {
|
|||||||
{id: 'GitLab', name: 'GitLab'},
|
{id: 'GitLab', name: 'GitLab'},
|
||||||
{id: 'Adfs', name: 'Adfs'},
|
{id: 'Adfs', name: 'Adfs'},
|
||||||
{id: 'Baidu', name: 'Baidu'},
|
{id: 'Baidu', name: 'Baidu'},
|
||||||
|
{id: 'Alipay', name: 'Alipay'},
|
||||||
{id: 'Casdoor', name: 'Casdoor'},
|
{id: 'Casdoor', name: 'Casdoor'},
|
||||||
{id: 'Infoflow', name: 'Infoflow'},
|
{id: 'Infoflow', name: 'Infoflow'},
|
||||||
{id: 'Apple', name: 'Apple'},
|
{id: 'Apple', name: 'Apple'},
|
||||||
|
@ -42,7 +42,7 @@ class SyncerListPage extends BaseListPage {
|
|||||||
affiliationTable: "",
|
affiliationTable: "",
|
||||||
avatarBaseUrl: "",
|
avatarBaseUrl: "",
|
||||||
syncInterval: 10,
|
syncInterval: 10,
|
||||||
isEnabled: true,
|
isEnabled: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +224,11 @@ class UserEditPage extends React.Component {
|
|||||||
{Setting.getLabel(i18next.t("general:Email"), i18next.t("general:Email - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Email"), i18next.t("general:Email - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col style={{paddingRight: '20px'}} span={11} >
|
<Col style={{paddingRight: '20px'}} span={11} >
|
||||||
<Input value={this.state.user.email} disabled />
|
<Input value={this.state.user.email}
|
||||||
|
disabled={this.state.user.id === this.props.account?.id ? true : !Setting.isAdminUser(this.props.account)}
|
||||||
|
onChange={e => {
|
||||||
|
this.updateUserField('email', e.target.value);
|
||||||
|
}} />
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={11} >
|
<Col span={11} >
|
||||||
{ this.state.user.id === this.props.account?.id ? (<ResetModal org={this.state.application?.organizationObj} buttonText={i18next.t("user:Reset Email...")} destType={"email"} />) : null}
|
{ this.state.user.id === this.props.account?.id ? (<ResetModal org={this.state.application?.organizationObj} buttonText={i18next.t("user:Reset Email...")} destType={"email"} />) : null}
|
||||||
@ -235,7 +239,11 @@ class UserEditPage extends React.Component {
|
|||||||
{Setting.getLabel(i18next.t("general:Phone"), i18next.t("general:Phone - Tooltip"))} :
|
{Setting.getLabel(i18next.t("general:Phone"), i18next.t("general:Phone - Tooltip"))} :
|
||||||
</Col>
|
</Col>
|
||||||
<Col style={{paddingRight: '20px'}} span={11} >
|
<Col style={{paddingRight: '20px'}} span={11} >
|
||||||
<Input value={this.state.user.phone} addonBefore={`+${this.state.application?.organizationObj.phonePrefix}`} disabled />
|
<Input value={this.state.user.phone} addonBefore={`+${this.state.application?.organizationObj.phonePrefix}`}
|
||||||
|
disabled={this.state.user.id === this.props.account?.id ? true : !Setting.isAdminUser(this.props.account)}
|
||||||
|
onChange={e => {
|
||||||
|
this.updateUserField('phone', e.target.value);
|
||||||
|
}}/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={11} >
|
<Col span={11} >
|
||||||
{ this.state.user.id === this.props.account?.id ? (<ResetModal org={this.state.application?.organizationObj} buttonText={i18next.t("user:Reset Phone...")} destType={"phone"} />) : null}
|
{ this.state.user.id === this.props.account?.id ? (<ResetModal org={this.state.application?.organizationObj} buttonText={i18next.t("user:Reset Phone...")} destType={"phone"} />) : null}
|
||||||
|
32
web/src/auth/AlipayLoginButton.js
Normal file
32
web/src/auth/AlipayLoginButton.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2022 The Casdoor 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 <img src={`${StaticBaseUrl}/buttons/alipay.svg`} alt="Sign in with Alipay" style={{width: 24, height: 24}} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
text: "Sign in with Alipay",
|
||||||
|
icon: Icon,
|
||||||
|
iconFormat: name => `fa fa-${name}`,
|
||||||
|
style: {background: "#ffffff", color: "#000000"},
|
||||||
|
activeStyle: {background: "#ededee"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const AlipayLoginButton = createButton(config);
|
||||||
|
|
||||||
|
export default AlipayLoginButton;
|
@ -36,6 +36,7 @@ import LarkLoginButton from "./LarkLoginButton";
|
|||||||
import GitLabLoginButton from "./GitLabLoginButton";
|
import GitLabLoginButton from "./GitLabLoginButton";
|
||||||
import AdfsLoginButton from "./AdfsLoginButton";
|
import AdfsLoginButton from "./AdfsLoginButton";
|
||||||
import BaiduLoginButton from "./BaiduLoginButton";
|
import BaiduLoginButton from "./BaiduLoginButton";
|
||||||
|
import AlipayLoginButton from "./AlipayLoginButton";
|
||||||
import CasdoorLoginButton from "./CasdoorLoginButton";
|
import CasdoorLoginButton from "./CasdoorLoginButton";
|
||||||
import InfoflowLoginButton from "./InfoflowLoginButton";
|
import InfoflowLoginButton from "./InfoflowLoginButton";
|
||||||
import AppleLoginButton from "./AppleLoginButton"
|
import AppleLoginButton from "./AppleLoginButton"
|
||||||
@ -206,6 +207,8 @@ class LoginPage extends React.Component {
|
|||||||
return <CasdoorLoginButton text={text} align={"center"} />
|
return <CasdoorLoginButton text={text} align={"center"} />
|
||||||
} else if (type === "Baidu") {
|
} else if (type === "Baidu") {
|
||||||
return <BaiduLoginButton text={text} align={"center"} />
|
return <BaiduLoginButton text={text} align={"center"} />
|
||||||
|
} else if (type === "Alipay") {
|
||||||
|
return <AlipayLoginButton text={text} align={"center"} />
|
||||||
} else if (type === "Infoflow") {
|
} else if (type === "Infoflow") {
|
||||||
return <InfoflowLoginButton text={text} align={"center"} />
|
return <InfoflowLoginButton text={text} align={"center"} />
|
||||||
} else if (type === "Apple") {
|
} else if (type === "Apple") {
|
||||||
|
@ -78,6 +78,10 @@ const authInfo = {
|
|||||||
scope: "basic",
|
scope: "basic",
|
||||||
endpoint: "http://openapi.baidu.com/oauth/2.0/authorize",
|
endpoint: "http://openapi.baidu.com/oauth/2.0/authorize",
|
||||||
},
|
},
|
||||||
|
Alipay: {
|
||||||
|
scope: "basic",
|
||||||
|
endpoint: "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm",
|
||||||
|
},
|
||||||
Casdoor: {
|
Casdoor: {
|
||||||
scope: "openid%20profile%20email",
|
scope: "openid%20profile%20email",
|
||||||
endpoint: "http://example.com",
|
endpoint: "http://example.com",
|
||||||
@ -287,6 +291,8 @@ export function getAuthUrl(application, provider, method) {
|
|||||||
return `${provider.domain}/adfs/oauth2/authorize?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&nonce=casdoor&scope=openid`;
|
return `${provider.domain}/adfs/oauth2/authorize?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&nonce=casdoor&scope=openid`;
|
||||||
} else if (provider.type === "Baidu") {
|
} else if (provider.type === "Baidu") {
|
||||||
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&display=popup`;
|
return `${endpoint}?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&display=popup`;
|
||||||
|
} else if (provider.type === "Alipay") {
|
||||||
|
return `${endpoint}?app_id=${provider.clientId}&scope=auth_user&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}&display=popup`;
|
||||||
} else if (provider.type === "Casdoor") {
|
} else if (provider.type === "Casdoor") {
|
||||||
return `${provider.domain}/login/oauth/authorize?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`;
|
return `${provider.domain}/login/oauth/authorize?client_id=${provider.clientId}&redirect_uri=${redirectUri}&state=${state}&response_type=code&scope=${scope}`;
|
||||||
} else if (provider.type === "Infoflow"){
|
} else if (provider.type === "Infoflow"){
|
||||||
|
Reference in New Issue
Block a user