Java釘釘開發_02_免登授權(身份驗證)


源碼已上傳GitHub: https://github.com/shirayner/DingTalk_Demo

 

一、本節要點

1.免登授權的流程

(1)簽名校驗

(2)獲取code,並傳到后台

(3)根據code獲取userid

(4)根據userid獲取用戶信息,(此處可進行相應業務處理)

(5)將用戶信息傳到前端,前端拿到用戶信息,並做相應處理

 

 

 

2.計算簽名信息(signature)

2.1 待簽名參數

ticket jsapi_ticket
nonceStr        隨機字符串,隨機生成
timeStamp 時間戳
url 當前網頁的URL,不包含#及其后面部分

2.2簽名流程

(1)字典序

將所有待簽名參數按照字段名的ASCII 碼從小到大排序(字典序)后,使用URL鍵值對的格式 (即 key1=value1&key2=value2…)拼接成字符串string1

如:String string1= "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "&timestamp=" + timeStamp + "&url=" + url;

(2)SHA-1簽名,得到 signature

 

/**
     * @desc : 3.生成簽名的函數 
     *  
     * @param ticket jsticket
     * @param nonceStr 隨機串,自己定義
     * @param timeStamp 生成簽名用的時間戳 
     * @param url 需要進行免登鑒權的頁面地址,也就是執行dd.config的頁面地址 
     * @return
     * @throws Exception String
     */
    
    public static String getSign(String jsTicket, String nonceStr, Long timeStamp, String url) throws Exception {  
        String plainTex = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "&timestamp=" + timeStamp + "&url=" + url;
        System.out.println(plainTex);
        try {  
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(plainTex.getBytes("UTF-8"));
            return byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception(e.getMessage());  
        } catch (UnsupportedEncodingException e) {  
            throw new Exception(e.getMessage());  
        }  
    }  

    //將bytes類型的數據轉化為16進制類型  
    private static String byteToHex(byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", new Object[] { Byte.valueOf(b) });
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }
View Code

 

3.簽名校驗的流程

