釘釘開發入門,微應用識別用戶身份,獲取用戶免登受權碼code,獲取用戶userid,獲取用戶詳細信息

這是幾年前寫的了,如今釘釘的認證流程有些改變,corpSecret 這個東西官方都不建議使用了。html

 

新的第三方企業開發微應用的免登流程 教程 請移步:http://www.javashuo.com/article/p-vskfeyvn-e.html前端


 

最近有個需求,在釘釘內,點擊微應用,獲取用戶身份,根據獲取到的用戶身份去企業內部的用戶中心作校驗,校驗經過,相關子系統直接登錄;java

就是在獲取這個用戶身份的時候,網上的資料七零八落的,找的人煩躁的很,因此本身記錄一下;git

實現這個要求,有好幾種方式,使用ISV方式相對來講比較簡單一點,獲取的到的信息雖然沒有其餘方式那麼全,可是也包含了百分之七八十的信息,少了角色信息之類的;web

 

效果:(demo的GIT地址在文末)api

 

說說步驟:服務器

1.去OA 控制檯建立一個微應用: https://oa.dingtalk.comapp

  

 

  這個首頁跳轉地址,信任了之後,就能夠直接使用js-sdk來獲取用戶code等相關信息,最方便的一種.ide

  若是是別的頁面,使用js-sdk 須要進行dd.config的初始化,這個初始化裏面,包含了相關的權限校驗.工具

2.應用建立完了之後,會生成一個agentID,

  若是僅僅只是爲了獲取當前點擊用戶的信息,而且獲取的位置是在這個首頁地址的js裏面,則大能夠不用管這個信息,可是,若是須要更加複雜的操做,就須要獲取這個ID,獲取方法在建立完了之後,右上角的小三角下拉,有個設置,點進去就能看到

  另外,關於js-sdk的須要鑑權的api信息查詢地址:jsapi列表(是否須要dd.config校驗)

  列表裏面不須要的接口調用,都不須要進行dd.config()

3.獲取釘釘開發的corpID和corpSecert

  進入釘釘開發者平臺獲取:http://open-dev.dingtalk.com

  

  通常獲取上面的足夠.web sso免登可能須要下面的SSOSecert;

  

4.準備工做作完

  如今咱們有如下信息:

  corpID:

  corpSecert:

  agentID:

  url:這個url就是你須要獲取用戶code的那個頁面url

  固然若是只是簡單的獲取用戶信息,不須要進行dd.config的話,能夠不用管agrntID和url

 

5.進入開發(這裏只是作獲取當前用戶信息的示例)

  (1).前端頁面引入 dingtalk.js 

  (2).在頁面添加 獲取code 的 js 代碼,

  (3).將獲取的 code 發送到後臺處理

  (4).後臺先根據corpID,corpSecert獲取一個accessToken(這個token是獲取其餘信息的一個關鍵key)。 文檔 

   後臺根據 code accessToken 獲取 userinfo , 這個獲取到的是一個簡單的用戶信息,包括userid,時候管理員等。 文檔 

   後臺根據上一步返回的簡單的,包含userid的信息,拿到userid

   後臺根據userid accessToken 獲取用戶的詳細信息  。文檔

  (5).返回給前臺顯示,或者進行後續開發

 

貼一貼這個流程中關鍵一點的代碼:

前端頁面在引入js 後,或有一個dd的全局變量,這個就是js-sdk,若是須要權限校驗的,就要放在最前邊

關於免登受權碼 code 的獲取 

