最近做了個釘釘企業內部微應用的項目。記錄下自己的心得。
首先根據官方文檔明白免登流程

免登錄的流程如上。首先我們需要拿到自己企業的corpId,和corpSecret,訪問企業后台https://oa.dingtalk.com/index.htm#/microApp/microAppList登錄后就可以拿到(當然你得有管理員權限),拿到這兩個參數后,通過調用釘釘的接口,我們就可以拿到令牌了,也就是access_Token。根據官方文檔的的說明,申請一個access_Token的有效時間是兩個小時,同時該接口對每分鍾的訪問量有限制,所以最好請求到緩存在本地。代碼如下。
function getToken(){
if(Session::has('dingToken')){
$accessToken = Session::get('dingToken');
}else{
$corpId = config('ding.CorpId');
$corpSecret = config('ding.CorpSecret');
$urlToken = "https://oapi.dingtalk.com/gettoken?corpid=$corpId&corpsecret=$corpSecret";
$resToken = apiGet($urlToken);
$resToken = json_decode($resToken,true);
$accessToken = $resToken['access_token'];
Session::set('dingToken',$accessToken);
}
return $accessToken;
}
在登錄前,首先要在前端引入釘釘的js文件,以前釘釘的js是要分pc端與移動端的,引入的js也不一樣,pc端為前綴為dingTalkPc,移動端前綴為dd。但是釘釘前不久有重新更新了開發文檔,將兩種js合並在了一起,通過傳入type參數區分設備,如下圖代碼所示。
dd.config({ agentId: "{$data['agentId']}", // 必填,微應用ID corpId: "{$data['corpId']}",//必填,企業ID timeStamp: "{$data['timeStamp']}", // 必填,生成簽名的時間戳 nonceStr: "{$data['nonceStr']}", // 必填,生成簽名的隨機串 signature: "{$data['signature']}", // 必填,簽名 type:0/1, //選填。0表示微應用的jsapi,1表示服務窗的jsapi;不填默認為0。該參數從dingtalk.js的0.8.3版本開始支持 jsApiList : [ 'runtime.info', 'runtime.permission.requestAuthCode', 'device.notification.confirm', 'device.notification.alert', 'device.notification.prompt', 'biz.ding.post', 'biz.util.uploadImage', ] // 必填,需要使用的jsapi列表,注意:不要帶dd。 });
js的地址我就不寫了,開發文檔中有。上面的代碼在釘釘開發文檔中稱之為鑒權。在釘釘的api中有部分api必須是要先進行鑒權才能調用的,而有部分則不需要。為什么要說這個呢。因為有兩種免登的方式,一種比較簡單,一種比較復雜。相信你也猜到了,簡單的不需要鑒權,而復雜的需要鑒權。這兩種方式也互有利弊。
我們先來說簡單的。當我們拿到access_Token后就可以進行免登了。在頁面中引入釘釘的js文件后,調用js中的api,如下
dd.ready(function() { dd.runtime.permission.requestAuthCode({ corpId: "corpid", onSuccess: function(result) { { code: 'hYLK98jkf0m' //string authCode } }, onFail : function(err) {} }); });
這個api是不用鑒權的,需要你把corpId傳到前台來,當頁面加載完成后自動執行,執行成功后會返回code碼,值得一提的是釘釘做了限制,它的jsapi只能在釘釘應用中訪問,所以如果直接在瀏覽器中查看時沒有效果的,所以如果你要在電腦上調試,就需要下載一個RC版的釘釘,打開釘釘后,在瀏覽器中輸入http://localhost:16888/就可以在瀏覽器中看到控制台了,手機上的話同樣也有開發版的釘釘app,在app設置中打開調試模式,開啟手機usb調試權限,通過下圖中google瀏覽器的工具來捕捉輸出。
回歸正題,通過釘釘的jsapi拿到code,code也是有過期時間的,為5分鍾有效時間。拿到code后將code傳回后台加上access_Token訪問釘釘的免登api,驗證成功后返回用戶信息,其中就有用戶的唯一標識Id,再使用拿到de用戶Id加上access_Token訪問另外一個api,代碼如下。
public function getUserInfo(){ //code $data = input(); $code = $data['code']; //Access_Token $accessToken = getToken(); //userId $urlId = "https://oapi.dingtalk.com/user/getuserinfo?access_token=$accessToken&code=$code"; $resId = apiGet($urlId); $resId = json_decode($resId,true); $userId = $resId['userid']; //登錄用戶信息 $urlInfo = "https://oapi.dingtalk.com/user/get?access_token=$accessToken&userid=$userId"; $resInfo = apiGet($urlInfo); $resInfo = json_decode($resInfo); $resInfo = get_object_vars($resInfo); }
就此,免登錄完成了。當然這種方法也有缺陷,那就是返回的用戶信息比較少,不是那么全面。只能拿到如下參數

如果需要更多的用戶信息,那我們就需要進行比較復雜的免登方式了。也就是說我們在請求用戶信息前必須進行一次鑒權,才能拿到更多的用戶信息。回到拿到access_Token的開頭,我們從后端開始,從一開始的流程圖來看,鑒權需求ticket,nonceStr,timeStamp,signature,agentId,corpId這六個參數agentId和corpId是直接可以拿到的,不再贅述,ticket帶上accessToken參數通過接口獲得,noceStr用於生成密鑰的參數,我是直接給的隨機數。timeStamp當前時間戳,而
signature則是上述幾個參數通過一定算法得到。
function ddconfig(){ //Access_Token $accessToken = getToken(); // $accessToken = "08bbf680be4f3a028aa652e75a0ad754"; //ticket $urlTicket = "https://oapi.dingtalk.com/get_jsapi_ticket?access_token=$accessToken"; $resTicket = apiGet($urlTicket,false); $resTicket = json_decode($resTicket,true); $ticket = $resTicket['ticket']; //signature $nonceStr = md5(rand(10000000,99999999)); $agentId = 181397144; $timeStamp = time(); $url = get_current_url(); $plain = 'jsapi_ticket=' . $ticket . '&noncestr=' . $nonceStr . '×tamp=' . $timeStamp . '&url=' . $url; $signature = sha1($plain); $corpId = config('ding.CorpId'); $data['nonceStr'] = $nonceStr; $data['agentId'] = $agentId; $data['timeStamp'] = $timeStamp; $data['url'] = $url; $data['signature'] = $signature; $data['corpId'] = $corpId; return $data; }
拿到這幾個參數后將其返回到前端頁面。首先進行釘釘鑒權,代碼前面已經貼過,值得注意的是鑒權過程中需要初始化jsapi,只有初始化了的jsapi在后面才能被調用,鑒權后的過程就跟第一種方法一樣,拿着返回的code碼,請求userId和用戶信息。最終可以拿到用戶的完整信息。再通過與自己數據庫的數據作對比就完成了免登。
