• 订订登录


    最近有个需求,在钉钉内,点击微应用,获取用户身份,根据获取到的用户身份去企业内部的用户中心做校验,校验通过,相关子系统直接登陆;

    就是在获取这个用户身份的时候,网上的资料七零八落的,找的人烦躁的很,所以自己记录一下;

    实现这个要求,有好几种方式,使用ISV方式相对来说比较简单一点,获取的到的信息虽然没有其他方式那么全,但是也包含了百分之七八十的信息,少了角色信息之类的;

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

    说说步骤:

    1.去OA 控制台创建一个微应用: https://oa.dingtalk.com

      

     

      这个首页跳转地址,信任了以后,就可以直接使用js-sdk来获取用户code等相关信息,最方便的一种.

      如果是别的页面,使用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;
        }
    }
    复制代码
  • 相关阅读:
    java io系列23之 BufferedReader(字符缓冲输入流)
    java io系列22之 FileReader和FileWriter
    java io系列21之 InputStreamReader和OutputStreamWriter
    java io系列20之 PipedReader和PipedWriter
    java io系列19之 CharArrayWriter(字符数组输出流)
    java io系列18之 CharArrayReader(字符数组输入流)
    java io系列17之 System.out.println("hello world")原理
    java io系列16之 PrintStream(打印输出流)详解
    java io系列15之 DataOutputStream(数据输出流)的认知、源码和示例
    java io系列14之 DataInputStream(数据输入流)的认知、源码和示例
  • 原文地址:https://www.cnblogs.com/zkx001/p/13321124.html
Copyright © 2020-2023  润新知