- 公司如果有在使用钉钉,向企业管理员申请一个开发者权限。
- 如果觉得麻烦,可以自己去钉钉平台注册一个企业,不需要认证的。
创建第三方授权应用
1、 选择 工作台 tab 页 2、 拉取至末尾,选择自建应用/或者直接进入 钉钉开发者后台:
3、 在开发者后台页面,选择企业内部开发,然后单击创建应用。
4、 在弹出的页面中填写基本信息,然后单击确定创建。
- 应用类型:选择H5微应用。
- 开发方式:选择企业自主开发。
5、应用创建完成后,在基础信息页面,复制应用的AppKey和AppSecret备用,后面会使用到!
6、单击开发管理进入开发管理页面,然后单击修改,并根据以下内容配置开发信息。
注意:服务器出口IP是公网IP。 应用首页地址填写后端服务部署的服务器的IP或域名
添加接口权限
1.登录开发者后台-点击应用开发-企业内部应用,找到对应的应用并点击。
2.单击权限管理进入权限管理页面,根据以下配置添加接口调用权限。
(1)权限范围选择全部员工。
(2)选择个人权限,申请个人手机号信息和通讯录个人信息读权限。
配置花生壳域名
如果还没有的话,可以买一个。我记得当时花了 6 元,体验版内网穿透永久使用。如果价格变了,可以评论区联系我,我帮你进行映射。也可以自己去使用 natApp,其实无所谓使用什么,只要钉钉能请求到你的服务就行!
设置第三方网站的回调域名
- 登录开发者后台,找到对应的应用,并点击应用。
- 单击登录与分享,填写回调域名,点击添加。
编码
基本思路
1、获取钉钉二维码界面(即下方:dingtalk-authorize-url方法)
2、扫描二维码成功后进入回调方法(即下方:callback方法)
3、在回调方法中获取accessToken
4、在回调方法中根据code和accessToken获取用户信息(重点是用户的openId)
5、在回调方法中根据用户的openId去自己系统的用户表中查询是否存在对应的用户。这一步已经是系统的业务逻辑了。如下:
- 1、用户还未注册,就使用扫码登录,跳转绑定页面,可以使用邮箱、手机号绑定。(如果手机号、邮箱不存在则同时进行注册)!
- 2、用户注册了,第一次使用扫码登录,进行绑定,可以使用邮箱、手机号绑定!
- 3、用户注册并已绑定,则表示登录成功,跳转至系统首页。
加入依赖
<!--新版本-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dingtalk</artifactId>
<version>1.4.78</version>
</dependency>
<!--旧版本-->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alibaba-dingtalk-service-sdk</artifactId>
<version>2.0.0</version>
</dependency>
复制代码
生成页面授权地址
@GetMapping("/dingtalk-authorize-url")
public void authorizeUrl (HttpServletResponse response) throws IOException {
HashMap<String, Object> map = new HashMap<>();
map.put("redirect_uri","https://4xh8921864.eicp.vip/awesome/login/callback/ding-talk");
map.put("response_type","code");
map.put("client_id","dinghjaqszom29kxzgbl");
map.put("scope","openid");
map.put("state","dddd");
map.put("prompt","consent");
String post = HttpUtil.toParams(map);
// 重定向,当然也可以将改地址返回给前端,让其将二维码内嵌到页面中,适配网站设计
response.sendRedirect("https://login.dingtalk.com/oauth2/auth?" + post);
}
复制代码
参数 | 是否必填 | 说明 |
redirect_uri | 是 | 授权通过/拒绝后回调地址。需要与开发者后台登录与分享中配置的地址保持一致。 |
response_type | 是 | 固定值为code。授权通过后返回authCode。 |
client_id | 是 | 企业内部应用:client_id为应用的AppKey。第三方企业应用:client_id为应用的SuiteKey。就是上面需要你复制备用的 AppKey 的值。 |
scope | 是 | 授权范围,授权页面显示的授权信息以应用注册时配置的为准。当前只支持两种输入: openid:授权后可获得用户 userid openid corpid:授权后可获得用户id和登录过程中用户选择的组织id,空格分隔。注意url编码。 |
state | 否 | 原样返回。 |
prompt | 是 | 值为 consent 时,会进入授权确认页。 |
org_type | 否 | 控制输出特定类型的组织列表,org_type=management 表示只输出有管理权限的组织。scope包含 corpid 时该参数存在意义。 |
corpId | 否 | 用于指定用户需要选择的组织。 scope 包含corpid时该参数存在意义。 传入的corpId需要是当前用户所在的组织。 |
exclusiveLogin | 否 | true表示专属帐号登录,展示组织代码输入页。 |
exclusiveCorpId | 否 | 开启了专属帐号功能的组织corpId。 exclusiveLogin为true时,该参数表示直接进入该组织的登录页。exclusiveLogin为false时,该参数无意义。 |
组装路径如下:
https://login.dingtalk.com/oauth2/auth?redirect_uri=https://4xh8921864.eicp.vip/awesome/login/callback/ding-talk&response_type=code&client_id=dinghjaqszom29kxzgbl&scope=openid&state=dddd&prompt=consent
复制代码
访问第三方网站地址
1、在浏览器里输入上方生成的地址并回车
2、使用扫码或者通过钉钉账号登录。
- 无登录状态时显示:
复制代码
- 登录状态时显示:
3、单击立即登录,触发请求设置的第三方网站的回调域名,钉钉在url返回authCode。如下图所示。
回调方法
@RequestMapping("/callback/{source}")
public String callback1(@PathVariable String source, ScanLoginAuthCallbackReq req) {
//1、获取 accesstoken
GetUserTokenResponseBody body = null;
try {
body = getAccessToken(req.getAuthCode());
} catch (Exception e) {
log.error("获取 accesstoken 失败",e);
}
String accessToken = body.getAccessToken();
try {
// 获取用户通讯录个人信息,
如需获取当前授权人的信息,unionId参数必须传me
return contactUsers(accessToken,"me");
} catch (Exception e) {
log.error("获取用户通讯录个人信息 失败",e);
}
return null;
}
@Data
public class ScanLoginAuthCallbackReq {
private String authCode;
private String state;
}
复制代码
- 根据authCode,调用服务端获取用户token接口,获取用户个人token。
/**
* 获取访问凭证,使用 authCode 和应用的信息,调用获取用户token接口得到 access_token
* @param authCode
* @return
* @throws Exception
*/
public GetUserTokenResponseBody getAccessToken(String authCode) throws Exception {
com.aliyun.dingtalkoauth2_1_0.Client client = dingtalkoauth2_1_0();
GetUserTokenRequest getUserTokenRequest = new GetUserTokenRequest()
.setClientId("请替换为正确的应用信息的AppKey")
.setClientSecret("请替换为正确的应用信息的AppSecret")
.setCode(authCode)
.setGrantType("authorization_code");
try {
GetUserTokenResponse userToken = client.getUserToken(getUserTokenRequest);
System.out.println(JSONObject.toJSONString(userToken));
GetUserTokenResponseBody body = userToken.getBody();
return body;
} catch (TeaException err) {
if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
// err 中含有 code 和 message 属性,可帮助开发定位问题
}
} catch (Exception _err) {
TeaException err = new TeaException(_err.getMessage(), _err);
if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
// err 中含有 code 和 message 属性,可帮助开发定位问题
}
}
return null;
}
public static com.aliyun.dingtalkoauth2_1_0.Client dingtalkoauth2_1_0() throws Exception {
Config config = new Config();
config.protocol = "https";
config.regionId = "central";
return new com.aliyun.dingtalkoauth2_1_0.Client(config);
}
复制代码
- 根据用户个人token,调用获取用户通讯录个人信息接口,实现获取用户个人信息。
/**
* 获取用户通讯录个人信息
* @param accessToken
* @param unionId
* @throws Exception
*/
public String contactUsers(String accessToken,String unionId) throws Exception {
com.aliyun.dingtalkcontact_1_0.Client client = dingtalkcontact_1_0();
GetUserHeaders getUserHeaders = new GetUserHeaders();
getUserHeaders.xAcsDingtalkAccessToken = accessToken;
try {
GetUserResponse userWithOptions = client.getUserWithOptions(unionId, getUserHeaders, new RuntimeOptions());
GetUserResponseBody body = userWithOptions.getBody();
return JSONObject.toJSONString(body);
} catch (TeaException err) {
if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
// err 中含有 code 和 message 属性,可帮助开发定位问题
}
} catch (Exception _err) {
TeaException err = new TeaException(_err.getMessage(), _err);
if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) {
// err 中含有 code 和 message 属性,可帮助开发定位问题
}
}
return "";
}
public static com.aliyun.dingtalkcontact_1_0.Client dingtalkcontact_1_0() throws Exception {
Config config = new Config();
config.protocol = "https";
config.regionId = "central";
return new com.aliyun.dingtalkcontact_1_0.Client(config);
}
复制代码
浏览器查看用户个人相关信息。如下图所示。
历史接口
各位小伙伴对接的时候可能还对接过如下这个接口:
https://oapi.dingtalk.com/connect/qrconnect?appid= SuiteKey
&response_type=code&scope=snsapi_login
&state=STATE&redirect_uri=REDIRECT_URI
复制代码
官方文档链接 官方文档说明: 使用扫码登录第三方网站产品功能进行升级,请开发者优先参考新的文档 实现登录第三方网站 。本篇文档将于2021年12月21日迁移至历史文档,功能暂不会下线,之前已使用此功能的应用可以正常调用。开发者可以根据使用情况,评估是否切换。
使用该接口的好处就是可以省略获取 access_token 的步骤,调用该接口,会302跳转到指定的redirect_uri,并向url参数中追加临时授权码code及state参数,使用该接口返回的临时授权码调用根据sns临时授权码获取用户信息 就可以获取用户的 openid。