From 3a4f5332c9d90ed6986914e2eca3b4438f91c101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E8=8C=B6=E6=B8=85=E6=AC=A2?= Date: Mon, 17 Jan 2022 00:56:01 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0OAuth=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oauth/define.go | 29 +++++++++++ oauth/oauth.go | 128 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 oauth/define.go create mode 100644 oauth/oauth.go diff --git a/oauth/define.go b/oauth/define.go new file mode 100644 index 0000000..8532e68 --- /dev/null +++ b/oauth/define.go @@ -0,0 +1,29 @@ +// Package oauth ... +// +// Description : oauth ... +// +// Author : go_developer@163.com<张德满> +// +// Date : 2022/01/17 12:20 AM +package oauth + +// Config OAuth相关配置 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2022/1/17 12:20 AM +type Config struct { + ClientID string `json:"client_id"` // 授权的client id + ClientSecret string `json:"client_secret"` // 授权的client_secret + CallbackURL string `json:"callback_url"` // 授权后携带code回调的地址 + Domain string `json:"domain"` // 服务器域名 + AuthorizationPageURI string `json:"authorization_page_uri"` // 授权页面URI + GetAccessTokenURI string `json:"get_access_token_uri"` // 获取access token地址 + ValidateAccessTokenURI string `json:"validate_access_token_uri"` // 验证access_token地址 + AccessTokenKey string `json:"access_token_key"` // 验证access token时的key + UseAuthorization bool `json:"use_authorization"` // 是否使用header中的Authorization + FormatAccessTokenFunc FormatAccessTokenFunc `json:"format_access_token_func"` // 格式化token的函数 +} + +// FormatAccessTokenFunc 格式化token +type FormatAccessTokenFunc func(token string) string diff --git a/oauth/oauth.go b/oauth/oauth.go new file mode 100644 index 0000000..a4d2aaf --- /dev/null +++ b/oauth/oauth.go @@ -0,0 +1,128 @@ +// Package oauth ... +// +// Description : oauth ... +// +// Author : go_developer@163.com<张德满> +// +// Date : 2022/01/17 12:18 AM +package oauth + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + + "github.com/pkg/errors" + + "github.com/ddliu/go-httpclient" +) + +// NewOAuth 获取OAuth实例 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2022/1/17 12:19 AM +func NewOAuth(cfg Config) *OAuth { + return &OAuth{ + cfg: cfg, + } +} + +// OAuth 管理 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2022/1/17 12:19 AM +type OAuth struct { + cfg Config +} + +// GetAuthorizationPageURL 获取授权页面的URL +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2022/1/17 12:33 AM +func (o *OAuth) GetAuthorizationPageURL(scope string, responseType string) string { + return fmt.Sprintf( + "%s%s?client_id=%s&redirect_uri=%s&scope=%s&response_type=%s", + o.cfg.Domain, + o.cfg.AuthorizationPageURI, + o.cfg.ClientID, + url.QueryEscape(o.cfg.CallbackURL), + scope, + responseType, + ) +} + +// ApplyAccessTokenByCode 通过code申请授权token +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2022/1/17 12:35 AM +func (o *OAuth) ApplyAccessTokenByCode(code string, receiver interface{}) error { + // OAuth 授权回调 + parameter := map[string]string{ + "code": code, + "client_id": o.cfg.ClientID, + "client_secret": o.cfg.ClientSecret, + "grant_type": "authorization_code", + } + client := httpclient.NewHttpClient() + client.WithHeader("Accept", "application/json") + resp, err := client.Post(o.cfg.Domain+o.cfg.GetAccessTokenURI+"?grant_type=authorization_code", parameter) + if nil != err { + return err + } + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("【%v】%v", resp.StatusCode, resp.Status) + } + body, err := io.ReadAll(resp.Body) + if nil != err { + return errors.New("读取响应体失败: " + err.Error()) + } + decoder := json.NewDecoder(bytes.NewReader(body)) + decoder.UseNumber() + return decoder.Decode(receiver) +} + +// ValidateAccessToken 验证授权token +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2022/1/17 12:43 AM +func (o *OAuth) ValidateAccessToken(token string, receiver interface{}) error { + if nil != o.cfg.FormatAccessTokenFunc { + token = o.cfg.FormatAccessTokenFunc(token) + } + parameter := make(map[string]string) + client := httpclient.NewHttpClient() + client.WithHeader("Accept", "application/json") + if o.cfg.UseAuthorization { + client.WithHeader("Authorization", "token "+token) + } else { + parameter[o.cfg.AccessTokenKey] = token + } + resp, err := client.Get("https://git.zhangdeman.cn/api/v1/user?grant_type=authorization_code", parameter) + if nil != err { + return err + } + body, err := io.ReadAll(resp.Body) + if nil != err { + return errors.New("读取响应体失败 : " + err.Error()) + } + decoder := json.NewDecoder(bytes.NewReader(body)) + decoder.UseNumber() + return decoder.Decode(receiver) +} + +// GetUserDetailByToken 根据 token 获取用户详情 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2022/1/17 12:55 AM +func (o *OAuth) GetUserDetailByToken(token string, receiver interface{}) error { + return o.ValidateAccessToken(token, receiver) +}