package auth import ( "context" "net/url" "git.esin.io/lab/weixin/clientapi/request" ) type Config struct { ClientID string ClientSecret string } type Client struct { appId string appSecret string } func NewClient(cfg *Config) *Client { return &Client{ appId: cfg.ClientID, appSecret: cfg.ClientSecret, } } type Scope string const ( ScopeBase Scope = "snsapi_base" ScopeUserinfo Scope = "snsapi_userinfo" ) func (scope Scope) String() string { return string(scope) } func (c Client) GetCodeURL(redirectURL, state string, scope Scope) string { endpoint := url.URL{ Scheme: "https", Host: "open.weixin.qq.com", Path: "/connect/oauth2/authorize", RawQuery: url.Values{ "appid": {c.appId}, "redirect_uri": {redirectURL}, "response_type": {"code"}, "scope": {scope.String()}, "state": {state}, }.Encode(), Fragment: "wechat_redirect", } return endpoint.String() } func (c Client) ExchangeToken(ctx context.Context, code string) (*Token, error) { req := request.New( "/sns/oauth2/access_token", url.Values{ "grant_type": {"authorization_code"}, "appid": {c.appId}, "secret": {c.appSecret}, "code": {code}, }) var resp Token if err := req.Get(ctx, &resp); err != nil { return nil, err } if err := resp.Err(); err != nil { return nil, err } return &resp, nil } type Lang string const ( LangZhCN Lang = "zh_CN" LangZhTW Lang = "zh_TW" LangEn Lang = "en" ) func (lang Lang) String() string { return string(lang) } func (c Client) GetUserinfo(ctx context.Context, accessToken, openid string, lang Lang) (*Userinfo, error) { req := request.New( "/sns/userinfo", url.Values{ "access_token": {accessToken}, "openid": {openid}, "lang": {"zh_CN"}, }, ) var resp Userinfo if err := req.Get(ctx, &resp); err != nil { return nil, err } if err := resp.Err(); err != nil { return nil, err } return &resp, nil } func (c Client) RefreshToken(ctx context.Context, refreshToken string) (*Token, error) { req := request.New( "/sns/oauth2/refresh_token", url.Values{ "grant_type": {"refresh_token"}, "appid": {c.appId}, "refresh_token": {refreshToken}, }, ) var resp Token if err := req.Get(ctx, &resp); err != nil { return nil, err } if err := resp.Err(); err != nil { return nil, err } return &resp, nil } func (c Client) ValidateToken(ctx context.Context, accessToken, openid string) error { req := request.New( "/sns/auth", url.Values{ "access_token": {accessToken}, "openid": {openid}, }, ) var resp request.Error if err := req.Get(ctx, &resp); err != nil { return err } if err := resp.Err(); err != nil { return err } return nil } func (c Client) GetClientCredential(ctx context.Context) (*ClientCredential, error) { req := request.New( "/cgi-bin/token", url.Values{ "grant_type": {"client_credential"}, "appid": {c.appId}, "secret": {c.appSecret}, }, ) var resp ClientCredential if err := req.Get(ctx, &resp); err != nil { return nil, err } if err := resp.Err(); err != nil { return nil, err } return &resp, nil }