3.1 后端准備好前端校驗參數

 后台方法:getConfig(HttpServletRequest) 

    public static String getConfig(HttpServletRequest request){  

        //1.准備好參與簽名的字段
        /* 
         *以http://localhost/test.do?a=b&c=d為例 
         *request.getRequestURL的結果是http://localhost/test.do 
         *request.getQueryString的返回值是a=b&c=d 
         */  
        String urlString = request.getRequestURL().toString();
        String queryString = request.getQueryString();

        String queryStringEncode = null;
        String url;
        if (queryString != null) {
            queryStringEncode = URLDecoder.decode(queryString);
            url = urlString + "?" + queryStringEncode;
        } else {
            url = urlString;
        }


        String nonceStr=UUID.randomUUID().toString();      //隨機數
        long timeStamp = System.currentTimeMillis() / 1000;     //時間戳參數  

        String signedUrl = url;
        String accessToken = null;
        String ticket = null;
        String signature = null;       //簽名

        //2.進行簽名,獲取signature
        try {  
            accessToken=AuthHelper.getAccessToken(Env.CORP_ID, Env.CORP_SECRET);  

            ticket=AuthHelper.getJsapiTicket(accessToken);  
            signature=getSign(ticket,nonceStr,timeStamp,signedUrl);  


        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  

        System.out.println("accessToken:"+accessToken);
        System.out.println("ticket:"+ticket);
        System.out.println("nonceStr:"+nonceStr);
        System.out.println("timeStamp:"+timeStamp);
        System.out.println("signedUrl:"+signedUrl);
        System.out.println("signature:"+signature);
        System.out.println("agentId:"+Env.AGENTID);
        System.out.println("corpId:"+Env.CORP_ID);
        
        
        
           String configValue = "{jsticket:'" + ticket + "',signature:'" + signature + "',nonceStr:'" + nonceStr + "',timeStamp:'"
                    + timeStamp + "',corpId:'" + Env.CORP_ID + "',agentId:'" + Env.AGENTID + "'}";
            System.out.println(configValue);

        return configValue;  
    }  
View Code

 

3.2 前端接收后台參數

在前端調用后端方法,獲取dd.config所需的校驗參數:‘url’,‘nonceStr’,‘agentId’,‘timeStamp’,‘corpId’,‘signature’。

<script type="text/javascript">
    var _config =<%=com.ray.dingtalk.auth.AuthHelper.getConfig(request)%>;
</script>
View Code

 

3.3 執行前端 dd.config ,進行簽名校驗

dd.config 用接收到的 nonceStr、agentId、timeStamp、corpId這四個參數去釘釘官方后端計算出一個簽名(signature ), 並將這個簽名與我們后端所計算的signature來進行比對,若一致,則校驗通過。若不一致,則是我們后端計算簽名的時候出錯了。此時可根據錯誤消息提示去進行調試。

dd.config({
    agentId : _config.agentId,
    corpId : _config.corpId,
    timeStamp : _config.timeStamp,
    nonceStr : _config.nonceStr,
    signature : _config.signature,
    jsApiList : [                           //需要調用的借口列表 
        'runtime.info',
        'biz.contact.choose',            //選擇用戶接口  
        'device.notification.confirm', 
        'device.notification.alert',   //confirm,alert,prompt都是彈出小窗口的接口     
        'device.notification.prompt', 
        'biz.ding.post',
        'biz.util.openLink' ]
});
View Code

 

3.4 異常:js加載順序有誤所引起的 前端什么信息都不提示

出現這個原因,可能是自己js出錯了。我的原因是js加載順序有誤。

請注意這幾個js的加載順序: _config,jquery-3.2.1.min.js 必須在auth.js之前加載

<script src="js/jquery-3.2.1.min.js"></script>
<script type="text/javascript" src="http://g.alicdn.com/dingding/open-develop/1.6.9/dingtalk.js"></script>

<script type="text/javascript">
    var _config =<%=com.ray.dingtalk.auth.AuthHelper.getConfig(request)%>;
</script>
<script type="text/javascript" src="js/auth.js"></script>
View Code

 

4. 將code送往后端:ajax

簽名校驗成功之后,即dd.config校驗成功之后,會執行dd.ready函數,這時我們就可以使用釘釘的jsapi了。

簽名校驗成功后,我們就可以調用獲取免登授權碼(CODE)的jsapi,來獲取code,然后通過ajax方式將這個code傳到后台userInfoServlet

 /**獲取免登授權碼 CODE
     * 
     */
    dd.runtime.permission.requestAuthCode({  
        corpId : _config.corpId,  
        onSuccess : function(info) {                                                   //成功獲得code值,code值在info中  
            alert('authcode: ' + info.code);  
            /* 
             *$.ajax的是用來使得當前js頁面和后台服務器交互的方法 
             *參數url:是需要交互的后台服務器處理代碼,userInfoServlet
             *參數type:指定和后台交互的方法,因為后台servlet代碼中處理Get和post的doGet和doPost 
             *data:負責傳遞請求參數
             *其中success方法和error方法是回調函數,分別表示成功交互后和交互失敗情況下處理的方法 
             */  
            $.ajax({  
                type : "POST",
                url : "http://p65s3p.natappfree.cc/DingTalk_Demo/userInfoServlet",
                data : {
                    code : info.code
                },
                success : function(data, status, xhr) {
                    alert(data);
                    var userInfo = JSON.parse(data);

                    document.getElementById("userName").innerHTML = userInfo.name;
                    document.getElementById("userId").innerHTML = userInfo.userid;

                    // 圖片
                    if(info.avatar.length != 0){
                        var img = document.getElementById("userImg");
                        img.src = info.avatar;
                        img.height = '200';
                        img.width = '200';
                    }

                },
                error : function(xhr, errorType, error) {  
                    logger.e("yinyien:" + _config.corpId);  
                    alert(errorType + ', ' + error);  
                }  
            });  

        },  
        onFail : function(err) {                                                       //獲得code值失敗  
            alert('fail: ' + JSON.stringify(err));  
        }  
    });  
View Code

 

5.根據code獲取userid

    private static final String GET_USERINFO_BYCODE_URL="https://oapi.dingtalk.com/user/getuserinfo?access_token=ACCESSTOKEN&code=CODE";

/** 5.根據免登授權碼Code查詢免登用戶userId
     * @desc :釘釘服務器返回的用戶信息為:
     * userid    員工在企業內的UserID
     * deviceId    手機設備號,由釘釘在安裝時隨機產生
     * is_sys    是否是管理員
     * sys_level    級別,0:非管理員 1:超級管理員(主管理員) 2:普通管理員(子管理員) 100:老板
     *  
     * @param accessToken
     * @param code
     * @throws Exception void
     */
    public JSONObject getUserInfo(String accessToken,String code) throws Exception {

        //1.獲取請求url
        String url=GET_USERINFO_BYCODE_URL.replace("ACCESSTOKEN", accessToken).replace("CODE", code);

        //2.發起GET請求,獲取返回結果
        JSONObject jsonObject=HttpHelper.httpGet(url);
        System.out.println("jsonObject:"+jsonObject.toString());

        //3.解析結果,獲取User
        if (null != jsonObject) {  
            //4.請求成功,則返回jsonObject
            if (0==jsonObject.getInteger("errcode")) {
                return jsonObject;
            }
            //5.錯誤消息處理
            if (0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
            }  
        }   

        return null;
    }
View Code

 

6.根據userid獲取用戶信息

    private static final String GET_USER_URL="https://oapi.dingtalk.com/user/get?access_token=ACCESSTOKEN&userid=USERID";


    /** 2.根據userid獲取成員詳情
     * @desc :獲取成員詳情
     *   參考文檔: https://open-doc.dingtalk.com/docs/doc.htm?spm=0.0.0.0.jjSfQQ&treeId=371&articleId=106816&docType=1#s0
     * @param accessToken
     * @param userId void
     * @throws Exception 
     */
    public JSONObject getUser(String accessToken, String userId) throws Exception {

        //1.獲取請求url
        String url=GET_USER_URL.replace("ACCESSTOKEN", accessToken).replace("USERID", userId);

        //2.發起GET請求,獲取返回結果
        JSONObject jsonObject=HttpHelper.httpGet(url);
        System.out.println("jsonObject:"+jsonObject.toString());
        //3.解析結果,獲取User
        if (null != jsonObject) {  
            //4.請求成功,則返回jsonObject
            if (0==jsonObject.getInteger("errcode")) {
                return jsonObject;
            }
            //5.錯誤消息處理
            if (0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
            }  
        }   

        return null;
    }
View Code

 

7.將用戶信息傳到前端

注意:傳輸格式為json

//3.通過userid換取用戶信息
            JSONObject jsonObject=us.getUser(accessToken, userId);
            result=JSON.toJSON(jsonObject);


PrintWriter out = response.getWriter(); 
        out.print(result);  
        out.close();  
        out = null;  
View Code

 

8.前端接收用戶信息后做相應處理

jsp中代碼:

<div align="center">
        <img id="userImg" alt="頭像" src="">
    </div>

    <div align="center">
        <span>UserName:</span>
        <div id="userName" style="display: inline-block"></div>
    </div>

    <div align="center">
        <span>UserId:</span>
        <div id="userId" style="display: inline-block"></div>
    </div>
View Code

js中代碼:發送code的ajax調用成功后

success : function(data, status, xhr) {
                    alert(data);
                    //接收后端發送過來的用戶信息
                    var userInfo = JSON.parse(data);

                    //收到用戶信息后所做的處理
                    document.getElementById("userName").innerHTML = userInfo.name;
                    document.getElementById("userId").innerHTML = userInfo.userid;

                    // 圖片
                    if(info.avatar.length != 0){
                        var img = document.getElementById("userImg");
                        img.src = info.avatar;
                        img.height = '200';
                        img.width = '200';
                    }

                },
View Code

 

二、代碼實現

1.釘釘參數配置——Env.java

將Env.java中的配置修改成你自己的

package com.ray.dingtalk.config;

/**@desc  : 企業應用接入時的常量定義
 * 
 * @author: shirayner
 * @date  : 2017年9月27日 下午4:57:36
 */

public class Env {

    /**
     * 企業應用接入秘鑰相關
     */
    public static final String CORP_ID = "ding6d4828968696691535c2f4657eb6378f";
    public static final String CORP_SECRET = "ZigmkCY4VcsGUhLIzmfxOmP0ElJbGI5uBhn-2mPelovnjPcA6e4LrjpYXQQw89Q4";
    public static final String SSO_Secret = "YgIGtCHmcwAmOuKsAo_lgqJJiOwyez2G6vBvhCf1zwR6kZ5DGMJsxOcUgK5p1C";
    public static final String AGENTID = "128838526";
    
    
    /**
     * DING API地址
     */
    public static final String OAPI_HOST = "https://oapi.dingtalk.com";
    /**
     * 企業應用后台地址,用戶管理后台免登使用
     */
    public static final String OA_BACKGROUND_URL = "";


    /**
     * 企業通訊回調加密Token,注冊事件回調接口時需要傳遞給釘釘服務器
     */
    public static final String TOKEN = "";
    public static final String ENCODING_AES_KEY = "";
    

    
}
View Code

 

2.Http請求工具類——HttpHelper.java

主要包括發送GET請求和POST請求

package com.ray.dingtalk.util;

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

import javax.servlet.http.HttpServletRequest;

import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ray.dingtalk.auth.AuthHelper;
import com.ray.dingtalk.config.Env;

/**
 * HTTP請求封裝,建議直接使用sdk的API
 */
public class HttpHelper {

    /**
     * @desc :1.發起GET請求
     *  
     * @param url
     * @return JSONObject
     * @throws Exception 
     */
    public static JSONObject httpGet(String url) throws Exception {
        //1.創建httpClient 
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //2.生成一個請求
        HttpGet httpGet = new HttpGet(url);
        //3.配置請求的屬性
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(2000).setConnectTimeout(2000).build();
        httpGet.setConfig(requestConfig);
        
        //4.發起請求,獲取響應信息
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpGet, new BasicHttpContext());

            //如果返回結果的code不等於200,說明出錯了  
            if (response.getStatusLine().getStatusCode() != 200) {

                System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()
                        + ", url=" + url);
                return null;
            }
            //5.解析請求結果
            HttpEntity entity = response.getEntity();      //reponse返回的數據在entity中 
            if (entity != null) {
                String resultStr = EntityUtils.toString(entity, "utf-8");  //將數據轉化為string格式  

                JSONObject result = JSON.parseObject(resultStr);    //將String轉換為 JSONObject
                if (result.getInteger("errcode") == 0) {
                    return result;
                } else {
                    System.out.println("request url=" + url + ",return value=");
                    System.out.println(resultStr);
                    int errCode = result.getInteger("errcode");
                    String errMsg = result.getString("errmsg");
                    throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                }
            }
        } catch (IOException e) {
            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (response != null) try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }


    /** 2.發起POST請求
     * @desc :
     *  
     * @param url
     * @param data
     * @return
     * @throws Exception JSONObject
     */
    public static JSONObject httpPost(String url, Object data) throws Exception {
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        CloseableHttpClient httpClient = HttpClients.createDefault();
        RequestConfig requestConfig = RequestConfig.custom().
                setSocketTimeout(2000).setConnectTimeout(2000).build();
        httpPost.setConfig(requestConfig);
        httpPost.addHeader("Content-Type", "application/json");

        try {
            StringEntity requestEntity = new StringEntity(JSON.toJSONString(data), "utf-8");
            httpPost.setEntity(requestEntity);

            response = httpClient.execute(httpPost, new BasicHttpContext());

            if (response.getStatusLine().getStatusCode() != 200) {

                System.out.println("request url failed, http code=" + response.getStatusLine().getStatusCode()
                        + ", url=" + url);
                return null;
            }
            HttpEntity entity = response.getEntity();
            if (entity != null) {
                String resultStr = EntityUtils.toString(entity, "utf-8");

                JSONObject result = JSON.parseObject(resultStr);
                if (result.getInteger("errcode") == 0) {
                    result.remove("errcode");
                    result.remove("errmsg");
                    return result;
                } else {
                    System.out.println("request url=" + url + ",return value=");
                    System.out.println(resultStr);
                    int errCode = result.getInteger("errcode");
                    String errMsg = result.getString("errmsg");
                    throw new Exception("error code:"+errCode+", error message:"+errMsg); 
                }
            }
        } catch (IOException e) {
            System.out.println("request url=" + url + ", exception, msg=" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (response != null) try {
                response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }

    
    



    
    
    
    
}
View Code

 

3.釘釘相關接口權限的獲取工具類——AuthHelper.java

主要包括:AccessToken、JsapiTicket、以及簽名校驗的工具類

package com.ray.dingtalk.auth;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.ray.dingtalk.config.Env;
import com.ray.dingtalk.util.HttpHelper;



/**
 * 釘釘相關配置參數的獲取工具類
 * @desc  : AccessToken和jsticket的獲取封裝
 * 
 * @author: shirayner
 * @date  : 2017年9月27日 下午5:00:25
 */
public class AuthHelper {
    //private static Logger log = LoggerFactory.getLogger(AuthHelper.class);  
    //獲取access_token的接口地址,有效期為7200秒
    private static final String GET_ACCESSTOKEN_URL="https://oapi.dingtalk.com/gettoken?corpid=CORPID&corpsecret=CORPSECRET"; 

    //獲取getJsapiTicket的接口地址,有效期為7200秒 
    private static final String GET_JSAPITICKET_URL="https://oapi.dingtalk.com/get_jsapi_ticket?access_token=ACCESSTOKE"; 


    /** 1.獲取access_token 
     * @desc : 
     *  
     * @param corpId
     * @param corpSecret
     * @return
     * @throws Exception String
     */
    public static String getAccessToken(String corpId,String corpSecret) throws Exception {
        //1.獲取請求url
        String url=GET_ACCESSTOKEN_URL.replace("CORPID", corpId).replace("CORPSECRET", corpSecret);

        //2.發起GET請求,獲取返回結果
        JSONObject jsonObject=HttpHelper.httpGet(url);

        //3.解析結果,獲取accessToken
        String accessToken="";  
        if (null != jsonObject) {  
            accessToken=jsonObject.getString("access_token");

            //4.錯誤消息處理
            if (0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
            }  
        }  


        return accessToken;
    }

    /**
     * 2、獲取JSTicket, 用於js的簽名計算
     * 正常的情況下,jsapi_ticket的有效期為7200秒,所以開發者需要在某個地方設計一個定時器,定期去更新jsapi_ticket
     * @throws Exception 
     */
    public static String getJsapiTicket(String accessToken) throws Exception  {
        //1.獲取請求url
        String url=GET_JSAPITICKET_URL.replace("ACCESSTOKE", accessToken);

        //2.發起GET請求,獲取返回結果
        JSONObject jsonObject=HttpHelper.httpGet(url);

        //3.解析結果,獲取ticket
        String ticket="";  
        if (null != jsonObject) {  
            ticket=jsonObject.getString("ticket");

            //4.錯誤消息處理
            if (0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
            }  
        }  

        return ticket;
    }


    /**
     * @desc : 3.生成簽名的函數 
     *  
     * @param ticket jsticket
     * @param nonceStr 隨機串,自己定義
     * @param timeStamp 生成簽名用的時間戳 
     * @param url 需要進行免登鑒權的頁面地址,也就是執行dd.config的頁面地址 
     * @return
     * @throws Exception String
     */
    
    public static String getSign(String jsTicket, String nonceStr, Long timeStamp, String url) throws Exception {  
        String plainTex = "jsapi_ticket=" + jsTicket + "&noncestr=" + nonceStr + "&timestamp=" + timeStamp + "&url=" + url;
        System.out.println(plainTex);
        try {  
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(plainTex.getBytes("UTF-8"));
            return byteToHex(crypt.digest());
        } catch (NoSuchAlgorithmException e) {  
            throw new Exception(e.getMessage());  
        } catch (UnsupportedEncodingException e) {  
            throw new Exception(e.getMessage());  
        }  
    }  

    //將bytes類型的數據轉化為16進制類型  
    private static String byteToHex(byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", new Object[] { Byte.valueOf(b) });
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    
    


    /**
     * @desc :獲取前端jsapi需要的配置參數(已棄用,請用getConfig(HttpServletRequest))
     *  
     * @param request      request:在釘釘中點擊微應用圖標跳轉的url地址 
     * @return Map<String,Object>  將需要的參數存入map,並返回
     */
    public static Map<String, Object> getDDConfig(HttpServletRequest request){  

        Map<String, Object> configMap = new HashMap<String, Object>();

        //1.准備好參與簽名的字段
        /* 
         *以http://localhost/test.do?a=b&c=d為例 
         *request.getRequestURL的結果是http://localhost/test.do 
         *request.getQueryString的返回值是a=b&c=d 
         */  
        String urlString = request.getRequestURL().toString();
        String queryString = request.getQueryString();

        String queryStringEncode = null;
        String url;
        if (queryString != null) {
            queryStringEncode = URLDecoder.decode(queryString);
            url = urlString + "?" + queryStringEncode;
        } else {
            url = urlString;
        }


        String nonceStr=UUID.randomUUID().toString();      //隨機數
        long timeStamp = System.currentTimeMillis() / 1000;     //時間戳參數  

        String signedUrl = url;
        String accessToken = null;
        String ticket = null;
        String signature = null;       //簽名

        //2.進行簽名,獲取signature
        try {  
            accessToken=AuthHelper.getAccessToken(Env.CORP_ID, Env.CORP_SECRET);  

            ticket=AuthHelper.getJsapiTicket(accessToken);  
            signature=getSign(ticket,nonceStr,timeStamp,signedUrl);  


        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  

        System.out.println("accessToken:"+accessToken);
        System.out.println("ticket:"+ticket);
        System.out.println("nonceStr:"+nonceStr);
        System.out.println("timeStamp:"+timeStamp);
        System.out.println("signedUrl:"+signedUrl);
        System.out.println("signature:"+signature);
        System.out.println("agentId:"+Env.AGENTID);
        System.out.println("corpId:"+Env.CORP_ID);
        
        
        
        //3.將配置參數存入Map
        configMap.put("agentId", Env.AGENTID);
        configMap.put("corpId", Env.CORP_ID);
        configMap.put("timeStamp", timeStamp);
        configMap.put("nonceStr", nonceStr);
        configMap.put("signature", signature);

        return configMap;  
    }  

    public static String getConfig(HttpServletRequest request){  

        //1.准備好參與簽名的字段
        /* 
         *以http://localhost/test.do?a=b&c=d為例 
         *request.getRequestURL的結果是http://localhost/test.do 
         *request.getQueryString的返回值是a=b&c=d 
         */  
        String urlString = request.getRequestURL().toString();
        String queryString = request.getQueryString();

        String queryStringEncode = null;
        String url;
        if (queryString != null) {
            queryStringEncode = URLDecoder.decode(queryString);
            url = urlString + "?" + queryStringEncode;
        } else {
            url = urlString;
        }


        String nonceStr=UUID.randomUUID().toString();      //隨機數
        long timeStamp = System.currentTimeMillis() / 1000;     //時間戳參數  

        String signedUrl = url;
        String accessToken = null;
        String ticket = null;
        String signature = null;       //簽名

        //2.進行簽名,獲取signature
        try {  
            accessToken=AuthHelper.getAccessToken(Env.CORP_ID, Env.CORP_SECRET);  

            ticket=AuthHelper.getJsapiTicket(accessToken);  
            signature=getSign(ticket,nonceStr,timeStamp,signedUrl);  


        } catch (Exception e) {  
            // TODO Auto-generated catch block  
            e.printStackTrace();  
        }  

        System.out.println("accessToken:"+accessToken);
        System.out.println("ticket:"+ticket);
        System.out.println("nonceStr:"+nonceStr);
        System.out.println("timeStamp:"+timeStamp);
        System.out.println("signedUrl:"+signedUrl);
        System.out.println("signature:"+signature);
        System.out.println("agentId:"+Env.AGENTID);
        System.out.println("corpId:"+Env.CORP_ID);
        
        
        
           String configValue = "{jsticket:'" + ticket + "',signature:'" + signature + "',nonceStr:'" + nonceStr + "',timeStamp:'"
                    + timeStamp + "',corpId:'" + Env.CORP_ID + "',agentId:'" + Env.AGENTID + "'}";
            System.out.println(configValue);

        return configValue;  
    }  
    
}
View Code

 

4.用戶業務類——UserService.java

package com.ray.dingtalk.service.contact;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ray.dingtalk.model.contact.User;
import com.ray.dingtalk.util.HttpHelper;

/**@desc  : 
 * 
 * @author: shirayner
 * @date  : 2017年9月28日 上午9:53:51
 */
public class UserService {

    private static final String CREATE_USER_URL="https://oapi.dingtalk.com/user/create?access_token=ACCESSTOKEN";
    private static final String GET_USER_URL="https://oapi.dingtalk.com/user/get?access_token=ACCESSTOKEN&userid=USERID";
    private static final String GET_DEPARTMENTUSER_URL="https://oapi.dingtalk.com/user/simplelist?access_token=ACCESSTOKEN&department_id=DEPARTMENTID";
    private static final String GET_DEPARTMENTUSERDETAIL_URL="https://oapi.dingtalk.com/user/list?access_token=ACCESSTOKEN&department_id=DEPARTMENTID";
    private static final String GET_USERINFO_BYCODE_URL="https://oapi.dingtalk.com/user/getuserinfo?access_token=ACCESSTOKEN&code=CODE";

    /**1.創建用戶
     * @desc :
     *  
     * @param accessToken
     * @param user
     * @return
     * @throws Exception String
     */
    public String createUser(String accessToken,User user) throws Exception {
        //1.准備POST請求參數
        Object data=JSON.toJSON(user);
        System.out.println(data);

        //2.獲取請求url
        String url=CREATE_USER_URL.replace("ACCESSTOKEN", accessToken);

        //3.發起POST請求,獲取返回結果
        JSONObject jsonObject=HttpHelper.httpPost(url, data);
        System.out.println("jsonObject:"+jsonObject.toString());

        //4.解析結果,獲取UserId
        String userId="";
        if (null != jsonObject) {  
            userId=jsonObject.getString("userid");
            //5.錯誤消息處理
            if (0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
            }  
        }   

        return userId;
    }


    /** 2.根據userid獲取成員詳情
     * @desc :獲取成員詳情
     *   參考文檔: https://open-doc.dingtalk.com/docs/doc.htm?spm=0.0.0.0.jjSfQQ&treeId=371&articleId=106816&docType=1#s0
     * @param accessToken
     * @param userId void
     * @throws Exception 
     */
    public JSONObject getUser(String accessToken, String userId) throws Exception {

        //1.獲取請求url
        String url=GET_USER_URL.replace("ACCESSTOKEN", accessToken).replace("USERID", userId);

        //2.發起GET請求,獲取返回結果
        JSONObject jsonObject=HttpHelper.httpGet(url);
        System.out.println("jsonObject:"+jsonObject.toString());
        //3.解析結果,獲取User
        if (null != jsonObject) {  
            //4.請求成功,則返回jsonObject
            if (0==jsonObject.getInteger("errcode")) {
                return jsonObject;
            }
            //5.錯誤消息處理
            if (0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
            }  
        }   

        return null;
    }

    /** 3.獲取部門成員
     * @desc :
     *  
     * @param accessToken
     * @param departmentId
     * @throws Exception void
     */
    public void getDepartmentUser(String accessToken, String departmentId) throws Exception {

        //1.獲取請求url
        String url=GET_DEPARTMENTUSER_URL.replace("ACCESSTOKEN", accessToken).replace("DEPARTMENTID", departmentId);

        //2.發起GET請求,獲取返回結果
        JSONObject jsonObject=HttpHelper.httpGet(url);
        System.out.println("jsonObject:"+jsonObject.toString());

        //3.解析結果,獲取User
        if (null != jsonObject) {  

            //4.錯誤消息處理
            if (0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
            }  
        }   
    }

    /** 4.獲取部門成員(詳情)
     * @desc :
     *  
     * @param accessToken
     * @param departmentId
     * @throws Exception void
     */
    public void getDepartmentUserDetail(String accessToken, String departmentId) throws Exception {

        //1.獲取請求url
        String url=GET_DEPARTMENTUSERDETAIL_URL.replace("ACCESSTOKEN", accessToken).replace("DEPARTMENTID", departmentId);

        //2.發起GET請求,獲取返回結果
        JSONObject jsonObject=HttpHelper.httpGet(url);
        System.out.println("jsonObject:"+jsonObject.toString());

        //3.解析結果,獲取User
        if (null != jsonObject) {  

            //4.錯誤消息處理
            if (0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
            }  
        }   
    }

    /** 5.根據免登授權碼Code查詢免登用戶userId
     * @desc :釘釘服務器返回的用戶信息為:
     * userid    員工在企業內的UserID
     * deviceId    手機設備號,由釘釘在安裝時隨機產生
     * is_sys    是否是管理員
     * sys_level    級別,0:非管理員 1:超級管理員(主管理員) 2:普通管理員(子管理員) 100:老板
     *  
     * @param accessToken
     * @param code
     * @throws Exception void
     */
    public JSONObject getUserInfo(String accessToken,String code) throws Exception {

        //1.獲取請求url
        String url=GET_USERINFO_BYCODE_URL.replace("ACCESSTOKEN", accessToken).replace("CODE", code);

        //2.發起GET請求,獲取返回結果
        JSONObject jsonObject=HttpHelper.httpGet(url);
        System.out.println("jsonObject:"+jsonObject.toString());

        //3.解析結果,獲取User
        if (null != jsonObject) {  
            //4.請求成功,則返回jsonObject
            if (0==jsonObject.getInteger("errcode")) {
                return jsonObject;
            }
            //5.錯誤消息處理
            if (0 != jsonObject.getInteger("errcode")) {  
                int errCode = jsonObject.getInteger("errcode");
                String errMsg = jsonObject.getString("errmsg");
                throw new Exception("error code:"+errCode+", error message:"+errMsg); 
            }  
        }   

        return null;
    }



}
View Code

 

5.Servlet——UserInfoServlet

(1)UserInfoServlet.java

package com.ray.dingtalk.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ray.dingtalk.auth.AuthHelper;
import com.ray.dingtalk.config.Env;
import com.ray.dingtalk.service.contact.UserService;

/**身份認證Servlet:免登
 * 
 * 
 * Servlet implementation class AuthServlet
 */
@WebServlet("/UserInfoServlet")
public class UserInfoServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
  
    public UserInfoServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        response.getWriter().append("Served at: ").append(request.getContextPath());
    }

    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.將請求、響應的編碼均設置為UTF-8(防止中文亂碼)  
        request.setCharacterEncoding("UTF-8");  
        response.setCharacterEncoding("UTF-8"); 
        
        //1.獲取code
        String code = request.getParameter("code");
        System.out.println("code:"+code);
        
        Object result=null;
        try {
            //2.通過CODE換取身份userid
            String accessToken = AuthHelper.getAccessToken(Env.CORP_ID, Env.CORP_SECRET);
            UserService us = new UserService();
            String userId=us.getUserInfo(accessToken, code).getString("userid");
        
            //3.通過userid換取用戶信息
            JSONObject jsonObject=us.getUser(accessToken, userId);
            result=JSON.toJSON(jsonObject);
            
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
        PrintWriter out = response.getWriter(); 
        out.print(result);  
        out.close();  
        out = null;  
    }

}
View Code

(2)web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:web="http://java.sun.com/xml/ns/javaee" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
    <servlet-name>userInfoServlet</servlet-name>
    <servlet-class>  
            com.ray.dingtalk.servlet.UserInfoServlet
    </servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>userInfoServlet</servlet-name>
    <url-pattern>/userInfoServlet</url-pattern>
  </servlet-mapping>
 
</web-app>
View Code

 

6.前端代碼

(1)IDAuthentication.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>身份認證</title>
<script src="js/jquery-3.2.1.min.js"></script>
<script type="text/javascript" src="http://g.alicdn.com/dingding/open-develop/1.6.9/dingtalk.js"></script>

<script type="text/javascript">
    var _config =<%=com.ray.dingtalk.auth.AuthHelper.getConfig(request)%>;
</script>
<script type="text/javascript" src="js/auth.js"></script>


</head>
<body>


    <div align="center">
        <img id="userImg" alt="頭像" src="">
    </div>

    <div align="center">
        <span>UserName:</span>
        <div id="userName" style="display: inline-block"></div>
    </div>

    <div align="center">
        <span>UserId:</span>
        <div id="userId" style="display: inline-block"></div>
    </div>


    <div align="center">
        <span class="desc">是否驗證成功</span>
        <button class="btn btn_primary" id="yanzheng">ceshi</button>
    </div>
    <div align="center">
        <span class="desc">測試按鈕</span>
        <button class="btn btn_primary" id="ceshi">ceshi</button>
    </div>


</body>
</html>
View Code

 

(2)auth.js

dd.config({
    agentId : _config.agentId,
    corpId : _config.corpId,
    timeStamp : _config.timeStamp,
    nonceStr : _config.nonceStr,
    signature : _config.signature,
    jsApiList : [                           //需要調用的借口列表 
        'runtime.info',
        'biz.contact.choose',            //選擇用戶接口  
        'device.notification.confirm', 
        'device.notification.alert',   //confirm,alert,prompt都是彈出小窗口的接口     
        'device.notification.prompt', 
        'biz.ding.post',
        'biz.util.openLink' ]
});

dd.ready(function() {  

    document.getElementById("yanzheng").innerHTML = "驗證成功";  

    document.querySelector('#ceshi').onclick = function () {
        alert("ceshiaaa");
    };

    /* 1.獲取容器信息
     *獲取容器信息,返回值為ability:版本號,也就是返回容器版本 
     *用來表示這個版本的jsapi的能力,來決定是否使用jsapi 
     */  
    dd.runtime.info({  
        onSuccess : function(info) {  
            logger.e('runtime info: ' + JSON.stringify(info));  
        },  
        onFail : function(err) {  
            logger.e('fail: ' + JSON.stringify(err));  
        }  
    });      



    /**獲取免登授權碼 CODE
     * 
     */
    dd.runtime.permission.requestAuthCode({  
        corpId : _config.corpId,  
        onSuccess : function(info) {                                                   //成功獲得code值,code值在info中  
            alert('authcode: ' + info.code);  
            /* 
             *$.ajax的是用來使得當前js頁面和后台服務器交互的方法 
             *參數url:是需要交互的后台服務器處理代碼,userInfoServlet
             *參數type:指定和后台交互的方法,因為后台servlet代碼中處理Get和post的doGet和doPost 
             *data:負責傳遞請求參數
             *其中success方法和error方法是回調函數,分別表示成功交互后和交互失敗情況下處理的方法 
             */  
            $.ajax({  
                type : "POST",
                url : "http://p65s3p.natappfree.cc/DingTalk_Demo/userInfoServlet",
                data : {
                    code : info.code
                },
                success : function(data, status, xhr) {
                    alert(data);
                    //接收后端發送過來的用戶信息
                    var userInfo = JSON.parse(data);

                    //收到用戶信息后所做的處理
                    document.getElementById("userName").innerHTML = userInfo.name;
                    document.getElementById("userId").innerHTML = userInfo.userid;

                    // 圖片
                    if(info.avatar.length != 0){
                        var img = document.getElementById("userImg");
                        img.src = info.avatar;
                        img.height = '200';
                        img.width = '200';
                    }

                },
                error : function(xhr, errorType, error) {  
                    logger.e("yinyien:" + _config.corpId);  
                    alert(errorType + ', ' + error);  
                }  
            });  

        },  
        onFail : function(err) {                                                       //獲得code值失敗  
            alert('fail: ' + JSON.stringify(err));  
        }  
    });  





});  


//在dd.config函數驗證失敗時執行 dd.error
dd.error(function(err) {                                             //驗證失敗  
    alert("進入到error中");  
    document.getElementById("userName").innerHTML = "驗證出錯";  
    alert('dd error: ' + JSON.stringify(err));  
});  
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM