这是几年前写的了,现在钉钉的认证流程有些改变,corpSecret 这个东西官方都不建议使用了。

新的第三方企业开发微应用的免登流程 教程 请移步:https://www.cnblogs.com/applerosa/p/11509512.html


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

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

实现这个要求,有好几种方式,使用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;
}
}

做了一个简单demo获取用户信息:

关于钉钉的接口封装GIT 地址: https://gitee.com/lne/DTalkApi

关于获取信息的简单demo地址:https://gitee.com/lne/dtalk_login_simple_demo

钉钉开发入门,微应用识别用户身份,获取用户免登授权码code,获取用户userid,获取用户详细信息的更多相关文章

  1. Java钉钉开发_02_免登授权(身份验证)(附源码)

    源码已上传GitHub: https://github.com/shirayner/DingTalk_Demo 一.本节要点 1.免登授权的流程 (1)签名校验 (2)获取code,并传到后台 (3) ...

  2. Java钉钉开发_02_免登授权(身份验证)

    源码已上传GitHub: https://github.com/shirayner/DingTalk_Demo 一.本节要点 1.免登授权的流程 (1)签名校验 (2)获取code,并传到后台 (3) ...

  3. 企业微信开发免登授权时提示scope不能为空,错误代码1001

    企业免登授权提示scope不能为空1001 原因是我们是单页面应用url自带#/在微信里面认为#号后面的参数不被识别 后端开发人员把参数放到跳转 URL地址前面,正确形式是 https://open. ...

  4. 微信扫码登录(3)---授权码code获取用户基本信息

    授权码code获取用户基本信息 上一遍已经获得微信回调的code,网址:回调获取code     那这篇通过code和其它参数去获得用户基本信息. 1.UserServiceImpl关键代码 @Ove ...

  5. 钉钉开发第三方H5微应用入门详细教程[ISV][免登流程][授权码][HTTP回调推送][识别用户身份][获取用户信息]

    转载请注明原文地址:https://www.cnblogs.com/applerosa/p/11509512.html (by lnexin@aliyun.com 世间草木) 此教程注意点: 适用于第 ...

  6. 钉钉企业内部H5微应用开发

    企业内部H5微应用开发 分为 服务端API和前端API的开发,主要涉及到进入应用免登流程和JSAPI鉴权. JSAPI鉴权开发步骤: 1.创建H5微应用 登入钉钉开放平台(https://open-d ...

  7. 用java实现“钉钉微应用,免登进入某H5系统首页“功能”

    一.前言 哈哈,这是我的第一篇博客. 先说一下这个小功能的具体场景: 用户登录钉钉app,点击微应用,获取当前用户的信息,与H5系统的数据库的用户信息对比,如果存在该用户,则点击后直接进入H5系统的首 ...

  8. Python—实现钉钉后台开发

    二.实现钉钉免登流程 免登流程分四步:1.前端获取钉钉免登授权码code:2.后端获取access_token:3.使用授权码code和access_token换取用户userid:4.通过acces ...

  9. .NET平台下,钉钉微应用开发之:获取userid

    工作需求,开发钉钉微应用和小程序,之前有接触过支付宝小程序和生活号的开发,流程没有很大的差别,这里记录下我用ASP.NET MVC实现钉钉微应用的开发,并实现获取用户的userid.小弟我技术有限,本 ...

随机推荐

  1. LeetCode第十二题-将数字转化为罗马数字

    Integer to Roman 问题简介:将输入的int类型数字转化为罗马数字 问题详解:罗马数字由七个不同的符号表示:I,V,X,L,C,D和M 符号-数值 I - 1 V - 5 X -10 L ...

  2. Beta 冲刺(2/7)

    目录 摘要 团队部分 个人部分 摘要 队名:小白吃 组长博客:hjj 作业博客:beta冲刺(2/7) 团队部分 后敬甲(组长) 过去两天完成了哪些任务 整理博客 做了点商家数据表格 接下来的计划 做 ...

  3. SQLAlchemy 使用(一)创建单一model

    前言 最近项目等待前端接接口,比较空闲.就想学习一些新东西.学啥呢?考虑到ORM的易用性,还是学习一下ORM.那么与Flask搭配的ORM有 flask-sqlalchemy 但是该组件专为Flask ...

  4. 洛谷P5280 [ZJOI2019]线段树 [线段树,DP]

    传送门 无限Orz \(\color{black}S\color{red}{ooke}\)-- 思路 显然我们不能按照题意来每次复制一遍,而多半是在一棵线段树上瞎搞. 然后我们可以从\(modify\ ...

  5. vs查找功能不显示查找结果

    今天打开vs,查找的时候发现查找结果窗口不出现了,导致看不到查找结果. 网上各种搜索,甚至看到不少说什么要重装vs的解决方案,我也是醉了...... 其实解决办法很简单啊 vs--窗口--重置窗口布局 ...

  6. uni-app调用原生的文件系统管理器(可选取附件上传)

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  7. NOIP基本算法

    NOIP基本算法 1.二分 poj 2018 Best Cow Fences ▪ http://poj.org/problem?id=2018 ▪ 题意:给定一个正整数数列

  8. get方法与post方法的区别与js获取url参数的方式

    1.get方法与post方法的区别: 区别一:get重点在从服务器上获取资源,post重点在向服务器发送数据:区别二:get传输数据是通过URL请求,以field(字段)= value的形式,置于UR ...

  9. MIPS(极路由1s[mt7620a])平台OpenWrt路由器系统内的Go应用程序开发

    起因,由于coolpy5核心转换到go语言开发,所以目前超人正在进行相关的技术攻关,在程序编写方面一切都相对顺利.由于coolpy5是一个真正的商业级性能的系统也考滤到coolpy之前的版本已经确定的 ...

  10. sql语句表连接删除

    DELETE 表1,表2FROM 表1 LEFT JOIN 表2 ON 表1.id=表2.id WHERE 表1.id=需要删除的ID