釘釘二次開發分為如下表所示三種類型的開發,只有企業內部應用才需要對JSAPI鑒權。
類型 |
開發方式 |
JSAPI鑒權 |
應用場景 |
第三方企業應用 |
E應用開發 |
不需要 |
用於發布到釘釘應用市場,供廣大用戶下載,應用可選收費或免費,需要收取保證金,並進行應用審核 |
企業內部應用 |
H5開發,8月中旬也開始支持E應用開發 |
需要 |
只能企業內部應用,不能發布到釘釘市場 |
第三方個人應用 |
E應用開發 |
需要 |
應用與企業不掛鈎,服務於個人 |
先來看一下釘釘官網給出的JSAPI鑒權的流程,它分為四個步驟:
- 獲取token
- 獲取ticket
- 獲取數字簽名
- 設置權限
查看釘釘開發文檔,它給出了兩個JSAPI的鑒權demo,分別是java和php的,需要前后端配合,而本文講述的是純前端JSAPI鑒權,完全實現前后端分離。
下面的代碼將用到以下三個js依賴包:
import CryptoJS from 'crypto-js'; // 加密,用於生成數字簽名 import * as dd from "dingtalk-jsapi"; // 釘釘JSAPI import axios from "axios"; // HTTP請求
提示:下面的代碼,用了ES6和ES7的一些語法,沒接觸過的朋友,可自行百度
1、獲取token
首先根據corpid和corpsecret參數,從釘釘服務器獲取token。
/** * 獲取token信息 * @param {Object} params {corpid, corpsecret} */ async function getToken(params) { return await axios.get('/proxy/gettoken', { params }) .then(function(response) { return response.data.access_token; }); }
細心的朋友會發現,axios請求的URL並沒有直接指定 https://oapi.dingtalk.com/gettoken,這是因為直接寫這個URL,會存在跨域問題,因此,這里我們用了代理。
代理可以采用nginx代理或者node代理,這里推薦用node代理。
因為需要代理的請求是https請求,本人也沒跑通nginx代理https請求,如果有哪位朋友跑通了nginx代理的,麻煩告知一聲,也學習以下。
2、設置代理
如果采用vue-cli創建的項目,可以直接在proxyTable中配置,如下:
proxyTable: { '/proxy': { target: 'https://oapi.dingtalk.com', secure: false, // 設置跨域 changeOrigin: true, pathRewrite: { '^/proxy': '' } } }
不過上面的配置只能在dev開發環境中使用,如果需要在生產環境中使用,還是需要自己寫nodejs代碼實現,如下:
var express = require('express'); var proxy = require('http-proxy-middleware'); var app = express(); app.use('/proxy', proxy({ target: 'https://oapi.dingtalk.com', changeOrigin: true, pathRewrite: { '^/proxy': '' } })); app.listen(3000);
這代碼量是不是很少,隨便百度下都搞定。
3、獲取ticket
根據上面獲取的access_token,從釘釘服務器獲取ticket。
/** * 獲取ticket信息 * @param {Object} params {access_token} */ async function getJsticket(params) { return await axios.get('/proxy/get_jsapi_ticket', { params }) .then(function(response) { return response.data.ticket; }); }
4、獲取數字簽名
釘釘官網的demo是后台實現生成數字簽名,通過crypto-js前端加密庫就可以將這個功能移植到前端來。
ticket是上面生成的;
nonce可以是任何字符串;
timeStamp是當前時間戳;
url是當前訪問的URL地址,不包括#及后面的部分,特別注意這個參數,別搞錯了。如果設置錯了,可以通過下面的dd.error輸出查看釘釘服務器獲取的URL地址
/** * 獲取簽名信息 * @param {*} ticket * @param {*} nonce * @param {*} timeStamp * @param {*} url */ function getJsApiSingnature(ticket, nonce, timeStamp, url) { let plainTex = "jsapi_ticket=" + ticket + "&noncestr=" + nonce + "×tamp=" + timeStamp + "&url=" + url; let signature = CryptoJS.SHA1(plainTex).toString(); return signature; }
5、設置權限
通過dd.config設置需要的權限
// 步驟4:設置權限 dd.config({ agentId: agentId, corpId: corpid, //必填,企業ID timeStamp: timeStamp, // 必填,生成簽名的時間戳 nonceStr: nonce, // 必填,生成簽名的隨機串 signature: signature, // 必填,簽名 jsApiList: jsApiList // 必填,需要使用的jsapi列表,注意:不要帶dd。 });
jsApiList是權限列表,如:
var jsApiList = [ 'biz.user.get', 'device.geolocation.get', 'biz.util.uploadImage' ];
6、驗證
上面配置成功之后,就能調用JSAPI中需要鑒權的功能了,下面以獲取當前地理位置為例說明:
/** * 測試代碼,通過調用位置服務,測試鑒權是否正確 */ function testJsApi() { // 獲取位置 dd.ready(() => { dd.device.geolocation.get({ targetAccuracy: 200, coordinate: 1, withReGeocode: false, useCache: true, //默認是true,如果需要頻繁獲取地理位置,請設置false, onSuccess: result => { /* 高德坐標 result 結構 { longitude : Number, latitude : Number, accuracy : Number, address : String, province : String, city : String, district : String, road : String, netType : String, operatorType : String, errorMessage : String, errorCode : Number, isWifiEnabled : Boolean, isGpsEnabled : Boolean, isFromMock : Boolean, provider : wifi|lbs|gps, accuracy : Number, isMobileEnabled : Boolean } */ console.log(result) alert("success: " + JSON.stringify(result)) }, onFail: err => { console.log(err) alert("error: " + JSON.stringify(err)) } }); }); // 查看鑒權錯誤信息 dd.error(function(err) { alert('dd error: ' + JSON.stringify(err)); }); }
如果鑒權失敗,則dd.error將輸出釘釘服務器采用的數字簽名參數,可以與自己采用的參數做比較
附:串起來的代碼
async function getAccessToken() { // 步驟1:獲取token let access_token = await getToken({ corpid, corpsecret }); // 步驟2:獲取ticket let ticket = await getJsticket({ access_token }); // 步驟3:獲取數字簽名 let signature = getJsApiSingnature(ticket, nonce, timeStamp, url); // 步驟4:設置權限 dd.config({ agentId: agentId, corpId: corpid, //必填,企業ID timeStamp: timeStamp, // 必填,生成簽名的時間戳 nonceStr: nonce, // 必填,生成簽名的隨機串 signature: signature, // 必填,簽名 jsApiList: jsApiList // 必填,需要使用的jsapi列表,注意:不要帶dd。 }); // 測試定位功能 testJsApi(); }