diff --git a/idp/dingtalk.go b/idp/dingtalk.go index 5b782f9e..2b76a0a7 100644 --- a/idp/dingtalk.go +++ b/idp/dingtalk.go @@ -15,11 +15,9 @@ package idp import ( - "bytes" "encoding/json" "fmt" "io" - "io/ioutil" "log" "net/http" "strings" @@ -170,10 +168,18 @@ func (idp *DingTalkIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro Email: dtUserInfo.Email, AvatarUrl: dtUserInfo.AvatarUrl, } - isUserInOrg, err := idp.isUserInOrg(userInfo.UnionId) - if !isUserInOrg { + + corpAccessToken := idp.getInnerAppAccessToken() + userId, err := idp.getUserId(userInfo.UnionId, corpAccessToken) + if err != nil { return nil, err } + + corpEmail, err := idp.getUserCorpEmail(userId, corpAccessToken) + if err == nil && corpEmail != "" { + userInfo.Email = corpEmail + } + return &userInfo, nil } @@ -202,23 +208,14 @@ func (idp *DingTalkIdProvider) postWithBody(body interface{}, url string) ([]byt } func (idp *DingTalkIdProvider) getInnerAppAccessToken() string { - appKey := idp.Config.ClientID - appSecret := idp.Config.ClientSecret body := make(map[string]string) - body["appKey"] = appKey - body["appSecret"] = appSecret - bodyData, err := json.Marshal(body) - if err != nil { - log.Println(err.Error()) - } - reader := bytes.NewReader(bodyData) - request, err := http.NewRequest("POST", "https://api.dingtalk.com/v1.0/oauth2/accessToken", reader) - request.Header.Set("Content-Type", "application/json;charset=UTF-8") - resp, err := idp.Client.Do(request) - respBytes, err := ioutil.ReadAll(resp.Body) + body["appKey"] = idp.Config.ClientID + body["appSecret"] = idp.Config.ClientSecret + respBytes, err := idp.postWithBody(body, "https://api.dingtalk.com/v1.0/oauth2/accessToken") if err != nil { log.Println(err.Error()) } + var data struct { ExpireIn int `json:"expireIn"` AccessToken string `json:"accessToken"` @@ -230,34 +227,53 @@ func (idp *DingTalkIdProvider) getInnerAppAccessToken() string { return data.AccessToken } -func (idp *DingTalkIdProvider) isUserInOrg(unionId string) (bool, error) { +func (idp *DingTalkIdProvider) getUserId(unionId string, accessToken string) (string, error) { body := make(map[string]string) body["unionid"] = unionId - bodyData, err := json.Marshal(body) + respBytes, err := idp.postWithBody(body, "https://oapi.dingtalk.com/topapi/user/getbyunionid?access_token="+accessToken) if err != nil { - log.Println(err.Error()) - } - reader := bytes.NewReader(bodyData) - accessToken := idp.getInnerAppAccessToken() - request, _ := http.NewRequest("POST", "https://oapi.dingtalk.com/topapi/user/getbyunionid?access_token="+accessToken, reader) - request.Header.Set("Content-Type", "application/json;charset=UTF-8") - resp, err := idp.Client.Do(request) - respBytes, err := ioutil.ReadAll(resp.Body) - if err != nil { - log.Println(err.Error()) + return "", err } + var data struct { ErrCode int `json:"errcode"` ErrMessage string `json:"errmsg"` + Result struct { + UserId string `json:"userid"` + } `json:"result"` } err = json.Unmarshal(respBytes, &data) if err != nil { - log.Println(err.Error()) + return "", err } if data.ErrCode == 60121 { - return false, fmt.Errorf("the user is not found in the organization where clientId and clientSecret belong") + return "", fmt.Errorf("the user is not found in the organization where clientId and clientSecret belong") } else if data.ErrCode != 0 { - return false, fmt.Errorf(data.ErrMessage) + return "", fmt.Errorf(data.ErrMessage) } - return true, nil + return data.Result.UserId, nil +} + +func (idp *DingTalkIdProvider) getUserCorpEmail(userId string, accessToken string) (string, error) { + body := make(map[string]string) + body["userid"] = userId + respBytes, err := idp.postWithBody(body, "https://oapi.dingtalk.com/topapi/v2/user/get?access_token="+accessToken) + if err != nil { + return "", err + } + + var data struct { + ErrMessage string `json:"errmsg"` + Result struct { + Email string `json:"email"` + } `json:"result"` + } + err = json.Unmarshal(respBytes, &data) + if err != nil { + return "", err + } + if data.ErrMessage != "ok" { + return "", fmt.Errorf(data.ErrMessage) + } + return data.Result.Email, nil }