钉钉企业内部应用单点登录开发
最近公司有钉钉单点登录需求,需用用户在钉钉中点击配置好的应用能自动登录到应用当中,我们的应用是移动端H5页面。
配置钉钉相关环境
钉钉单点登录需要注册号钉钉企业,然后配置企业H5应用,并把地址和出口IP等信息配置到应用中,应用的访问页面需要引入钉钉的dingtalk-jsapi,并通过dingtalk-jsapi+corpId获取免登code,后台使用AppKey,AppSecret获取accessToken,然后用AccessToken加上免登陆code等信息获取用户信息,完成单点登录。
开放平台文档地址:https://ding-doc.dingtalk.com/
简单流程如下:
钉钉应用模式
钉钉目前有一下几种应用模式
- 企业内部应用
- 第三方企业应用
- 第三方个人应用
我们目前选择的是企业内部应用,第三方应用需要入驻成为钉钉应用服务商,而且需要配置【RDS钉钉云推送数据源】等,操作是比较麻烦,普通公司其实是用不上的,使用【企业内部应用】即可。
注册钉钉企业
https://oa.dingtalk.com/register_new.htm#/
输入手机号注册公司,按照提示填写完信息,然后需要【设置管理密码】:
钉钉管理后台
钉钉管理后台是注册好钉钉企业之后管理企业信息,通讯录,管理员等信息的平台
https://oa.dingtalk.com/#/login
应用管理
在【钉钉管理后台】点击创建应用或者其他应用设置相关链接就可以进入【钉钉开发者平台】
地址是:https://open-dev.dingtalk.com/#/index
新建应用,管理应用等都在此界面操作:
此界面可以看到corpId等信息,jsapi获取code的时候需要。
- 新建应用
- 填写应用基本信息
- 配置应用信息
这里需要选择【开发应用】,快捷链接不能做单点登录,只是快捷方式
【应用首页链接】和【PC端首页地址】分别对应手机和电脑端访问地址,本地可以用hosts写上域名来做配置。
出口IP地址,可以用IP工具查看自己的IP,如果填写不对也没关系,在调用接口的时候的会报错,错误信息里面有自己的出口IP,填写上自己的出口IP即可。如果是发布到正式服务器上,需要根据服务器的出口IP填写。
- 创建完成
- 查看App详情
注意下:
AgentId:在创建应用时,系统会自动生成一个AgentId,可用于发送企业会话消息等场景。
AppKey:在创建应用时,系统会自动分配一对AppKey和AppSecret,该AppKey是应用开发过程中的唯一性标识。
AppSecret:AppSecret和上面AppKey一同生成,使用AppKey和AppSecret来换取access_token。
应用开发
客户端前台开发
这里使用前台页面的js来获取code,输入要corpId信息,且必须在钉钉的浏览器环境(手机端或者桌面端都可以)中才能正常获取
客户端需要引入dingtalk-jsapi,使用ES6语法在vuejs项目中代码如下:
import * as dd from 'dingtalk-jsapi'
function dingtalkLogin (corpId) {
dd.ready(() => {
// dd.ready参数为回调函数,在环境准备就绪时触发,jsapi的调用需要保证在该回调函数触发后调用,否则无效。
dd.runtime.permission.requestAuthCode({
corpId, // 每个公司服务商独立的
onSuccess (result) {
// 拿到code之后,可以在服务器端通过code、appKey和appSecret等信息获取用户信息了
if (result.code) {
console.log(result)
}
},
onFail (err) {
// log err
}
})
})
}
服务端后台开发
服务端需要根据jsapi中获取到的code来获取用户信息,类似oauth2授权之后拿到的code。
引入jar文件,目前钉钉官方提供的jar似乎没有提交到maven仓库,需要手动下载并引入到自己的工程。
文档地址:https://ding-doc.dingtalk.com/doc#/faquestions/vzbp02
根据需要下载支持的语言,这里用的是java
下载地址:http://open-dev.dingtalk.com/download/openSDK/java
下载之后是个zip:dingtalk-sdk-java.zip,解压之后有编译后的jar和源文件jar
可以放到自己项目当中引用,如果公司有私服仓库也可以install到maven私服仓库,这里把jar直接放到工程的/extra目录下,并使用scope=system方式引入:
<dependency>
<groupId>com.dingtalk.open</groupId>
<artifactId>taobao-sdk-java</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>system</scope>
<systemPath>${project.basedir}/extra/taobao-sdk-java-auto_1479188381469-20200302.jar</systemPath>
</dependency>
开发调用
测试代码如下,由于用的JUnit测试,需要把页面上通过jsapi获取到的code写入代码进行测试:
public class DingtalkLoginTest {
private static final Logger logger = LoggerFactory.getLogger(DingtalkLoginTest.class);
private static final String DING_URL = "https://oapi.dingtalk.com";
private static final String APP_KEY = ""; // 应用的Key
private static final String APP_SECRET = ""; // 应用的密码
@Test
public void test() {
// code是前台使用jsapi获取到的,然后传递给后台使用
String code = "xxxxxxxxxxxxxxxxxx";
String accessToken = getAccessToken();
if (StringUtils.isNotBlank(accessToken)) {
String userId = getUserId(accessToken, code);
OapiUserGetResponse userDetail = StringUtils.isNotBlank(userId) ? getUserDetail(userId, accessToken) : null;
logger.debug("{}", userDetail);
}
}
public String getAccessToken() {
String result = null;
DefaultDingTalkClient client = new DefaultDingTalkClient(DING_URL + "/gettoken");
OapiGettokenRequest request = new OapiGettokenRequest();
request.setAppkey(APP_KEY);
request.setAppsecret(APP_SECRET);
request.setHttpMethod(HttpMethod.GET.name());
try {
OapiGettokenResponse response = client.execute(request);
result = response.isSuccess() ? response.getAccessToken() : null;
} catch (ApiException e) {
logger.error("获取钉钉AccessToken错误", e);
}
return result;
}
public String getUserId(String accessToken, String code) {
DingTalkClient client = new DefaultDingTalkClient(DING_URL + "/user/getuserinfo");
OapiUserGetuserinfoRequest request = new OapiUserGetuserinfoRequest();
request.setCode(code);
request.setHttpMethod("GET");
String userId = null;
try {
OapiUserGetuserinfoResponse response = client.execute(request, accessToken);
userId = response.isSuccess() ? response.getUserid() : null;
} catch (ApiException e) {
logger.error("获取钉钉UserId错误", e);
}
return userId;
}
public OapiUserGetResponse getUserDetail(String userId, String accessToken) {
DingTalkClient client = new DefaultDingTalkClient(DING_URL + "/user/get");
OapiUserGetRequest request = new OapiUserGetRequest();
request.setUserid(userId);
request.setHttpMethod("GET");
OapiUserGetResponse userDetail = null;
try {
userDetail = client.execute(request, accessToken);
} catch (ApiException e) {
logger.error("获取钉钉UserDetail错误", e);
}
return userDetail;
}
}
测试钉钉单点登录
可以直接使用钉钉桌面版做测试,不过在配置应用的时候需要填写好【PC端首页地址】。
访问之后应用H5路径之后,得到js得到当前用户code,传到后台获取用户信息。
开启钉钉调试功能
注意:如果需要开启调试功能,需要在H5应用中把开发人员配置成【开发负责人】,H5页面按F12就可以出现类似Chrome的开发者工具了。
参考文档:https://ding-doc.dingtalk.com/doc#/kn6zg7/qg4y64
常见错误信息
如果报IP错误(错误信息中提供了IP地址,并把此IP地址写入到应用出口IP位置):
{
"errcode":60020,
"errmsg":"请参考FAQ:https://open-doc.dingtalk.com/microapp/faquestions/cvbtph。错误原因:访问ip不在白名单之中,request ip=124.15.237.12 appKey\u0028dingebhlv5xxxxx\u0029"
}
另外可能报权限错误,根据实际使用的数据来给新建的应用配置权限即可
{
"errcode":60011,
"errmsg":"没有调用该接口的权限"
}
配置接口权限: