zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    h5布局之道(最终篇)
    javascript 数组的常用方法总结
    排序算法之简单排序算法
    浅谈h5移动端页面的适配问题
    开园子啦(浅谈移动端以及h5的发展)
    Android开发(二):RelativeLayout、FrameLayout、LinearLayout、TableLayout、AbsoluteLayout各种Layout属性
    Android开发(一):android环境搭建
    为何没有人用DELPHI IDHTTP + WEB做三层应用
    Asp.net学习1-弹出消息框
    处理SQL函数IN问题
  • 原文地址:https://www.cnblogs.com/shirui/p/7614228.html
Copyright © 2011-2022 走看看