github.com/infraboard/keyauth@v0.8.1/apps/provider/auth/dingtalk/auth.go (about) 1 package dingtalk 2 3 import ( 4 "bytes" 5 "crypto/hmac" 6 "crypto/sha256" 7 "encoding/base64" 8 "encoding/json" 9 "fmt" 10 "io/ioutil" 11 "net/http" 12 "net/url" 13 "strconv" 14 "time" 15 16 "github.com/infraboard/keyauth/apps/provider/auth" 17 "github.com/infraboard/mcube/logger/zap" 18 ) 19 20 var ( 21 client = &http.Client{} 22 ) 23 24 type Response struct { 25 ErrCode int64 `json:"errcode"` 26 ErrMsg string `json:"errmsg"` 27 UserInfo UserInfo `json:"user_info"` 28 } 29 30 type UserInfo struct { 31 Nick string `json:"nick"` 32 OpenID string `json:"openid"` 33 UnionID string `json:"unionid"` 34 } 35 36 type Dingtalk struct { 37 AppID string `json:"app_id" bson:"app_id"` 38 AppSecret string `json:"app_secret" bson:"app_secret"` 39 } 40 41 func (a *Dingtalk) getSignature(msg []byte) string { 42 hmac := hmac.New(sha256.New, []byte(a.AppSecret)) 43 _, err := hmac.Write(msg) 44 if err != nil { 45 zap.L().Errorf("GetSignature hmac.Write error", err) 46 } 47 digest := hmac.Sum(nil) 48 return url.QueryEscape(base64.StdEncoding.EncodeToString(digest)) 49 } 50 51 func (a *Dingtalk) accessTokenURL() string { 52 timestamp := strconv.FormatInt(time.Now().UnixNano()/1e6, 10) 53 signature := a.getSignature([]byte(timestamp)) 54 accessTokenURL := fmt.Sprintf("https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=%s×tamp=%s&signature=%s", 55 a.AppID, 56 timestamp, 57 signature) 58 return accessTokenURL 59 } 60 61 // https://ding-doc.dingtalk.com/doc#/serverapi3/mrugr3 62 // Step 1: To https://oapi.dingtalk.com/connect/qrconnect?appid=APPID&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=REDIRECT_URI 63 // Step 2.2: Within Callback, get user_info.nick 64 // POST HTTPS with body { "tmp_auth_code": "23152698ea18304da4d0ce1xxxxx" } == code ? 65 // https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=xxx×tamp=xxx&signature=xxx 66 // accessKey=appid 67 // https://ding-doc.dingtalk.com/doc#/serverapi2/kymkv6 68 func (a *Dingtalk) CodeAuth(req *auth.AuthCodeRequest) error { 69 body := fmt.Sprintf(`{"tmp_auth_code": "%s"}`, req.Code) 70 request, _ := http.NewRequest("POST", a.accessTokenURL(), bytes.NewReader([]byte(body))) 71 request.Header.Set("Content-Type", "application/json") 72 // 发起请求 73 resp, err := client.Do(request) 74 if err != nil { 75 return err 76 } 77 defer resp.Body.Close() 78 79 // 处理响应 80 b, err := ioutil.ReadAll(resp.Body) 81 if err != nil { 82 return err 83 } 84 zap.L().Debugf("dingding oauthcode request, req: %s [%s], response: %s", request, string(b)) 85 86 if (resp.StatusCode / 100) != 2 { 87 return fmt.Errorf("status code: %d, %s", resp.StatusCode, string(b)) 88 } 89 90 ins := Response{} 91 err = json.Unmarshal(b, &ins) 92 if err != nil { 93 return err 94 } 95 96 return nil 97 }