Files
MonkeyCode/backend/pkg/oauth/dingtalk.go
2025-07-01 21:08:30 +08:00

100 lines
2.6 KiB
Go

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
}