zoukankan      html  css  js  c++  java
  • 用java实现“钉钉微应用,免登进入某H5系统首页“功能”

    一、前言

    哈哈,这是我的第一篇博客。

    先说一下这个小功能的具体场景:

    用户登录钉钉app,点击微应用,获取当前用户的信息,与H5系统的数据库的用户信息对比,如果存在该用户,则点击后直接进入H5系统的首页,否则显示“您无权限”。

    补充:又加了一个小需求,就是免登成功,会给该用户发条消息

    我是参考钉钉开发文档实现的这个小功能,文档地址:https://ding-doc.dingtalk.com/doc#/serverapi2/clotub

    二、准备工作

     需要创建一个微应用:https://open-dev.dingtalk.com

     

    1.是在企业内部开发中创建H5微应用,不是第三方企业应用中

    企业内部开发:企业内部开发是指“开发企业内部应用”供企业内部的人员使用。企业可以选择由企业内部的开发者进行开发,或者由企业授权定制服务商进行开发。

    第三方企业应用:第三方企业应用开发,是指开发者以钉钉、企业之外的第三方身份,基于钉钉的开放能力开发应用,并提供给钉钉上的其他组织使用。(哈哈,这个区别我是直接copy文档中的)

    2.H5工程中,创建的一个前端页面ddNoLogin.html(哈哈,这个起名有点中文式英语,因为我没有找到合适的英文单词):

    该页面是用来获取免登授权码,然后把该code传递给后台接口的。

    3.填写公司服务器的公网IP

    可以敲命令查看该ip:curl ifconfig.me

     4.微应用创建好,会生成三个参数,

    agentId、appKey、appSecret

    外加一个corpId(钉钉开发者平台的首页中有显示),这四个参数值是固定的,后续开发需用

    5.接口权限

    高级权限-企业通讯录中的接口都需要给开通

    6.最后发布应用

    三、功能开发

    哈哈,要开始敲代码了

    1.获取免登授权码code

    这里调用的是钉钉JS-API中的方法,本功能调用的方法是不需要鉴权的,如果需要鉴权,则还需先dd.config。

    关于功能方法是否需要鉴权,可以去查看JSAPI总览

    ddNoLogin.html:

    <!DOCTYPE html>
    <html>
    <head>
        <title>微应用登陆</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1 user-scalable=0" />
        <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
        <script type="text/javascript" src="http://g.alicdn.com/dingding/open-develop/1.9.0/dingtalk.js"></script>
    </head>
    <body>
    <div id="ddNoLogin"></div>
    <script type="text/javascript">
            dd.ready(function() {
            //1.获取免登授权码code
            dd.runtime.permission.requestAuthCode({
                corpId : corpId ,  //企业id
                onSuccess : function(result) {
                    var code = result.code;
                    getUserInfo(code);   //通过该code可以获取用户身份
                },
                onFail : function(err) {
                    alert('出错了, ' + err);
                }
            });
        });
            function getUserInfo(code) {
            $.ajax({
                type : "GET",
                url : "/xxx/noLogin?code=" + code,
                async : false,
                dataType : 'json',
                contentType : "application/json;charset=utf-8",
                success : (function(res) {
                    if(res.code == "0000"){                                        
                           window.location.href = '/#/xxxxx';
                                    }else{
                                       $('#ddNoLogin').html(res.msg);
                                    }
                }),
            });
        }
    </script>
    </body>
    </html>

    获取code的实现是需要用前端JS去写的

    2.获取access_token

    钉钉提供了开放的api后台接口,这里通过appkey和appsecret获取token,请求路径:https://oapi.dingtalk.com/gettoken?appkey=key&appsecret=secret

    该token有效期是2个小时,有效期内重复获取,会返回相同结果,并自动续期,

    故这里我的实现是:定时刷新token,每隔1小时50分钟去获取钉钉的token,并缓存到redis中(我把钉钉的相关配置都放入到application.yml中了)

    DdTokenTask.java:

    /**
     * 定时获取钉钉的token
     */
    @Component
    @EnableScheduling
    public class DdTokenTask {
    
        @Autowired
        private JedisClient jedisClient;
    
        public static final long cacheTime = 1000 * 60 * 55 * 2;//1小时50分钟
        @Value("${dtalk.tokenUrl}")
        private String tokenUrl;
        @Value("${dtalk.app.key}")
        private String appKey;
        @Value("${dtalk.app.secret}")
        private String appSecret;
        @Value("${dtalk.redisTokenKey}")
        private String tokenKey;
        @Value("${dtalk.taskRun}")
        private String taskRun;
    
    
        /**
         * 每隔1小时50分钟获取钉钉的access_token
         */
        @Scheduled(fixedRate = cacheTime)
        @Async
        public void getDdTokenTask(){
            if("true".equals(taskRun)){
                //刷新
                System.out.println("--->>>>>-------------获取钉钉token的定时任务开始了:"+ DateUtil.formatDateToString(new Date(), "HH:mm:ss"));
    
                String accessTokenUrl = tokenUrl + "?appkey=" + appKey + "&appsecret=" + appSecret;
                //访问获取access_token   有效期是2小时
                String accessToken = JsonUtil.getJsonNode(HttpUtil.doGet(accessTokenUrl)).get("access_token").asText();
                //放入到redis中
                jedisClient.set(tokenKey, accessToken);
    
                System.out.println("--->>>>>-------------获取钉钉token的定时任务结束了,token:"+accessToken);
            }
        }
    
        /*private String getAccessToken(){
            //需引入SDK,公司私服没有
            DefaultDingTalkClient client = new 
            DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
            OapiGettokenRequest request = new OapiGettokenRequest();
            request.setAppkey("appkey");
            request.setAppsecret("appsecret");
            request.setHttpMethod("GET");
            OapiGettokenResponse response = client.execute(request);
            return "";
        }*/
    
    }
    

    (哈哈,其实文档中提供了钉钉SDK的java写法,不过公司私服没有该SDK,所以我就直接用htttp请求了)

     3.获取用户userid

     通过免登授权码和access_token获取用户的userid,请求路径:https://oapi.dingtalk.com/user/getuserinfo?access_token=access_token&code=code

     4.获取用户详情

    请求路径:https://oapi.dingtalk.com/user/get?access_token=ACCESS_TOKEN&userid=shaocui

    会返回用户的姓名、手机号等所有信息

    DdLoginController.java:

    @RestController
    @RequestMapping("/ddUser")
    @Api(value = "/ddUser", description = "钉钉H5微应用登录", tags = {"DdLoginController"})
    public class DdLoginController {
    
        @Autowired
        private JedisClient jedisClient;
    
        @Value("${dtalk.userUrl}")
        private String userUrl;
        @Value("${dtalk.userDetailUrl}")
        private String userDetailUrl;
        @Value("${dtalk.redisTokenKey}")
        private String tokenKey;
        @Value("${dtalk.agentId}")
        private Integer agentId;
    
    
        @GetMapping("/noLogin")
        @ApiOperation( "钉钉免登")
        @ApiImplicitParam(paramType = "query", name = "code", value = "免登授权码", dataType = "String")
        public WebResponse noLogin(@RequestParam("code") String code, HttpServletResponse response){
            //2.获取access_token
            String accessToken = jedisClient.get(tokenKey);
    
            //3.获取用户userid
            String userIdUrl =userUrl + "?access_token=" + accessToken + "&code=" + code;
            //访问获取userid
            JsonNode user = JsonUtil.getJsonNode(HttpUtil.doGet(userIdUrl));
            if(user.get("errcode").asInt() != 0){
                //有些公司的公网ip不固定,导致微应用中设置的不对,这里就会报错
                return WebResponse.resFail(user.get("errmsg").asText());
            }
            String userId = user.get("userid").asText();
    
            //4.获取用户详情  手机号
            String userInfoUrl = userDetailUrl + "?access_token=" + accessToken + "&userid=" + userId;
            //访问获取mobile
            JsonNode userInfo = JsonUtil.getJsonNode(HttpUtil.doGet(userInfoUrl));
            String mobile = userInfo.get("mobile").asText();
    
            System.out.println("钉钉用户的手机号:"+mobile);
    
            //通过手机号获取该用户
            SysUser sysUser = 。。。。。;
            if(sysUser == null){
                //不存在该用户
                return WebResponse.resFail("您无权限访问", null);
            }
    
            。。。。。。
    
            //钉钉发送免登成功消息给用户
            sendMessage(accessToken, userId, userInfo.get("name").asText());
    
            return WebResponse.resSuccess("免登成功", loginUserInfo);
        }
    
        //钉钉发送消息给用户
        private void sendMessage(String token, String userId, String userName){
            String messageUrl = "https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token="+token;
            Map<String, Object> map = new HashMap<>();
            map.put("agent_id", agentId.longValue());
            map.put("userid_list", userId);
            map.put("to_all_user", false);
            String content = "用户"+userName+"在"+ DateUtil.formatDateToString(new Date(), "yyyy-MM-dd HH:mm:ss")+"时成功登录xxH5端,并进入到xxx页面";
            String msg = "{"msgtype":"text","text":{"content":"+"""+content+"""+"}}";
            JSONObject jsonObj = JSONObject.parseObject(msg);
            map.put("msg",jsonObj);
    
            HttpUtil.doPost(messageUrl, map, "UTF-8", 20000, null);
        }
    }
    

    (哈哈,那个。。。。。处的代码是实现系统认证成功后的具体操作,故这里省略)

    到此钉钉免登就实现了,然后免登成功后给用户发送消息

    5.工作通知消息

    POST请求,请求路径:https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token=ACCESS_TOKEN

    请求体{agent_id、userid_list、dept_id_list、to_all_user、msg}

    注意:

    给同一个用户发送相同的内容,一天只能发一次;发送不同的内容,一天可以500次,

    故这里我在发送的消息中添加了当前时间。

    (哈哈,一些细节的东西我都写在代码的注释里了,最后发现这个小功能好像就一点点代码量)

  • 相关阅读:
    模拟title提示!
    常用CSS缩写语法总结
    cron表达式每个月最后一天,corn表达式使用L报错
    浏览器调试器(F12)详解
    查询重复数据只显示一条并且在规定范围时间内
    java导出统计数据excel设置单元格样式
    微信小程序官方人脸核身认证
    小程序引用app.js中的全局变量
    微信小程序 view中的image水平垂直居中
    MYSQL中的sql_mode模式
  • 原文地址:https://www.cnblogs.com/muxisc/p/11613628.html
Copyright © 2011-2022 走看看