zoukankan      html  css  js  c++  java
  • 订订登录

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

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

    实现这个要求,有好几种方式,使用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;
        }
    }
    复制代码
  • 相关阅读:
    缓存IO读写的方式
    mapboxgl 纠偏百度地图
    GIS常用算法
    DevExpress VCL TdxBar工具栏上的按钮等居右对齐无效的问题
    dxRichEditControl、Invalid operation in GDI+ (Code: 2)
    Indy+POP/SMTP收发邮件
    VUE父组件给子组件传对象
    Linux下进程间通信
    Linux下守护进程
    Linux下进程控制相关
  • 原文地址:https://www.cnblogs.com/zkx001/p/13321124.html
Copyright © 2011-2022 走看看