[TOC]

OAUTH之钉钉第三方受权

hello,我是小魔童哪吒,欢送点击关注,有更新,将第一工夫出现到你的背后

胖sir:小魔童,我明天收到了一个需要,冀望咱们做一个第三方登录的性能,用户能够通过第三方受权来登录咱们的web

小魔童:啊哈?你有眉目吗

胖sir:那当然,我晓得能够通过微信登录,钉钉登录,github登录等等呢

小魔童:那你晓得都是咋实现的吗?说给我听听,让我也学一下

胖sir:你带我跑飞车吗?

小魔童:这。。 你。。 我教你如何一骑绝尘把,前提是你给我讲明确咋弄

胖sir:稳了,成交。

其实这种第三方登录的原理属于OAuth机制,次要用来颁发令牌(token),当初OAuth曾经到 OAuth2.0了

用百度百科的话说:

OAuth2.0是OAuth协定的连续版本,但不向前兼容OAuth 1.0(即齐全废止了OAuth1.0)。 OAuth 2.0关注客户端开发者的繁难性。要么通过组织在资源拥有者和HTTP服务商之间的被批准的交互动作代表用户,要么容许第三方利用代表用户取得拜访的权限。同时为Web利用,桌面利用和手机,和起居室设施提供专门的认证流程。2012年10月,OAuth 2.0协定正式公布为RFC 6749 [1] 。

次要有如下四种形式,简略给你列举一下:

  • 受权码
  • 隐藏式
  • 密码式
  • 客户端凭证

画一个简图来你感受一下

当然我不是给你说OAuth本身的原理和波及的技术,我是要来间接给你说咱们咋实现我方才说的对接钉钉的接口,因为钉钉的开发文档两头有批改过好几次,

另外文档中的表述也存在艰涩难懂的中央,鉴于你带我飞车 一骑绝尘,我就给你说说 如何获取到钉钉的受权,以及拿到应用钉钉对应公司(必须有公司管理员的权限)下的组织构造

钉钉开发文档没有golang版本的SDK和源码,那么咱们就本人来实现

后期用到的工具

  • postman 做接口调试
  • golang 语言 通过 goland 编译器 做 通过 access_token 和 长期 code 获取 unionid 的性能

获取access_token

申请地址

https://oapi.dingtalk.com/gettoken?appkey=xxx&appsecret=xxx

申请办法

  • GET
  • query

    • appkey
    • appsecret

此处的 appkeyappsecret 是H5微利用外面的利用数据

响应

{    "errcode": 0,    "access_token": "4dbda4ddb82dxxxxxx138afab15655",    "errmsg": "ok",    "expires_in": 7200}

扫码 / 应用账号密码 -- 获取 长期 code

参数重要阐明

  • appId

    登录利用的 appId

  • redirect_uri - 回调域名

    重定向的url地址,登录胜利后,网页会重定向到redirect_uri

    redirect_uri 必须要在钉钉开放平台配置好,否则会没有权限拜访如下地址 ,例如该参数填百度的地址

  • LOGO地址

    本人在网络上的一张能够拜访的图片地址即可,如下:

间接拜访 扫码登录

https://oapi.dingtalk.com/connect/qrconnect?appid=xxxx&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=https://www.baidu.com/

应用账号密码登录第三方网站

https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=xxx&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=https://www.baidu.com/

如上2种形式登录胜利后,是如下成果,临时咱们应用跳转的域名为https://www.baidu.com/ 次要是为了获取 长期code

依据 sns 长期受权码获取用户信息

通过 access_token 和 长期code 获取unionid

前置条件

  • 须要在钉钉开放平台上设置本人的服务器的进口ip白名单

申请地址

https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature=xxx&timestamp=xxx&accessKey=xxx
  • POST
  • query

    • accessKey

      钉钉开放平台中,登录利用的 appId

    • timestamp

      单位: 毫秒

    • signature

      签名算法为HmacSHA256,签名数据是以后工夫戳timestamp,密钥是appId对应的appSecret,应用密钥对timestamp计算签名值。

      发送HTTP申请时须要把signature进行urlEncode,如果您应用的是HTTP封装办法,请确保不要反复urlEncode

  • body
{        "tmp_auth_code":"4a2c5695b78738d495f47bxxxxxx"}

响应

{        "errcode":0,        "user_info":{                "nick":"名字",                "unionid":"dingdkjjojoixxxx",                "openid":"dingsdsqwlklklxxxx",                "main_org_auth_high_level":true        },        "errmsg":"ok"}

golang 具体操作和逻辑

对于这个接口的签名计算形式,须要给你看看是如何实现的,具体实现很简略,然而对于工夫戳的取值,须要留神是毫秒级别的

