这篇文章默认你已经在钉钉创建好了H5微应用,同时对一些功能有一定了解。

首先,需要明白整个授权登录的流程,如下图所示:


下面的示例可用于前后端分离项目应用场景,后端以springboot,前端以html。

前端实现

内嵌二维码扫码登录,不走页面重定向。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>登录</title><script src="http://code.jquery.com/jquery-2.1.1.min.js"></script><script src="https://g.alicdn.com/dingding/h5-dingtalk-login/0.21.0/ddlogin.js"></script><style>/* STEP2:指定这个包裹容器元素的CSS样式,尤其注意宽高的设置 */.self-defined-classname {width: 300px;height: 300px;border: 1px #000 solid;}</style>
</head>
<body><!-- STEP1:在HTML中添加包裹容器元素 --><div id="self_defined_element" class="self-defined-classname"></div>
</body>
</html>
<script>// STEP3:在需要的时候,调用 window.DTFrameLogin 方法构造登录二维码,并处理登录成功或失败的回调。window.DTFrameLogin({id: 'self_defined_element',width: 300,height: 300,},{// 回调地址:可以理解为用户扫码同意后钉钉会重定向到你指定的地址并把授权码authCode拼接到该地址参数92redirect_uri: encodeURIComponent('http://xxxxxxxxxxxxx'), client_id: 'xxxxxxxxxxxxxxxxxxxx', // 你的企业内部应用appKeyscope: 'openid',   // 保持不变response_type: 'code', // 保持不变state: 'pc',   // 跟随authCode原样返回prompt: 'consent',   // 值为consent时,会进入授权确认页},(loginResult) => {const {redirectUrl, authCode, state} = loginResult;// 用户扫码成功后获取到重定向地址以及同意的授权码,这里不做重定向地址。// 通过拿到的授权码调用我们第三方应用的钉钉授权码登录接口换取用户凭证token$.ajax({url:`http://8cyif2.natappfree.cc/dingTalk/auth?authCode=${authCode}`,method:'get',contentType:'application/json',dataType:'json',success:function(data) {if(data.code == 0) {// 获取token并缓存下来window.localStorage.setItem('token', data.data.adminToken);// 重定向到首页,这样钉钉扫码授权登录就全部完成了window.location.href = 'http://8cyif2.natappfree.cc/oa2login/index'}else {alert(data.msg);return;}},error: function(err){alert(err);}});},(errorMsg) => {// 这里一般需要展示登录失败的具体原因alert(`Login Error: ${errorMsg}`);},);
</script>

后端实现

将钉钉二维码扫描得到的授权码authCode,提交到我们的第三方应用服务端授权接口。

/*** 钉钉授权码登录* @param authCode  授权码*/@GetMapping("auth")@ApiOperation("钉钉授权码登录")public Result dingTalkLogin(@RequestParam(value = "authCode") String authCode) throws Exception {Client client = DingTalkAuthClient.oauth2Client();GetUserTokenRequest tokenRequest = new GetUserTokenRequest().setClientId(appKey).setClientSecret(appSecret).setCode(authCode).setGrantType("authorization_code");GetUserTokenResponse tokenResponse = client.getUserToken(tokenRequest);String accessToken = tokenResponse.getBody().getAccessToken();// 根据用户凭证调用钉钉开放接口获取用户信息GetUserResponseBody userInfo = DingTalkAuthClient.getUserInfo(accessToken);// TODO 这里获取钉钉绑定的手机号,当然你也可以进一步去获取unionid或userid(具体根据自己实际业务去实现)String mobile = userInfo.getMobile();if(mobile == null) {return Result.error(202, "该钉钉没有绑定手机号");}// TODO 这里根据绑定的钉钉手机号获取用户凭证token(具体根据自己实际业务去实现)return loginByMobile(mobile);}

上述 DingTalkAuthClient 是我自己封装的工具类,(包含一些其他方法)代码如下:

import com.aliyun.dingtalkcontact_1_0.models.GetUserHeaders;
import com.aliyun.dingtalkcontact_1_0.models.GetUserResponseBody;
import com.aliyun.dingtalkoauth2_1_0.Client;
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest;
import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse;
import com.aliyun.teaopenapi.models.Config;
import com.aliyun.teautil.models.RuntimeOptions;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.request.OapiV2UserGetRequest;
import com.dingtalk.api.request.OapiV2UserGetuserinfoRequest;
import com.dingtalk.api.response.OapiV2UserGetResponse;
import com.dingtalk.api.response.OapiV2UserGetuserinfoResponse;
import com.xxx.core.base.exception.GlobalException;
import com.xxx.core.servlet.ApplicationContextHolder;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.TimeUnit;public class DingTalkAuthClient {public final static String DING_TALK_ACCESS_TOKEN = "dingTalk:accessToken";public static Client oauth2Client() throws Exception {Config config = new Config();config.protocol = "https";config.regionId = "central";return new Client(config);}public static com.aliyun.dingtalkcontact_1_0.Client contactClient() throws Exception {Config config = new Config();config.protocol = "https";config.regionId = "central";return new com.aliyun.dingtalkcontact_1_0.Client(config);}/*** 获取钉钉用户信息* @param accessToken 授权token* @return* @throws Exception*/public static GetUserResponseBody getUserInfo(String accessToken) throws Exception {com.aliyun.dingtalkcontact_1_0.Client client = contactClient();GetUserHeaders userHeaders = new GetUserHeaders();userHeaders.xAcsDingtalkAccessToken = accessToken;GetUserResponseBody responseBody = client.getUserWithOptions("me", userHeaders, new RuntimeOptions()).getBody();return responseBody;}/*** 获取企业内部应用accessToken* - 已实现缓存机制(自动续期)* @param appKey* @param appSecret* @return* @throws Exception*/public static String getAppAccessToken(String appKey, String appSecret) throws Exception {RedisTemplate redisTemplate = ApplicationContextHolder.getBean("redisTemplate");Long expire = redisTemplate.opsForValue().getOperations().getExpire(DING_TALK_ACCESS_TOKEN);if(expire > 120) {return (String) redisTemplate.opsForValue().get(DING_TALK_ACCESS_TOKEN);}Client client = oauth2Client();GetAccessTokenRequest accessTokenRequest = new GetAccessTokenRequest();accessTokenRequest.appKey = appKey;accessTokenRequest.appSecret = appSecret;GetAccessTokenResponse response = client.getAccessToken(accessTokenRequest);String accessToken = response.getBody().accessToken;Long expireIn = response.getBody().expireIn;redisTemplate.opsForValue().set(DING_TALK_ACCESS_TOKEN, accessToken, expireIn, TimeUnit.SECONDS);return accessToken;}/*** (钉钉应用内免密)通过accessToken* @param access_token    应用授权码* @param code  免密临时用户授权码* @return*/public static String getUseridByAccessToken(String access_token, String code) throws ApiException {DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getuserinfo");OapiV2UserGetuserinfoRequest userinfoRequest = new OapiV2UserGetuserinfoRequest();userinfoRequest.setCode(code);OapiV2UserGetuserinfoResponse response = client.execute(userinfoRequest, access_token);if(!response.isSuccess()) {log.error("调用钉钉接口失败,错误代码【{}】,错误详情:{}", response.getErrcode(), response.getErrmsg());throw new GlobalException("调用钉钉接口失败,错误原因:" + response.getErrmsg());}return response.getResult().getUserid();}/*** (钉钉应用内免密)获取钉钉用户信息* - "企业员工手机号信息权限"、“成员信息读权限”* @param appAccessToken    应用授权码* @param userid            钉钉userid* @return* @throws ApiException*/public static OapiV2UserGetResponse.UserGetResponse getUserInfoByUserid(String appAccessToken, String userid) throws ApiException {DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get");OapiV2UserGetRequest userGetRequest = new OapiV2UserGetRequest();userGetRequest.setUserid(userid);userGetRequest.setLanguage("zh_CN");OapiV2UserGetResponse response = client.execute(userGetRequest, appAccessToken);if(!response.isSuccess()) {log.error("调用钉钉接口失败,错误代码【{}】,错误详情:{}", response.getErrcode(), response.getErrmsg());throw new GlobalException("调用钉钉接口失败,错误原因:" + response.getErrmsg());}return response.getResult();}}

【新版API】实现第三方应用钉钉扫码登录相关推荐

  1. 钉钉开发系列(十一)钉钉网页扫码登录

    在<钉钉开发系列(八)二维码扫描登录的实现>介绍了一种扫码登录的方式,该方式是自己产生二维码,二维码中的URL指到自身的服务器页面,在该页面中以JSSDK的方式来获取钉钉用户的信息.钉钉官 ...

  2. 【网课平台】Day10.对接第三方:实现微信扫码登录

    文章目录 一.需求:微信扫码登录 1.接口文档 2.开发环境准备 3.接入分析 4.接口定义 5.申请令牌 6.查询用户信息 7.保存用户信息 一.需求:微信扫码登录 (和第三方对接的流程) 1.接口 ...

  3. 钉钉扫码登录cs架构,winform设计钉钉扫码客户端

    先上效果图 下面开始流程: 准备工作 你需要一个注册钉钉的账号,以获取APPID: 你还需要你要登录的第三方网站的网址,以及一张网站logo图片的地址: 具体步骤: 1.注册成功后,登录,进行如下四步 ...

  4. vue实现钉钉扫码登录第三方网站

    (1)### 登录钉钉开放平台,进入应用开发页面,此页面需要管理员开放权限才能进入 (2)### 点击[创建应用],圈出的三部分填写完之后点击[确定创建] (3)### 切换到新版,钉钉登录与分享中填 ...

  5. 钉钉扫码登录第三方_在钉钉发布公司重要文件,真的安全吗?

    钉钉以疫情在家办公为契机,加上"幸运地"被教育部"选中",在2月5日,钉钉下载量首次超过微信,跃居苹果App Store排行榜第一,并打破App Store记录 ...

  6. 钉钉授权第三方WEB网站扫码登录

    一.阅读开发文档 首先阅读钉钉官方的开发文档,扫码登录其实用的是官方文档描述的第二种方式,即将钉钉登录二维码内嵌到自己页面中,用户使用钉钉扫码登录第三方网站,网站可以拿到钉钉的用户信息. 二.准备工作 ...

  7. 钉钉扫码登录第三方_e签宝联合钉钉升级产品功能,共建企业服务生态闭环

    钉钉微应用更新了,e签宝助力升级.互联网时代下,传统模式的"稳定"已然成为历史,客户的需求在不断变化,我们创新的脚步也从未停止. e签宝携手钉钉,双方着力共建开放.共生.多赢的企业 ...

  8. 使用第三方账号认证(一):钉钉扫码登录

    一.需求 要使用钉钉扫码登录,也就是需要把kintone的登录画面替换成扫码画面. 而在扫码后,则需要获取钉钉用户的身份信息并将其转化为对应的kintone用户. 最后服务端生成相应的session, ...

  9. vue3 钉钉扫码登录第三方网站 最新解决方案

    vue3 钉钉扫码登录 最新解决方案 主要是使用方法和踩坑吧,坑踩的挺大,有vue3一起踩坑的可以相互讨论哈 注意看注释,很多注意点在注释和总结那里 往index.html 添加引入 <scri ...

最新文章

  1. Mozilla开源了VR框架A-Frame
  2. Java中的图像锐化操作
  3. 在symfony2项目中100%提升doctrine的性能
  4. python3最新稳定版本-python3稳定版
  5. nginx php fpm sock_nginx使用sock方式调用php-fpm
  6. php点击按钮变文字,点击按钮文字变成input框,点击保存变成文字的实现
  7. springCloud - 第10篇 - 服务间调用追踪 (zipkin 的使用)
  8. 项目经历怎么写_这样写项目经历可以锦上添花
  9. ASP.NET设置发帖时间间隔不超过30秒
  10. 索尼电视总出现Android,索尼BRAVIA电视推送更新:升级安卓8.0,修复众多问题
  11. 程序员零下20度雪地求婚快冻伤 女友却崩溃了
  12. [C语言]显示器【模拟】
  13. php doctrine datetime,php – doctrine和Symfony 2中的DateTime字段
  14. HTTP API接口设计规范
  15. 数字签名与数字证书技术简介(一)
  16. i3-10110U和i5 1035g7 哪个好
  17. 信号量机制实现进程互斥与同步,生产者消费者
  18. 万向节锁--简单解释
  19. Vue CLI 官方文档(一)@vue/cli、@vue/cli-service、插件和 Preset
  20. nginx+keepalived+tomcat+memcache负载均衡搭建小集群

热门文章

  1. vs,qt编程软件中,光标变粗
  2. Java15异常处理
  3. linux取消挂载命令
  4. jpa使用findById
  5. 如何通过软件优化可编程无线测试?
  6. php和Apache安装配置
  7. sdk与开放API协议支持二次开发的摄像头
  8. chm文件打开空白无内容的解决办法
  9. mysql tinyint 与char_mysql tinyint和char(1)性能对比
  10. 马云对话80、90后:永远保持乐观