package oauth import ( "fmt" "time" "github.com/google/uuid" "github.com/chaitin/MonkeyCode/backend/domain" "github.com/chaitin/MonkeyCode/backend/pkg/request" ) type DingTalk struct { ClientID string ClientSecret string RedirectURI string client *request.Client } var _ domain.OAuther = &DingTalk{} func NewDingTalk(config domain.OAuthConfig) *DingTalk { client := request.NewClient("https", "api.dingtalk.com", 30*time.Second) client.SetDebug(config.Debug) return &DingTalk{ ClientID: config.ClientID, ClientSecret: config.ClientSecret, RedirectURI: config.RedirectURI, client: client, } } // GetUserInfo implements domain.OAuther. func (d *DingTalk) GetUserInfo(code string) (*domain.OAuthUserInfo, error) { accessToken, err := d.getAccessToken(code) if err != nil { return nil, err } return d.getUserInfo(accessToken) } type dingtalkAccessTokenResp struct { AccessToken string `json:"accessToken"` ExpiresIn int `json:"expireIn"` RefreshToken string `json:"refreshToken"` CorpID string `json:"corpId"` } type dingtalkAccessTokenReq struct { ClientID string `json:"clientId"` ClientSecret string `json:"clientSecret"` Code string `json:"code"` GrantType string `json:"grantType"` } func (d *DingTalk) getAccessToken(code string) (string, error) { resp, err := request.Post[dingtalkAccessTokenResp](d.client, "/v1.0/oauth2/userAccessToken", dingtalkAccessTokenReq{ ClientID: d.ClientID, ClientSecret: d.ClientSecret, Code: code, GrantType: "authorization_code", }) if err != nil { return "", err } return resp.AccessToken, nil } type dingtalkUserInfoResp struct { Nick string `json:"nick"` AvatarURL string `json:"avatarUrl"` Mobile string `json:"mobile"` OpenID string `json:"openId"` UnionID string `json:"unionId"` Email string `json:"email"` StateCode string `json:"stateCode"` } func (d *DingTalk) getUserInfo(accessToken string) (*domain.OAuthUserInfo, error) { resp, err := request.Get[dingtalkUserInfoResp](d.client, "/v1.0/contact/users/me", request.WithHeader(request.Header{ "x-acs-dingtalk-access-token": accessToken, })) if err != nil { return nil, err } return &domain.OAuthUserInfo{ ID: resp.OpenID, UnionID: resp.UnionID, Name: resp.Nick, Email: resp.Email, AvatarURL: resp.AvatarURL, }, nil } func (d *DingTalk) GetAuthorizeURL() (string, string) { state := uuid.NewString() url := fmt.Sprintf("https://login.dingtalk.com/oauth2/auth?response_type=code&scope=openid&client_id=%s&prompt=consent&state=%s&redirect_uri=%s", d.ClientID, state, d.RedirectURI) return state, url }