package mainimport (    "bytes"    "crypto/hmac"    "crypto/sha256"    "crypto/tls"    "encoding/base64"    "encoding/json"    "fmt"    "io/ioutil"    "net/http"    "net/url"    "time")func main() {    // 登录利用的 appSecret    secret := "xxxx"    key := []byte(secret)    h := hmac.New(sha256.New, key)    timestamp := time.Now().UnixNano()/1e6 + 120000 //因为我的环境工夫比钉钉服务器慢2分钟,所以我这里加了2分钟    strTimeStamp := fmt.Sprintf("%d", timestamp)    h.Write([]byte(strTimeStamp))    sha := h.Sum(nil)    sig := base64.StdEncoding.EncodeToString(sha)    mysig := url.QueryEscape(sig)    url := fmt.Sprintf("https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature=%s&timestamp=%d&accessKey=%s",        mysig, timestamp, "xxxx")    fmt.Println(url)    tr := &http.Transport{        TLSClientConfig: &tls.Config{InsecureSkipVerify: true},    }    spaceClient := http.Client{Timeout: time.Second * time.Duration(5), Transport: tr}    m := map[string]string{"tmp_auth_code": "67d86cb135ee3bd18d756c2d2fa1a350"}    res, err := json.Marshal(m)    if err != nil {        fmt.Println(res)        return    }    fmt.Println(string(res))    req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(res))    req.Header.Set("Content-Type", "application/json")    rawResp, err := spaceClient.Do(req)    if err != nil {        fmt.Println(rawResp)        return    }    if rawResp.Status != "200 OK" {        fmt.Println("rawResp.Status != 200 ok", rawResp)        return    }    body, readErr := ioutil.ReadAll(rawResp.Body)    if readErr != nil {        fmt.Println("ReadAll error ", readErr)        return    }    fmt.Println("result --", string(body))}

依据 unionid 获取用户 userid

申请地址

https://oapi.dingtalk.com/topapi/user/getbyunionid?access_token=xxxxxx

申请办法

  • POST
  • query

    • access_token
  • body 申请
{ "unionid":"xxxxxx"}

响应

{    "errcode": 0,    "errmsg": "ok",    "result": {        "contact_type": 0,        "userid": "managerxxxx"    },    "request_id": "xxxxxx"}

依据userid 获取 用户详情

申请地址

https://oapi.dingtalk.com/topapi/v2/user/get?access_token=xxxxx

申请办法

  • POST
  • query

    • access_token
  • body 申请
{   "language":"zh_CN",   "userid":"managerxxxxx"}

响应

{    "errcode": 0,    "errmsg": "ok",    "result": {        "active": true,        "admin": true,        "avatar": "",        "boss": false,        "dept_id_list": [            1        ],        "dept_order_list": [            {                "dept_id": 1,                "order": 176299320823645512            }        ],        "email": "",        "exclusive_account": false,        "hide_mobile": false,        "leader_in_dept": [            {                "dept_id": 1,                "leader": false            }        ],        "mobile": "xxxxx",        "name": "xxx",        "real_authed": true,        "role_list": [            {                "group_name": "默认",                "id": 1993003008,                "name": "主管理员"            }        ],        "senior": false,        "state_code": "86",        "unionid": "xxxxx",        "userid": "managerxxxxx"    },    "request_id": "xxxxx"}

获取部门列表

申请地址

https://oapi.dingtalk.com/topapi/v2/department/listsub?access_token=xxxxx

申请办法

  • POST
  • query

    • access_token
  • body申请
{        "language":"zh_CN",        "dept_id":1}

响应

{    "errcode": 0,    "errmsg": "ok",    "result": [        {            "auto_add_user": true,            "create_dept_group": true,            "dept_id": 477856721,            "name": "运营部",            "parent_id": 1        },        {            "auto_add_user": true,            "create_dept_group": true,            "dept_id": 477856722,            "name": "设计部",            "parent_id": 1        }    ],    "request_id": "evcmse04h8op"}

获取部门用户 userid 列表

申请地址

https://oapi.dingtalk.com/topapi/user/listid?access_token=xxxxxx

申请办法

  • POST
  • query

    • access_token
  • body 申请
{ "dept_id":xx}

响应

{    "errcode": 0,    "errmsg": "ok",    "result": {        "userid_list": [            "managerxxxxx"        ]    },    "request_id": "xxxxx"}

好了,本期就到这里了,要是对你还有点作用的话,还请帮忙点赞,评论,要是可能点个关注 或 转发到你的朋友圈,这将是对我最大的激励

技术是凋谢的,咱们的心态更应如此,咱们拥抱变动,心向阳光,坚韧不拔的实际咱们的每一个想法。

作者:小魔童哪吒