釘釘掃碼登錄-PHP版本
- 2020 年 4 月 10 日
- 筆記
今天寫了一個第三方登錄的功能,使用的是釘釘,實現的功能就是打開網頁,使用的釘釘APP掃描二維碼,快捷登錄網站,下面一起來看一下!
釘釘開放平台
首先,登錄管理後台,點擊右上角進行登錄,這裡的登錄需要是管理員身份或者授權許可權的子管理員身份,其他的身份不好使,如果沒有管理員身份或子管理員身份(如我一樣),那麼就只能自己創建一個團隊了,裡面邀請了好友就可以了。這樣你就是擁有管理員身份了。繼而可以登錄這個管理後台了(第一次登錄需要設置個密碼,後續登錄時需要輸入的)。
創建應用
進入管理頁面後,我們進入應用開發菜單,找到最下方的「移動接入應用」,進入子級菜單中的「登錄」,在裡面創建一個應用。如下圖:

創建應用後,回到頁面中,我們可以看到 appid 和 appSecret 這兩項參數,後續我們會用到。
授權流程
第三方發起釘釘授權登錄請求,釘釘用戶允許授權第三方應用後,釘釘會拉起應用或重定向到第三方網站,並且帶上授權臨時票據code參數。
通過code調用介面getuserinfo_bycode獲取授權登錄用戶資訊。

構造掃碼登錄頁面
構建登錄頁面有兩種方式,我們以跳轉方式為例,這種方式使用得較多,也非常方便。在企業Web系統里,用戶點擊使用釘釘掃描登錄,第三方Web系統跳轉到如下地址:地址就不做展示了,說一下地址的參數:

獲取用戶資訊
首先說一下,我們獲取到的用戶資訊只有三項,如下表:

但是在下午的實際測試中發現,介面返回的值還多了兩項,文檔中沒有做出說明,猜測是許可權欄位和許可權標識欄位。
在獲取用戶資訊時我們要使用到的參數有如下:

在請求的時候需要使用POST方式並傳遞數據,數據如下:
{"tmp_auth_code": "23152698ea18304da4d0ce1xxxxx"}
這裡需要注意一點,傳遞數據為json格式,如果使用CURL進行請求時會出現post請求數據格式錯誤的提示,我們需要在curl請求頭上面做出說明,程式碼如下:
$header = [ "Content-Type: application/json; charset=utf-8", "Content-Length:" . strlen(json_encode($postFields)) ]; curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
程式碼
<?php /** * Created by PhpStorm. * User: Administrator * Date: 2020/4/3 0003 * Time: 11:27 */ namespace appcontroller; use thinkController; class Login extends Controller { /** * 登錄 * @return thinkresponseView */ public function index() { // 臨時關閉模板布局 $this->view->engine->layout(false); return view("login/index"); } public function out() { } public function back() { $code = input('get.code'); $state = input('get.state'); if(!$code or !$state) { $this->error('參數缺失'); } if($state > time()) { $this->error('參數異常'); } $accessKey = 'dingoa9f8qj1**********'; $timestamp = $this->mTime(); $signature = $this->signature($timestamp); $url = 'https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=' . $accessKey . '×tamp=' . $timestamp . '&signature=' . $signature; $data = [ 'tmp_auth_code' => $code ]; $userInfo = $this->curl_json($url, $data); $res = json_decode($userInfo, true); if(isset($res['errcode']) and $res['errcode'] == 0) { //登錄成功 echo 1; } } /** * 計算簽名 * @param $timestamp * @return string */ public function signature($timestamp) { // 根據timestamp, appSecret計算簽名值 $s = hash_hmac('sha256', $timestamp, '**********G6KaiRey7NFJxXHyBthsPL5Q4rBSvlJhQvREadhO__uHhDs', true); $signature = base64_encode($s); $urlEncode_signature = urlencode($signature); return $urlEncode_signature; } /** * 毫秒級時間戳 * @return float */ public function mTime() { list($s1, $s2) = explode(' ', microtime()); $mTime = (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000); return $mTime; } public function curl_json($url, $postFields = null) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_FAILONERROR, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, "dingtalk-sdk-php"); //https 請求 if(strlen($url) > 5 && strtolower(substr($url, 0, 5)) == "https") { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); } curl_setopt($ch, CURLOPT_POST, true); $header = [ "Content-Type: application/json; charset=utf-8", "Content-Length:" . strlen(json_encode($postFields)) ]; curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields)); $reponse = curl_exec($ch); if(curl_errno($ch)) { throw new Exception(curl_error($ch), 0); } else { $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if(200 !== $httpStatusCode) { throw new Exception($reponse, $httpStatusCode); } } curl_close($ch); return $reponse; } }