123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- package dingtalk
- import (
- "crypto/hmac"
- "crypto/sha256"
- "encoding/base64"
- "encoding/json"
- "errors"
- "fmt"
- "io/ioutil"
- "net/http"
- "net/url"
- "strconv"
- "strings"
- "time"
- )
- // DingTalkAgent 用于钉钉交互
- type DingTalkAgent struct {
- AppSecret string
- AppKey string
- AccessToken string
- }
- // NewDingTalkAgent 钉钉交互构造函数
- func NewDingTalkAgent(appSecret, appKey string) *DingTalkAgent {
- return &DingTalkAgent{
- AppSecret: appSecret,
- AppKey: appKey,
- }
- }
- // GetUserIDByCode 通过临时code获取当前用户ID
- func (d *DingTalkAgent) GetUserIDByCode(code string) (string, error) {
- urlEndpoint, err := url.Parse("https://oapi.dingtalk.com/user/getuserinfo")
- if err != nil {
- return "", err
- }
- query := url.Values{}
- query.Set("access_token", d.AccessToken)
- query.Set("code", code)
- urlEndpoint.RawQuery = query.Encode()
- urlPath := urlEndpoint.String()
- resp, err := http.Get(urlPath)
- if err != nil {
- return "", err
- }
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return "", err
- }
- // 解析钉钉返回数据
- var rdata map[string]interface{}
- err = json.Unmarshal(body, &rdata)
- if err != nil {
- return "", err
- }
- errcode := rdata["errcode"].(float64)
- if errcode != 0 {
- return "", fmt.Errorf("登录错误: %.0f, %s", errcode, rdata["errmsg"].(string))
- }
- userid := rdata["userid"].(string)
- return userid, nil
- }
- // GetUserNameAndAvatarByUserID 通过userid获取当前用户姓名和头像
- func (d *DingTalkAgent) GetUserNameAndAvatarByUserID(userid string) (string, string, error) {
- urlEndpoint, err := url.Parse("https://oapi.dingtalk.com/topapi/v2/user/get")
- if err != nil {
- return "", "", err
- }
- query := url.Values{}
- query.Set("access_token", d.AccessToken)
- urlEndpoint.RawQuery = query.Encode()
- urlPath := urlEndpoint.String()
- resp, err := http.PostForm(urlPath, url.Values{"userid": {userid}})
- if err != nil {
- return "", "", err
- }
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return "", "", err
- }
- // 解析钉钉返回数据
- var rdata map[string]interface{}
- err = json.Unmarshal(body, &rdata)
- if err != nil {
- return "", "", err
- }
- errcode := rdata["errcode"].(float64)
- if errcode != 0 {
- return "", "", fmt.Errorf("登录错误: %.0f, %s", errcode, rdata["errmsg"].(string))
- }
- userinfo := rdata["result"].(map[string]interface{})
- username := userinfo["name"].(string)
- avatar := userinfo["avatar"].(string)
- return username, avatar, nil
- }
- // GetUserIDByUnionID 根据UnionID获取用户Userid
- func (d *DingTalkAgent) GetUserIDByUnionID(unionid string) (string, error) {
- urlEndpoint, err := url.Parse("https://oapi.dingtalk.com/topapi/user/getbyunionid")
- if err != nil {
- return "", err
- }
- query := url.Values{}
- query.Set("access_token", d.AccessToken)
- urlEndpoint.RawQuery = query.Encode()
- urlPath := urlEndpoint.String()
- resp, err := http.PostForm(urlPath, url.Values{"unionid": {unionid}})
- if err != nil {
- return "", err
- }
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return "", err
- }
- // 解析钉钉返回数据
- var rdata map[string]interface{}
- err = json.Unmarshal(body, &rdata)
- if err != nil {
- return "", err
- }
- errcode := rdata["errcode"].(float64)
- if errcode != 0 {
- return "", fmt.Errorf("登录错误: %.0f, %s", errcode, rdata["errmsg"].(string))
- }
- result := rdata["result"].(map[string]interface{})
- if result["contact_type"].(float64) != 0 {
- return "", errors.New("该用户不属于企业内部员工,无法登录。")
- }
- userid := result["userid"].(string)
- return userid, nil
- }
- // GetAccesstoken 获取钉钉请求Token
- func (d *DingTalkAgent) GetAccesstoken() (err error) {
- url := fmt.Sprintf("https://oapi.dingtalk.com/gettoken?appkey=%s&appsecret=%s", d.AppKey, d.AppSecret)
- resp, err := http.Get(url)
- if err != nil {
- return err
- }
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return err
- }
- var i map[string]interface{}
- err = json.Unmarshal(body, &i)
- if err != nil {
- return err
- }
- if i["errcode"].(float64) == 0 {
- d.AccessToken = i["access_token"].(string)
- return nil
- }
- return errors.New("accesstoken获取错误:" + i["errmsg"].(string))
- }
- // DingtalkQRLogin 用于钉钉扫码登录
- type DingtalkQRLogin struct {
- AppSecret string
- AppKey string
- }
- // NewDingtalkQRLogin 构造钉钉扫码登录实例
- func NewDingtalkQRLogin(appSecret, appKey string) DingtalkQRLogin {
- return DingtalkQRLogin{
- AppSecret: appSecret,
- AppKey: appKey,
- }
- }
- // GetUnionIDByCode 获取扫码用户UnionID
- func (d *DingtalkQRLogin) GetUnionIDByCode(code string) (userid string, err error) {
- var resp *http.Response
- //服务端通过临时授权码获取授权用户的个人信息
- timestamp := strconv.FormatInt(time.Now().UnixNano()/1000000, 10) // 毫秒时间戳
- signature := d.encodeSHA256(timestamp) // 加密签名
- urlPath := fmt.Sprintf(
- "https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=%s×tamp=%s&signature=%s",
- d.AppKey, timestamp, signature)
- // 构造请求数据
- param := struct {
- Tmp_auth_code string `json:"tmp_auth_code"`
- }{code}
- paraByte, _ := json.Marshal(param)
- paraString := string(paraByte)
- resp, err = http.Post(urlPath, "application/json;charset=UTF-8", strings.NewReader(paraString))
- if err != nil {
- return "", err
- }
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return "", err
- }
- // 解析钉钉返回数据
- var rdata map[string]interface{}
- err = json.Unmarshal(body, &rdata)
- if err != nil {
- return "", err
- }
- errcode := rdata["errcode"].(float64)
- if errcode != 0 {
- return "", fmt.Errorf("登录错误: %.0f, %s", errcode, rdata["errmsg"].(string))
- }
- unionid := rdata["user_info"].(map[string]interface{})["unionid"].(string)
- return unionid, nil
- }
- func (d *DingtalkQRLogin) encodeSHA256(timestamp string) string {
- // 钉钉签名算法实现
- h := hmac.New(sha256.New, []byte(d.AppSecret))
- h.Write([]byte(timestamp))
- sum := h.Sum(nil) // 二进制流
- tmpMsg := base64.StdEncoding.EncodeToString(sum)
- uv := url.Values{}
- uv.Add("0", tmpMsg)
- message := uv.Encode()[2:]
- return message
- }
|