[TOC]git
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和源碼,那麼咱們就本身來實現
經過 access_token 和 臨時 code 獲取 unionid
的功能https://oapi.dingtalk.com/gettoken?appkey=xxx&appsecret=xxx
query
此處的 appkey
和 appsecret
是H5微應用裏面的應用數據
{ "errcode": 0, "access_token": "4dbda4ddb82dxxxxxx138afab15655", "errmsg": "ok", "expires_in": 7200 }
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
經過 access_token 和 臨時code 獲取unionid
https://oapi.dingtalk.com/sns/getuserinfo_bycode?signature=xxx×tamp=xxx&accessKey=xxx
query
accessKey
釘釘開放平臺中,登陸應用的 appId
timestamp
單位: 毫秒
signature
簽名算法爲HmacSHA256,簽名數據是當前時間戳timestamp,密鑰是appId對應的appSecret,使用密鑰對timestamp計算簽名值。
發送HTTP請求時須要把signature進行urlEncode,若是您使用的是HTTP封裝方法,請確保不要重複urlEncode
{ "tmp_auth_code":"4a2c5695b78738d495f47bxxxxxx" }
{ "errcode":0, "user_info":{ "nick":"名字", "unionid":"dingdkjjojoixxxx", "openid":"dingsdsqwlklklxxxx", "main_org_auth_high_level":true }, "errmsg":"ok" }
對於這個接口的簽名計算方式,須要給你看看是如何實現的,具體實現很簡單,可是對於時間戳的取值,須要注意是毫秒級別的
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×tamp=%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)) }
https://oapi.dingtalk.com/topapi/user/getbyunionid?access_token=xxxxxx
query
{ "unionid":"xxxxxx" }
響應
{ "errcode": 0, "errmsg": "ok", "result": { "contact_type": 0, "userid": "managerxxxx" }, "request_id": "xxxxxx" }
https://oapi.dingtalk.com/topapi/v2/user/get?access_token=xxxxx
query
{ "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
query
{ "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" }
https://oapi.dingtalk.com/topapi/user/listid?access_token=xxxxxx
query
{ "dept_id":xx }
{ "errcode": 0, "errmsg": "ok", "result": { "userid_list": [ "managerxxxxx" ] }, "request_id": "xxxxx" }
好了,本期就到這裏了,要是對你還有點做用的話,還請幫忙點贊,評論,要是可以點個關注 或 轉發到你的朋友圈,這將是對我最大的鼓勵
技術是開放的,咱們的心態更應如此,咱們擁抱變化,心向陽光,堅決不移的實踐咱們的每個想法。
做者:小魔童哪吒