OAUTH之釘釘第三方受權

[TOC]git

OAUTH之釘釘第三方受權

hello,我是小魔童哪吒,歡迎點擊關注,有更新,將第一時間呈現到你的面前github

胖sir:小魔童,我今天收到了一個需求,指望咱們作一個第三方登陸的功能,用戶能夠經過第三方受權來登陸咱們的webgolang

小魔童:啊哈?你有眉目嗎web

胖sir:那固然,我知道能夠經過微信登陸,釘釘登陸,github登陸等等呢算法

小魔童:那你知道都是咋實現的嗎?說給我聽聽,讓我也學一下json

胖sir:你帶我跑飛車嗎?api

小魔童:這。。 你。。 我教你如何一騎絕塵把,前提是你給我講明白咋弄服務器

胖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 main

import (
    "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"
}

好了,本期就到這裏了,要是對你還有點做用的話,還請幫忙點贊,評論,要是可以點個關注 或 轉發到你的朋友圈,這將是對我最大的鼓勵

技術是開放的,咱們的心態更應如此,咱們擁抱變化,心向陽光,堅決不移的實踐咱們的每個想法。

做者:小魔童哪吒

相關文章
相關標籤/搜索