管理员身份登录钉钉管理后台 https://oa.dingtalk.com/#/logins
创建一个钉钉H5微应用
H5微应用创建步骤和配置
点击前往钉钉开放平台 获取并记录【CorpId】
选择 应用开发》》》企业内部开发》》》H5微应用》》》创建应用
记录应用凭证 【AgentId】【AppKey】【AppSecret】
填写开发管理应用首页地址和服务器出口IP
根据需求添加接口权限
发布应用和配置可见权限
至此我们已经可以在手机或PC的钉钉中使用自建应用了
编写工具类
DingUtils工具类中的【agentid】=上述的【AgentId】/【appkey】=上述的【AppKey】/【appsecret】=上述的【AppSecret】/
- https://work.weixin.qq.com/api/doc/90000/90135/91039 (获取获取access_token)
- https://work.weixin.qq.com/api/doc/90000/90135/91023 (获取访问用户身份)
- https://work.weixin.qq.com/api/doc/90000/90135/90236 (发送应用消息)
AccessTokenD
/**
* 钉钉AccessToken
* @author Lehman
* @Date 2021-04-08
* @email 280668200@qq.com
*
*/
@Data
public class AccessTokenD {
/**
* 生成的access_token。
*/
private String access_token;
/**
* access_token的过期时间,单位秒。
*/
private double expires_in;
/**
* 返回码描述。
*/
private String errmsg;
/**
* 返回码。
*/
private double errcode;
}
DingUser
/**
* 钉钉user
* @author Lehman
* @Date 2021-04-08
* @email 280668200@qq.com
*
*/
@Data
public class DingUser {
private String request_id;
private int errcode;
private String errmsg;
private HashMap result;
}
Sns
/**
* 钉钉Sns
* @author Lehman
* @Date 2021-04-08
* @email 280668200@qq.com
*
*/
@Data
public class Sns {
private String unionid;
private String openid;
private String persistent_code;
private String errmsg;
private double errcode;
}
SendMsg
/**
* 钉钉msg
* @author Lehman
* @Date 2021-04-08
* @email 280668200@qq.com
*
*/
@Data
public class SendMsg {
/**
* 请求ID
*/
private String request_id;
private String errmsg;
private double errcode;
private double task_id;
}
DingUtils
package com.windseeker.common.system.utlis;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.google.gson.Gson;
import com.windseeker.common.core.utils.HttpsUtils;
import com.windseeker.common.system.entity.AccessTokenD;
import com.windseeker.common.system.entity.DingUser;
import com.windseeker.common.system.entity.SendMsg;
import com.windseeker.common.system.entity.Sns;
import org.apache.http.client.ClientProtocolException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
/**
* 钉钉工具类
* @author Lehman
* @Date 2021-04-05
* @email 280668200@qq.com
*
*/
@Configuration
public class DingUtils {
private static String ding_agentid;
private static String ding_appkey;
private static String ding_appsecret;
public String getDing_agentid() {
return ding_agentid;
}
@Value("${ding.agentid}")
public void setDing_agentid(String ding_agentid) {
DingUtils.ding_agentid = ding_agentid;
}
public String getDing_appkey() {
return ding_appkey;
}
@Value("${ding.appkey}")
public void setDing_appkey(String ding_appkey) {
DingUtils.ding_appkey = ding_appkey;
}
public String getDing_appsecret() {
return ding_appsecret;
}
@Value("${ding.appsecret}")
public void setDing_appsecret(String ding_appsecret) {
DingUtils.ding_appsecret = ding_appsecret;
}
/**
* 获取AccessToken
* @return
*/
public static AccessTokenD getAccessToken() {
String access_token="";
try {
access_token= HttpsUtils.sendSSL("https://oapi.dingtalk.com/gettoken?appkey="+ding_appkey+"&appsecret="+ding_appsecret);
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
AccessTokenD accessToken=JSONArray.parseObject(access_token, AccessTokenD.class);
return accessToken;
}
/**
* 获取钉钉 DingUser
* @return
*/
public static DingUser getUser(String code) {
String snsResult="";
Gson gson=new Gson();
Map<Object, Object> src = new HashMap<Object, Object>();
src.put("code",code);
try {
snsResult = HttpsUtils.sendPost("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo?access_token="+getAppToken(),gson.toJson(src));
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
DingUser dingUser=JSONArray.parseObject(snsResult, DingUser.class);
return dingUser;
}
/**
* 钉钉推送发送消息到用户
* @param userIDList
* @param msgJson
* @return
*/
public static SendMsg sendMsgToUser(String userIDList, String msgJson) {
String sendResult="";
Gson gson=new Gson();
Map<Object, Object> src = new HashMap<Object, Object>();
src.put("agent_id",ding_agentid);
src.put("userid_list",userIDList);
Map<String, String> markdown=new HashMap<String, String>();
markdown.put("title", "待处理");
markdown.put("text", msgJson);
Map<String, Object> msg=new HashMap<String, Object>();
msg.put("msgtype", "markdown");
msg.put("markdown", markdown);
src.put("msg",JSON.toJSON(msg));
try {
sendResult = HttpsUtils.sendPost("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2?access_token="+getAppToken(),gson.toJson(src));
} catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SendMsg sendMsg=JSONArray.parseObject(sendResult, SendMsg.class);
return sendMsg;
}
/**
* 应用获取Token
* @return
*/
public static String getAppToken() {
String token="";
try {
String access_token= HttpsUtils.sendSSL("https://oapi.dingtalk.com/gettoken?appkey="+ding_appkey+"&appsecret="+ding_appsecret);
AccessTokenD accessToken=JSONArray.parseObject(access_token, AccessTokenD.class);
token=accessToken.getAccess_token();
}catch (KeyManagementException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return token;
}
}
H5微应用自动授权登录
根据前面的工具类和【AgentId】 【AppKey】【AppSecret】【CorpId】可以自定义编写业务需求,最终实现前端/后端互通(此处根据自己业务实现,此处不在赘述)
基础思路如下:
浏览器引入
<script src="https://g.alicdn.com/dingding/dingtalk-jsapi/2.13.42/dingtalk.open.js"></script>
前端处理
dd.ready(function() {
dd.runtime.permission.requestAuthCode({
corpId: "ding12345xxx", // 企业id
onSuccess: function (info) {
let code = info.code // 通过该免登授权码可以获取用户身份
//钉钉自动登录
$.ajax({
url: requestUrl+'login',
type: 'POST',
data:{code:code}, // 授权码,有效期5分钟,且只能使用一次,使用后会失效。
success: function (res,status,xhr) {
if (0 === res.code) {
layer.msg('登录成功', {icon: 1, time: 1000, shade: [0.3,'#000']})
} else {
layer.msg(res.msg || '登录失败', {icon: 2, anim: 6})
}
},error:function (e) {
layer.msg(`企业微信自动登录接口异常`)
return;
}
});
}});
});
后端处理
String code = request.getParameter("code");
if (StringUtils.isBlank(code)) {
return JsonResult.error("钉钉接口异常,获取code失败或code失效!");
} else {
AccessTokenD accessToken = DingUtils.getAccessToken();
if (accessToken == null || accessToken.getErrcode() != 0) {
return JsonResult.error("钉钉接口异常,获取access_token失败," + accessToken.getErrmsg() + "!");
} else {
DingUser dingUser = DingUtils.getUser(code);
if (dingUser == null || dingUser.getErrcode() != 0) {
return JsonResult.error("钉钉接口异常,获取userid失败," + dingUser.getErrmsg());
} else {
String dingUserId = dingUser.getResult().get("userid").toString();
// .... 此处根据业务需求编写代码 其中【dingUserId】为用户钉钉标识!!!
if (【登录业务返回结果】)
return JsonResult.ok("登录成功!");
else
return JsonResult.error("您的钉钉账号当前未与系统绑定,请使用账号密码登录!");
}
}
}
web应用扫码登录钉钉
接入应用
填写接入的信息
记录appld和appSecret
tips:根据文档编写前后端代码,实现扫码登录
扫码登录第三方网站:https://open.dingtalk.com/document/isvapp-server/scan-qr-code-to-log-on-to-third-party-websites
步骤一:在页面中先引入如下JS文件(支持HTTPS)
<script src="https://g.alicdn.com/dingding/dinglogin/0.0.5/ddLogin.js"></script>
步骤二:在需要使用钉钉登录的地方实例以下JS对象
/*
* 解释一下goto参数,参考以下例子:
* var url = encodeURIComponent('http://localhost.me/index.php?test=1&aa=2');
* var goto = encodeURIComponent('https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=SuiteKey&response_type=code&scope=snsapi_login&state=STATE&redirect_uri='+url)
*/
var appid='XXXXXXXX'; //SuiteKey/SuiteSecret(第三方企业应用)或AppKey/AppSecret(企业内部应用)
var redirect_uri= encodeURIComponent('微应用回调的URL/loginDing(自定义接口)');
var ding_goto = encodeURIComponent('https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid='+appid+'&response_type=code&scope=snsapi_login&state=STATE&redirect_uri='+redirect_uri)
var obj = DDLogin({
id:"ding_login",//这里需要你在自己的页面定义一个HTML标签并设置id
goto: ding_goto, //请参考注释里的方式
style: "border:none;background-color:#FFFFFF;",
width : "365",
height: "400"
});
用户允许授权后,将会重定向到redirect_uri的网址上,并且带上【code】参数
步骤三:编写【重定向地址】接口
上述重定向到接口后,地址会带上【code】和【state】参数,我们根据【code】和【state】参数以及上述的【DingUtils】编写业务代码 实现扫码登录(此处根据自己业务实现,下述代码为大概思路)
/**
* 钉钉扫码登录
* @param code
* @return
*/
@RequestMapping("/loginDing")
@ResponseBody
public JsonResult login(String code,String state) {
if (StringUtil.isBlank(code)) {
return JsonResult.error("Error code:280450---钉钉接口异常,获取code失败或code失效!");
} else {
AccessToken accessToken = DingUtils.getAccessToken();
if (accessToken == null || accessToken.getErrcode() != 0) {
return JsonResult.error("Error code:280450---钉钉接口异常,获取access_token失败,错误信息:" + accessToken.getErrmsg() + "!");
} else {
Sns sns = DingUtils.getSns(accessToken.getAccess_token(), code);
if (sns == null || sns.getErrcode() != 0) {
return JsonResult.error("Error code:280450---钉钉接口异常,获取Unionid失败,错误信息:" + sns.getErrmsg() + "!");
} else {
DingUser dingUser = DingUtils.getUser(accessToken.getAccess_token(), sns.getUnionid());
if (dingUser == null || dingUser.getErrcode() != 0) {
return JsonResult.error("Error code:280450---钉钉接口异常,获取userid失败," + dingUser.getErrmsg());
} else {
String dingUserId = dingUser.getResult().get("userid").toString();
// .... 此处根据业务需求编写代码 其中【dingUserId】为用户钉钉标识!!!
if (【登录业务返回结果】) {
return JsonResult.ok("登录成功!");
} else {
return JsonResult.error("Error code:280404---您的钉钉账号当前未与系统绑定,请使用账号密码登录!");
}
}
}
}
}
}
开发使用文档
无论是web接入,还是微应用的配置,在配置完毕后具体使用请结合钉钉开发文档食用https://developers.dingtalk.com/document/app/document-upgrade-notice