dd.ready(function() {
            dd.runtime.permission.requestAuthCode({
                corpId : "這裏是你的corpID",
                onSuccess : function(result) {
                    var code = result.code;
                    alert(code);
            //將code 發日後臺處理 }, onFail :
function(err) { alert('出錯了, ' + err); } }); });

 

後臺處理部分:

AuthHelper.java 文末提供

在接收到受權碼之後:

String accessToken = AuthHelper.getAccessToken(CORP_ID, CORP_SECRET);
String user = AuthHelper.getUserInfo(code, accessToken);

當返回正確的時候,這個user 裏面結果大體是這樣的:

{
    "errcode": 0,
    "errmsg": "ok",
    "userid": "USERID",
    "deviceId":"DEVICEID",
    "is_sys": true,
    "sys_level": 0|1|2
}

而後根據裏面的userid,獲取詳細的用戶信息:

String userall = AuthHelper.getUser(userid, accessToken);

返貨正確的話,這個userall裏面的結果大體是:(具體查看釘釘開發文檔)

{
    "errcode": 0,
    "unionid": "PiiiPyQqBNBii0HnCJ3zljcuAiEiE",
    "openId": "PiiiPyQqBNBii0HnCJ3zljcuAiEiE",
    "roles": [{
        "id": 23003585,
        "name": "財務",
        "groupName": "職務"
    }],
    "remark": "備註",
    "userid": "04232334556237185",
    "isLeaderInDepts": "{1:false}",
    "isBoss": false,
    "hiredDate": 1520265600000,
    "isSenior": false,
    "tel": "010-88996533",
    "department": [1,2],
    "workPlace": "北京市朝陽區",
    "email": "ceshi@aliyun.com",
    "orderInDepts": "{1:71738366882504}",
    "dingId": "$:LWCP_v1:$aTPvVHhhsCMtDZRQ1xbYGg==",
    "mobile": "15901516821",
    "errmsg": "ok",
    "active": false,
    "avatar": "dingtalk.com/abc.jpg",
    "isAdmin": false,
    "isHide": false,
    "jobnumber": "001",
    "name": "測試名字",
    "extattr": {},
    "stateCode": "86",
    "position": "總監"
}

 

而後簡單的獲取信息到此結束;

注意的是:

   若是須要更多的操做,就須要在前端頁面進行dd.config的初始化,這個裏面的所須要的sign,能夠在後臺根據相關信息生成,是必不可少的,生成規則見AuthHelper.java(其餘工具類見文末的 git 地址)

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;

import cn.jlhd.util.HttpHelper;
import cn.jlhd.util.JsonUtil;
import cn.jlhd.util.ReturnUtil;

/**
 * 
 * 1.獲取accessToken
 * 2.獲取jsapi中的ticket
 * 3.生成jsapiz中的鑑權sign
 * 4.根據傳入的臨時code獲取用戶的基本信息,入userinfo
 * 5.根據userid獲取詳細用戶信息
 * 
 * @author lnexin
 *
 */
public class AuthHelper {

    // 釘釘api相關
    static String TOKEN_URL = "https://oapi.dingtalk.com/gettoken";
    static String TICKET_URL = "https://oapi.dingtalk.com/get_jsapi_ticket";
    static String USER_INFO_URL = "https://oapi.dingtalk.com/user/getuserinfo";
    static String USER_ALL_URL = "https://oapi.dingtalk.com/user/get";

    // 調整到1小時50分鐘
    public static final long cacheTime = 1000 * 60 * 55 * 2;

    private static String ACCESS_TOKEN = null;
    private static String JSAPI_TICKET = null;
    private static long LAST_TIME = 0;

    /**
     * 
     * @param corpId
     * @param corpSecert
     * @return 與釘釘服務器請求生成的accessToken
     */
    public static String getAccessToken(String corpId, String corpSecert) {
        long curTime = System.currentTimeMillis();
        long differ = curTime - LAST_TIME;

        if (ACCESS_TOKEN != null && differ < cacheTime)
            return ACCESS_TOKEN;

        ACCESS_TOKEN = requestAccessToken(corpId, corpSecert);
        LAST_TIME = curTime;

        return ACCESS_TOKEN;
    }

    /**
     * 
     * @param accessToken
     *            
     * @see getAccess_Token(String corpId, String corpSecert) 生成的access_token
     * @return 一個用於js鑑權的ticket
     */
    public static String getJsapiTicket(String accessToken) {
        long curTime = System.currentTimeMillis();
        long differ = curTime - LAST_TIME;

        if (JSAPI_TICKET != null && differ < cacheTime) {
            return JSAPI_TICKET;
        }
        JSAPI_TICKET = requestJsapiTicket(accessToken);
        return JSAPI_TICKET;
    }

    /**
     * 根據傳入的相關參數生成sign
     * 
     * @param ticket
     * @param nonceStr
     * @param timeStamp
     * @param url
     * @return
     */
    public static String sign(String ticket, String nonceStr, long timeStamp, String url) {
        StringBuffer plain = new StringBuffer();
        plain.append("jsapi_ticket=").append(ticket);
        plain.append("&noncestr=").append(nonceStr);
        plain.append("&timestamp=").append(String.valueOf(timeStamp));
        plain.append("&url=").append(url);
        MessageDigest sha;
        try {
            sha = MessageDigest.getInstance("SHA-1");
            sha.reset();
            sha.update(plain.toString().getBytes("UTF-8"));
            return bytesToHex(sha.digest());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String requestAccessToken(String corpId, String corpSecert) {
        StringBuffer url = new StringBuffer(TOKEN_URL);
        url.append("?corpid=").append(corpId);
        url.append("&corpsecret=").append(corpSecert);
        String result = null;
        try {
            result = HttpHelper.sendGet(url.toString());
        } catch (IOException e) {
            result = ReturnUtil.result("-1",
                    "請求accessTokenc出錯!corpid:" + corpId + ",corpsecert:" + corpSecert + "異常信息:" + e);
        }
        return JsonUtil.getJsonNode(result).get("access_token").asText();
    }

    private static String requestJsapiTicket(String accessToken) {
        StringBuffer url = new StringBuffer(TICKET_URL);
        url.append("?access_token=").append(accessToken);
        String result = null;
        try {
            result = HttpHelper.sendGet(url.toString());
        } catch (IOException e) {
            result = ReturnUtil.result("-1", "請求JsapiTicket出錯!accessToken:" + accessToken + "異常信息:" + e);
        }
        return JsonUtil.getJsonNode(result).get("ticket").asText();
    }

    private static String bytesToHex(byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    /**
     * 獲取用戶信息
     * 
     * @param code
     *            用戶相應的臨時code
     * @param token
     *            根據相應corpid和corpsecret生成的access_token
     * @return 用戶ID等相關信息
     */
    public static String getUserInfo(String code, String accessToken) {
        StringBuffer url = new StringBuffer(USER_INFO_URL);
        url.append("?access_token=").append(accessToken);
        url.append("&code=").append(code);
        String result = null;
        try {
            result = HttpHelper.sendGet(url.toString());
        } catch (IOException e) {
            result = ReturnUtil.result("-1", "請求User信息出錯!code:" + code + "異常信息:" + e);
        }
        return result;
    }
    /**
     * 獲取用戶詳細信息
     * @param userid 在某個corpid下的惟一用戶userid
     * @param accessToken 據相應corpid和corpsecret生成的access_token
     * @return
     */
    public static String getUser(String userid, String accessToken) {
        StringBuffer url = new StringBuffer(USER_ALL_URL);
        url.append("?access_token=").append(accessToken);
        url.append("&userid=").append(userid);
        String result = null;
        try {
            result = HttpHelper.sendGet(url.toString());
        } catch (IOException e) {
            result = ReturnUtil.result("-1", "請求User信息出錯!userid:" + userid + "異常信息:" + e);
        }
        return result;
    }
}

 

 

作了一個簡單demo獲取用戶信息:

關於釘釘的接口封裝GIT 地址: https://gitee.com/lne/DTalkApi

關於獲取信息的簡單demo地址:https://gitee.com/lne/dtalk_login_simple_demo

相關文章
相關標籤/搜索