记一次钉钉H5微应用免登接入流程
准备工作
1.1 创建应用
要开发钉钉H5微应用,首先需要进入钉钉开发平台。点击“创建应用”按钮,进入创建应用的页面。在该页面中,可以选择创建H5微应用,并填写应用的相关信息。需要注意的是,应用的名称需要遵循钉钉的命名规范,且应用名称需要唯一。在填写完应用信息后,需要保存应用的appKey和appSecret,这些信息将用于后续的开发和部署。
保存应用的appKey和appSecret
1.2 配置应用地址
为了使H5微应用能够正常使用,需要将应用地址配置到首页地址上,并添加相应的参数。具体而言,需要在首页地址中添加&corpId=CORPIDCORPIDCORPID参数(获取组织id用)。
1.3 分配权限
为了确保H5微应用能够正常使用,需要在权限管理中对其进行相应的分配。具体而言,需要对应用中需要访问的数据进行权限控制,并确保只有具有相应权限的用户才能够访问相应的数据。此外,还需要确保应用的代码和数据在运行时得到充分的保护,以避免数据泄露和安全漏洞。
1.3.1 个人权限
个人权限需要申请:个人手机号信息、通讯录个人信息读权限
1.3.2 通讯录管理权限
通讯录管理要申请:企业员工手机号信息、邮箱等个人信息、成员信息读权限
1.4 发布
当H5微应用的开发和部署工作完成后,需要将其发布到钉钉上供用户使用。为此,需要在发布页面中填写相应的信息,并确保应用的功能和界面能够满足用户的需求。发布成功后,用户即可通过钉钉进行交互和使用H5微应用。
然后我们就能在钉钉的工作台看到我们的微应用了。
开始接入
1. 前端
我们这边选择获取微应用免登授权码 的方式接入
1.1 引入钉钉js
方式一:使用npm引入(推荐)
使用npm安装。
npm install dingtalk-jsapi --save
方式二 使用cdn引入(不推荐)
浏览器引入,在浏览器中使用 script 和 link 标签直接引入文件,并使用全局变量 dd。
1.2 调用
调用runtime.permission.requestAuthCode获取微应用免登授权码。
dd.runtime.permission.requestAuthCode({ corpId: "corpid", onSuccess: function(result) { /*{ code: 'hYLK98jkf0m' //string authCode }*/ }, onFail : function(err) {} })
2.后端
2.1 引入maven
com.aliyun dingtalk 2.0.35
2.2 编写代码
2.2.1 调用钉钉接口
包含获取accessToken,获取用户id,获取用户信息的方法。
/** * 初始化请求客户端 * @return * @throws Exception */ private Client initClient() throws Exception { Config config = new Config(); config.protocol = "https"; config.regionId = "central"; return new Client(config); } /** * 获取企业内部应用accessToken * @param appKey * @param appSecret * @return */ public String getAccessToken(String appKey,String appSecret){ String accessToken = redisUtils.get(DINGTALK_ACCESSTOKEN_PREFIX + appKey); if (StrUtil.isNotBlank(accessToken)){ return accessToken; }else{ try { Client client = initClient(); GetAccessTokenRequest getAccessTokenRequest = new GetAccessTokenRequest() .setAppKey(appKey) .setAppSecret(appSecret); GetAccessTokenResponse getAccessTokenResponse = client.getAccessToken(getAccessTokenRequest); if (ResultCode.SUCCESS == getAccessTokenResponse.getStatusCode()){ redisUtils.set(DINGTALK_ACCESSTOKEN_PREFIX +appKey,getAccessTokenResponse.getBody().getAccessToken(),getAccessTokenResponse.getBody().getExpireIn()); accessToken = getAccessTokenResponse.getBody().getAccessToken(); }else { throw new RRException("获取accessToken失败!状态码:{}",getAccessTokenResponse.getStatusCode()); } } catch (TeaException err) { if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { // err 中含有 code 和 message 属性,可帮助开发定位问题 log.error("调用钉钉开发平台API报错!报错码:{};报错信息:{}",err.getCode(),err.getMessage()); } } 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 属性,可帮助开发定位问题 log.error("调用钉钉开发平台API报错!报错码:{};报错信息:{}",err.getCode(),err.getMessage()); } } } return accessToken; } /** * 获取用户信息 * @param accessToken accessToken * @param code 免登码 前端获取 */ public OapiV2UserGetuserinfoResponse.UserGetByCodeResponse getUserInfo(String accessToken,String code) throws ApiException { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo"); OapiV2UserGetuserinfoRequest req = new OapiV2UserGetuserinfoRequest(); req.setCode(code); OapiV2UserGetuserinfoResponse rsp = client.execute(req, accessToken); return rsp.getResult(); } /** * 获取用户详细信息 * @param accessToken accessToken * @param userId userId */ public OapiV2UserGetResponse.UserGetResponse getUserDetail(String accessToken, String userId) throws ApiException { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get"); OapiV2UserGetRequest req = new OapiV2UserGetRequest(); req.setUserid(userId); OapiV2UserGetResponse rsp = client.execute(req, accessToken); return rsp.getResult(); }
2.2.2 DingDingH5AuthService
@Slf4j @RefreshScope @Service("dingDingH5AuthService") public class DingDingH5AuthService { @Autowired private DingTalkService dingTalkService; @Autowired private MallSiteService mallSiteService; public OapiV2UserGetResponse.UserGetResponse getDingTalkUserInfo(String code,Long siteId){ MallSite mallSite = mallSiteService.getMallSite(siteId); try{ //获取access_token String accessToken = dingTalkService.getAccessToken(mallSite.getDingTalkAppKey(), mallSite.getDingTalkAppSecret()); //获取用户id OapiV2UserGetuserinfoResponse.UserGetByCodeResponse userInfo = dingTalkService.getUserInfo(accessToken, code); //获取用户信息 return dingTalkService.getUserDetail(accessToken, userInfo.getUserid()); }catch (Exception e){ log.error("调用钉钉授权服务失败!",e); return null; } } }
获取token
前面我们已经通过对接获取到了用户在钉钉里面的信息,现在只需要关联我们自己系统的用户,实现登录就可以了
由于每个系统中登录逻辑不一样,只贴上伪代码逻辑
// 获取用户钉钉信息 OapiV2UserGetResponse.UserGetResponse dingTalkUserInfo = dingDingH5AuthService.getDingTalkUserInfo(code, siteId); log.info("通过code获取用户信息dingtalkUserInfo{}",JSON.toJSONString(dingTalkUserInfo)); if (dingTalkUserInfo == null){ return R.error("用户信息获取失败"); } String unionid = dingTalkUserInfo.getUnionid(); String mobile = dingTalkUserInfo.getMobile(); //todo 通过手机号在自己系统查询用户 // 存在,调用登录逻辑,获取token // 不存在,注册并登陆,获取token
参考
H5微应用JSAPI总览 - 钉钉开放平台 (dingtalk.com)
第三方企业应用免登 - 钉钉开放平台 (dingtalk.com)