Skip to content
This repository has been archived by the owner on Apr 25, 2023. It is now read-only.

Commit

Permalink
New interface: CheckUserExists,LoginByEmail,LoginByPhonePassword,Logi…
Browse files Browse the repository at this point in the history
…nByUsername
  • Loading branch information
luojielin committed Aug 9, 2021
1 parent eff33d5 commit ec83d5b
Show file tree
Hide file tree
Showing 11 changed files with 667 additions and 36 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module github.com/Authing/authing-go-sdk

require (
github.com/bitly/go-simplejson v0.5.0
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/json-iterator/go v1.1.11
github.com/kelvinji2009/ctxhttp v0.0.0-20190723014959-778a004eb7c4 // indirect
github.com/kelvinji2009/graphql v0.0.0-20190723015100-e537b5df1797
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E=
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY=
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
Expand Down
243 changes: 218 additions & 25 deletions lib/authentication/authentication_client.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
package authentication

import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"github.com/Authing/authing-go-sdk/lib/constant"
"github.com/Authing/authing-go-sdk/lib/model"
"github.com/Authing/authing-go-sdk/lib/util"
"github.com/Authing/authing-go-sdk/lib/util/cacheutil"
simplejson "github.com/bitly/go-simplejson"
"io/ioutil"
"net/http"
"strings"
"sync"
"time"
)

type Client struct {
Expand All @@ -19,6 +25,7 @@ type Client struct {
Secret string
Host string
RedirectUri string
userPoolId string
TokenEndPointAuthMethod constant.AuthMethodEnum

Log func(s string)
Expand Down Expand Up @@ -87,24 +94,24 @@ func (c *Client) GetAccessTokenByCode(code string) (string, error) {
}

body := map[string]string{
"client_id": c.AppId,
"client_id": c.AppId,
"client_secret": c.Secret,
"grant_type": "authorization_code",
"code": code,
"redirect_uri": c.RedirectUri,
"grant_type": "authorization_code",
"code": code,
"redirect_uri": c.RedirectUri,
}

switch c.TokenEndPointAuthMethod {
case constant.ClientSecretPost:
body["client_id"] = c.AppId
body["client_secret"] = c.Secret
case constant.ClientSecretBasic:
base64String := "Basic " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s",c.AppId, c.Secret)))
base64String := "Basic " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", c.AppId, c.Secret)))
header["Authorization"] = base64String
default:
body["client_id"] = c.AppId
}
resp, err := c.SendHttpRequest(url,constant.HttpMethodPost,header,body)
resp, err := c.SendHttpRequest(url, constant.HttpMethodPost, header, body)
return string(resp), err
}

Expand All @@ -117,7 +124,7 @@ func (c *Client) GetUserInfoByAccessToken(accessToken string) (string, error) {
return string(resp), err
}

func (c *Client) GetNewAccessTokenByRefreshToken (refreshToken string) (string, error) {
func (c *Client) GetNewAccessTokenByRefreshToken(refreshToken string) (string, error) {
if c.Protocol != constant.OIDC && c.Protocol != constant.OAUTH {
return constant.StringEmpty, errors.New("初始化 AuthenticationClient 时传入的 protocol 参数必须为 ProtocolEnum.OAUTH 或 ProtocolEnum.OIDC,请检查参数")
}
Expand All @@ -132,9 +139,9 @@ func (c *Client) GetNewAccessTokenByRefreshToken (refreshToken string) (string,
}

body := map[string]string{
"client_id": c.AppId,
"client_id": c.AppId,
"client_secret": c.Secret,
"grant_type": "refresh_token",
"grant_type": "refresh_token",
"refresh_token": refreshToken,
}

Expand All @@ -143,16 +150,16 @@ func (c *Client) GetNewAccessTokenByRefreshToken (refreshToken string) (string,
body["client_id"] = c.AppId
body["client_secret"] = c.Secret
case constant.ClientSecretBasic:
base64String := "Basic " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s",c.AppId, c.Secret)))
base64String := "Basic " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", c.AppId, c.Secret)))
header["Authorization"] = base64String
default:
body["client_id"] = c.AppId
}
resp, err := c.SendHttpRequest(url,constant.HttpMethodPost,header,body)
resp, err := c.SendHttpRequest(url, constant.HttpMethodPost, header, body)
return string(resp), err
}

func (c *Client) IntrospectToken (token string) (string, error) {
func (c *Client) IntrospectToken(token string) (string, error) {
url := c.Host + fmt.Sprintf("/%s/token/introspection", c.Protocol)

header := map[string]string{
Expand All @@ -168,16 +175,16 @@ func (c *Client) IntrospectToken (token string) (string, error) {
body["client_id"] = c.AppId
body["client_secret"] = c.Secret
case constant.ClientSecretBasic:
base64String := "Basic " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s",c.AppId, c.Secret)))
base64String := "Basic " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", c.AppId, c.Secret)))
header["Authorization"] = base64String
default:
body["client_id"] = c.AppId
}
resp, err := c.SendHttpRequest(url,constant.HttpMethodPost,header,body)
resp, err := c.SendHttpRequest(url, constant.HttpMethodPost, header, body)
return string(resp), err
}

func (c *Client) ValidateToken (req model.ValidateTokenRequest) (string, error) {
func (c *Client) ValidateToken(req model.ValidateTokenRequest) (string, error) {
if req.IdToken == constant.StringEmpty && req.AccessToken == constant.StringEmpty {
return constant.StringEmpty, errors.New("请传入 AccessToken 或 IdToken")
}
Expand All @@ -192,11 +199,11 @@ func (c *Client) ValidateToken (req model.ValidateTokenRequest) (string, error)
url += "access_token=" + req.AccessToken
}

resp, err := c.SendHttpRequest(url,constant.HttpMethodGet,nil,nil)
resp, err := c.SendHttpRequest(url, constant.HttpMethodGet, nil, nil)
return string(resp), err
}

func (c *Client) RevokeToken (token string) (string, error) {
func (c *Client) RevokeToken(token string) (string, error) {
if c.Protocol != constant.OIDC && c.Protocol != constant.OAUTH {
return constant.StringEmpty, errors.New("初始化 AuthenticationClient 时传入的 protocol 参数必须为 ProtocolEnum.OAUTH 或 ProtocolEnum.OIDC,请检查参数")
}
Expand All @@ -212,24 +219,24 @@ func (c *Client) RevokeToken (token string) (string, error) {

body := map[string]string{
"client_id": c.AppId,
"token": token,
"token": token,
}

switch c.TokenEndPointAuthMethod {
case constant.ClientSecretPost:
body["client_id"] = c.AppId
body["client_secret"] = c.Secret
case constant.ClientSecretBasic:
base64String := "Basic " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s",c.AppId, c.Secret)))
base64String := "Basic " + base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", c.AppId, c.Secret)))
header["Authorization"] = base64String
default:
body["client_id"] = c.AppId
}
resp, err := c.SendHttpRequest(url,constant.HttpMethodPost,header,body)
resp, err := c.SendHttpRequest(url, constant.HttpMethodPost, header, body)
return string(resp), err
}

func (c *Client) GetAccessTokenByClientCredentials (req model.GetAccessTokenByClientCredentialsRequest) (string, error) {
func (c *Client) GetAccessTokenByClientCredentials(req model.GetAccessTokenByClientCredentialsRequest) (string, error) {
if req.Scope == constant.StringEmpty {
return constant.StringEmpty, errors.New("请传入 scope 参数,请看文档:https://docs.authing.cn/v2/guides/authorization/m2m-authz.html")
}
Expand All @@ -244,16 +251,107 @@ func (c *Client) GetAccessTokenByClientCredentials (req model.GetAccessTokenByCl
}

body := map[string]string{
"client_id": req.ClientCredentialInput.AccessKey,
"client_id": req.ClientCredentialInput.AccessKey,
"client_secret": req.ClientCredentialInput.SecretKey,
"grant_type": "client_credentials",
"scope": req.Scope,
"grant_type": "client_credentials",
"scope": req.Scope,
}

resp, err := c.SendHttpRequest(url,constant.HttpMethodPost,header,body)
resp, err := c.SendHttpRequest(url, constant.HttpMethodPost, header, body)
return string(resp), err
}

func (c *Client) LoginByUserName(request model.LoginByUsernameInput) (*model.User, error) {
request.Password = util.RsaEncrypt(request.Password)
reqParam := make(map[string]interface{})
reqParam["input"] = request
data, _ := json.Marshal(&reqParam)
variables := make(map[string]interface{})
json.Unmarshal(data, &variables)
b, err := c.SendHttpRequestManage(c.Host+constant.CoreAuthingGraphqlPath, constant.HttpMethodPost, constant.LoginByUsernameDocument, variables)
if err != nil {
return nil, err
}
return loginGetUserInfo(b, "loginByUsername")
}

func (c *Client) LoginByEmail(request model.LoginByEmailInput) (*model.User, error) {
request.Password = util.RsaEncrypt(request.Password)
reqParam := make(map[string]interface{})
reqParam["input"] = request
data, _ := json.Marshal(&reqParam)
variables := make(map[string]interface{})
json.Unmarshal(data, &variables)
b, err := c.SendHttpRequestManage(c.Host+constant.CoreAuthingGraphqlPath, constant.HttpMethodPost, constant.LoginByEmailDocument, variables)
if err != nil {
return nil, err
}
return loginGetUserInfo(b, "loginByEmail")
}

func (c *Client) LoginByPhonePassword(request model.LoginByPhonePasswordInput) (*model.User, error) {
request.Password = util.RsaEncrypt(request.Password)
reqParam := make(map[string]interface{})
reqParam["input"] = request
data, _ := json.Marshal(&reqParam)
variables := make(map[string]interface{})
json.Unmarshal(data, &variables)
b, err := c.SendHttpRequestManage(c.Host+constant.CoreAuthingGraphqlPath, constant.HttpMethodPost, constant.LoginByPhonePasswordDocument, variables)
if err != nil {
return nil, err
}
return loginGetUserInfo(b, "loginByPhonePassword")
}

/*func (c *Client) LoginByPhoneCode(request model.LoginByPhoneCodeInput) (*model.User,error) {
reqParam := make(map[string]interface{})
reqParam["input"] = request
data, _ := json.Marshal(&reqParam)
variables := make(map[string]interface{})
json.Unmarshal(data, &variables)
b, err := c.SendHttpRequestManage(c.Host+constant.CoreAuthingGraphqlPath, constant.HttpMethodPost, constant.LoginByPhoneCodeDocument, variables)
if err != nil {
return nil, err
}
return loginGetUserInfo(b,"loginByPhoneCode")
}
func (c *Client) SendSmsCode(phone string) (*model.CommonMessage, error) {
var result *model.CommonMessage
variables := map[string]interface{}{
"phone": phone,
}
b, err := c.SendHttpRequestManage(c.Host+"/api/v2/sms/send", constant.HttpMethodPost, constant.StringEmpty, variables)
if err != nil {
return result, err
}
log.Println(string(b))
jsoniter.Unmarshal(b, result)
return result, nil
}*/

func loginGetUserInfo(b []byte, userKey string) (*model.User, error) {
var result *simplejson.Json
result, err := simplejson.NewJson(b)
if _, r := result.CheckGet("errors"); r {
msg, err := result.Get("errors").GetIndex(0).Get("message").Get("message").String()
if err != nil {
return nil, err
}
return nil, errors.New(msg)
}
byteUser, err := result.Get("data").Get(userKey).MarshalJSON()
if err != nil {
return nil, err
}
resultUser := model.User{}
err = json.Unmarshal(byteUser, &resultUser)
if err != nil {
return nil, err
}
return &resultUser, nil
}

func (c *Client) SendHttpRequest(url string, method string, header map[string]string, body map[string]string) ([]byte, error) {
var form http.Request
form.ParseForm()
Expand All @@ -279,3 +377,98 @@ func (c *Client) SendHttpRequest(url string, method string, header map[string]st
respBody, err := ioutil.ReadAll(res.Body)
return respBody, nil
}

func (c *Client) SendHttpRequestManage(url string, method string, query string, variables map[string]interface{}) ([]byte, error) {
var req *http.Request
if method == constant.HttpMethodGet {
req, _ = http.NewRequest(http.MethodGet, url, nil)
if variables != nil && len(variables) > 0 {
q := req.URL.Query()
for key, value := range variables {
q.Add(key, fmt.Sprintf("%v", value))
}
req.URL.RawQuery = q.Encode()
}

} else {
in := struct {
Query string `json:"query"`
Variables map[string]interface{} `json:"variables,omitempty"`
}{
Query: query,
Variables: variables,
}
var buf bytes.Buffer
err := json.NewEncoder(&buf).Encode(in)
if err != nil {
return nil, err
}
req, err = http.NewRequest(method, url, &buf)
req.Header.Add("Content-Type", "application/json")
}

//增加header选项
if !strings.HasPrefix(query, "query accessToken") {
token, _ := GetAccessToken(c)
req.Header.Add("Authorization", "Bearer "+token)
}
req.Header.Add("x-authing-userpool-id", ""+c.userPoolId)
req.Header.Add("x-authing-request-from", constant.SdkType)
req.Header.Add("x-authing-sdk-version", constant.SdkVersion)
req.Header.Add("x-authing-app-id", ""+constant.AppId)

res, err := c.HttpClient.Do(req)
if err != nil {
return nil, err
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
return body, nil
}

func QueryAccessToken(client *Client) (*model.AccessTokenRes, error) {
type Data struct {
AccessToken model.AccessTokenRes `json:"accessToken"`
}
type Result struct {
Data Data `json:"data"`
}

variables := map[string]interface{}{
"userPoolId": client.userPoolId,
"secret": client.Secret,
}

b, err := client.SendHttpRequestManage(client.Host+constant.CoreAuthingGraphqlPath, constant.HttpMethodPost, constant.AccessTokenDocument, variables)
if err != nil {
return nil, err
}
var r Result
if b != nil {
json.Unmarshal(b, &r)
}
return &r.Data.AccessToken, nil
}

func GetAccessToken(client *Client) (string, error) {
// 从缓存获取token
cacheToken, b := cacheutil.GetCache(constant.TokenCacheKeyPrefix + client.userPoolId)
if b && cacheToken != nil {
return cacheToken.(string), nil
}
// 从服务获取token,加锁
var mutex sync.Mutex
mutex.Lock()
defer mutex.Unlock()
cacheToken, b = cacheutil.GetCache(constant.TokenCacheKeyPrefix + client.userPoolId)
if b && cacheToken != nil {
return cacheToken.(string), nil
}
token, err := QueryAccessToken(client)
if err != nil {
return "", err
}
var expire = *(token.Exp) - time.Now().Unix() - 43200
cacheutil.SetCache(constant.TokenCacheKeyPrefix+client.userPoolId, *token.AccessToken, time.Duration(expire*int64(time.Second)))
return *token.AccessToken, nil
}
Loading

0 comments on commit ec83d5b

Please sign in to comment.