1、场景描述

我们开发了一个钉钉应用,但是客户要求手机端要使用微信。这样的话,我们给客户的解决方案是后台管理功能监控功能使用的钉钉(主要是依托于钉钉的人员,部门,角色的管理,我们应用本身就没有做相关的维护页面),手机端使用公众号。

这样的话,就带来了一个问题,由于我们应用是依托于钉钉的,没有自己的账号体系。所以就必须使用钉钉的账号来登录。

2、开发环境

1、前后端分离。前端使用的vue

2、后端是springboot 工程

3、实际开发

(1)技术选型经过

1、首先我们是想用微信小程序来开发,但是发现小程序的web-view没法实现,尤其是我们还是用的钉钉,光是跳转域名的审核就没法通过,审核需要的验证文件我们根本没办法放到钉钉的域名下。所以就选择普通的H5工程。

2、找到钉钉官方文档,这里有两种方式,扫码和账号密码。

这里由于我们本就是为了手机端做的,扫码登录这个就不考虑了。选用账号密码。

(2)步骤

接下来是步骤,基本上是按照官方文档来的,不过有些地方我加上了截图

1、首先是登录开发者后台,选择应用开发 > 移动接入应用 > 登录,然后单击创建扫码登录应用授权,创建用于免登过程中验证身份的appId及appSecret,创建后即可看到appId和appSecret。

位置:

单击“创建扫码登录应用授权”按钮,弹出以下对话框

加完之后,能够得到AppId和appSecret。

注:所有的字段中,只有描述没有实际的用途,其他的字段都很重要

2、构造要跳转的链接

构造如下跳转链接,此链接处理成功后,会重定向跳转到指定的redirect_uri并向url追加临时授权码code及state两个参数

1

https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=APPID&response_type=code&scope=snsapi_login&state=STATE&redirect_uri=REDIRECT_URI

根据我上面的参数,构造的url是

1

https://oapi.dingtalk.com/connect/oauth2/sns_authorize?appid=dingoaddugp123ueic122dbpxf6v2wq71yn81&response_type=code&scope=snsapi_login&state=STATE&&redirect_uri=http://192.168.0.16:8080/#/

其中需要注意的是:

redirect_uri 的参数值必须是申请扫码登录授权应用的回调url。如果一直但是还是有问题,看看是否是没有urlencode编码导致的。

在浏览器中查看构造好的url

如果错了的话,提示

如果正确的话,就能够跳转到第三方登录页面。图片因为用的百度的,是403 (Forbidden)了。这个换成可用的图片url就可以了。

单击登录账号,

输入手机号和密码,单击授权登录,就会跳转到我们指定的回调地址上并添加上临时授权码

我们的工程是vue,所以我的回调地址直接就是前段的地址。

这里前端从url中拿到临时授权码,用这个授权码请求我的后端,获取用户的信息,完成整个登录过程

后端代码

controller

@ApiOperation("第三方网站使用钉钉账号登录")@RequestMapping(value = "/third-party/login", method = RequestMethod.GET)public ResponseMessage<DingUserDto> thirdPartyLogin(@ApiParam("临时授权码") @RequestParam("code") @NotBlank(message = "授权Code 不能为空") String code) throws Exception {return ResponseMessage.ok(dingUserService.thirdPartyLogin(code));}

service

获取用户信息的步骤,首先是unionId。

这个unionId是用户在钉钉的唯一标识。我的理解是手机号的替代。因为手机号虽然也具有唯一性,但是信息太敏感,所以给用户添加了一个unionId来唯一区分各个用户。

我们在进行应用开发的时候还有一个概念叫userId。这个userId是针对组织而言的。也就是,同样一个用户,不同的组织当中userId是不一样的。

举例子

我用手机号(13512341234)申请了一个钉钉账号,我会获得一个unionId,比如dingunion1234

后来我加入了公司A,那么我的unionId依然还是dingunion1234,我在这个公司的urserId是dinguser987654

我同时又加入了公司B,那么我的unionId依然还是dingunion1234,但是我在公司B的urserId就变成了dinguser29387928

这样的话其实就可以看到,unionId + 企业corpId就可以唯一确定userId

后面也是这么获取用户信息的,只不过企业coprId要换成企业accessToken

1、通过临时授权码(一次性的,用过就失效)获取用户的unionId。

public OapiSnsGetuserinfoBycodeResponse getUserInfoByCode(String code) {DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/sns/getuserinfo_bycode");OapiSnsGetuserinfoBycodeRequest reqBycodeRequest = new OapiSnsGetuserinfoBycodeRequest();// code临时授权码reqBycodeRequest.setTmpAuthCode(code);OapiSnsGetuserinfoBycodeResponse response;try {response = client.execute(reqBycodeRequest, dingSnsPropertiesConfig.getAppId(), dingSnsPropertiesConfig.getAppSecret());} catch (ApiException e) {log.info(e.toString(), e);return null;}if (response == null || !response.isSuccess()) {return null;}return response;}

2、获取企业accessToken

public static OapiServiceGetCorpTokenResponse getCorpTokenUtil(String corpId, String suiteTicket, String suiteKey, String suiteSecret) {long timestamp = System.currentTimeMillis();String signature = DingTalkSignatureUtil.computeSignature(suiteSecret, DingTalkSignatureUtil.getCanonicalStringForIsv(timestamp, suiteTicket));Map<String, String> params = new LinkedHashMap<>();params.put("timestamp", "" + timestamp);params.put("suiteTicket", suiteTicket);params.put("accessKey", suiteKey);params.put("signature", signature);String queryString = DingTalkSignatureUtil.paramToQueryString(params, "utf-8");DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/service/get_corp_token?" + queryString);OapiServiceGetCorpTokenRequest request = new OapiServiceGetCorpTokenRequest();request.setAuthCorpid(corpId);try {return client.execute(request, suiteKey, suiteSecret, suiteTicket);} catch (ApiException e) {e.printStackTrace();throw new DingApiException("获取企业 token 异常,详情:" + e.getErrCode() + "-" + e.getErrMsg() + ":" + e.getSubErrCode() + "-" + e.getSubErrMsg());} finally {log.info("GetCorpTokenUtil 耗时:{}", System.currentTimeMillis() - timestamp);}}

3、根据企业的accessToken和unionId获取用户信息

public OapiUserGetbyunionidResponse getByUnionId(String unionId, String accessToken) {DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/getbyunionid");OapiUserGetbyunionidRequest req = new OapiUserGetbyunionidRequest();req.setUnionid(unionId);OapiUserGetbyunionidResponse response;try {response = client.execute(req, accessToken);} catch (ApiException e) {log.info(e.toString(), e);return null;}if (response == null || !response.isSuccess()) {return null;}return response;}

到此为止,我们获取到了该用户的userid,名称,角色,corpId等信息。

剩下的根据自己的业务做处理就行了。

企业自建应用使用钉钉账号密码登录(钉钉第三方登录)相关推荐

  1. linux 本地账号密码无法登陆(shell可以登录),一直返回 登陆的login界面

    今天我在我虚拟机测试的时候遇到了一个问题.登陆centos一直是返回login,账号和密码没错,我也换了两个用户. 1.问题描述 我正常的输入用户名和密码 错误提示截图:返回登陆界面,我重新试了另外的 ...

  2. oracle shell 登录,linux 本地账号密码无法登陆(shell可以登录),一直返回 登陆的login界面...

    今天我在我虚拟机测试的时候遇到了一个问题.登陆centos一直是返回login,账号和密码没错,我也换了两个用户. 1.问题描述 我正常的输入用户名和密码 错误提示截图:返回登陆界面,我重新试了另外的 ...

  3. python账号密码一一对应_python模拟用户登录系统,如何两个用户输入各自的密码才能登入?...

    展开全部 #我可以把我自己2113的成果送你,你来研究5261研究 import json #用来存储数据4102的模块 import os #用来进行文件操作1653 import sys #获取脚 ...

  4. session模拟登录怎么传账号密码_三国群英传全系列登录Steam;合金装备V主题仿生手臂;了不起的修仙模拟器 推出首个DLC...

    点击蓝字[游戏风云]关注我们~ <三国群英传>全系列登录Steam 新闻来源:游戏风云 <三国群英传8>将于2021年1月13日发售,为了更好的让新老玩家重温经典,官方将系列1 ...

  5. 企业邮箱登录地址,邮箱登录入口,邮箱登录须知

    企业邮箱注册后,有很多登录方式选择,TOM企业邮箱可在官方网页端.独立定制登录页.微信端.手机APP.电脑邮箱客户端.接下来给大家一一介绍下~ 官方统一登录页 喜欢用网页端的用户,一般从统一登录页面登 ...

  6. 网站输入正确账号密码页面刷新一下_Folx的密码管理保存网站登陆信息

    Folx的密码管理保存网站登陆信息 大家下载某个文件时,需要登录文件所在的网站才能进行下载,否则哪怕有下载链接也无权限进行文件下载,那Folx遇到这种情况是否就无法使用了呢?Folx的密码管理也能保存 ...

  7. 使用Socket实现账号密码验证

    客户端: 1. 提示用户输入用户名和密码,将用户输入的用户名和密码发送给服务端 2. 接收服务端验证完用户名和密码的结果 服务端: 1. 服务端设置一组账号.密码作为合法账号 2. 接收客户端发送过来 ...

  8. iOS 手机记录登录账号密码列表

    当在开发的过程中,我们可能需要记录一下登陆过的账号密码,为了用户方便登录时再次操作. 举个例子:当我们退出登录的时候,换一个账号登录的时候我们就可以在记录的账号列表中选择想要的账号,直接就可以登录了. ...

  9. google 云开启 ssh 账号密码登录

    google 云开启 ssh 账号密码登录 1.新买的 google 服务器是不支持使用账号密码通过 ssh 登录的,这样就很不方便,要使用账号密码登录需要修改 ssh 配置文件. 先通过浏览器打开 ...

最新文章

  1. 在react hook里使用mobx(配置mobx依赖)
  2. 基于mpi的奇偶排序_并行程序设计(第2版)pdf
  3. i 智慧 | IBM存储:全面贯彻新存储的“智慧之道”
  4. linux usb键盘驱动详解
  5. 从零基础入门Tensorflow2.0 ----五、26TF1.0tf_data,make_initializable_iteror()
  6. PGIS平台部署中的问题及解决方案
  7. 用Python搭建股票舆情分析系统
  8. AD9 设置网络标号作用域 (NET 全局)
  9. 简述对CAN协议栈的理解
  10. 微信公众号跳转小程序,详细教程
  11. 360wifi: 手机锁屏360wifi掉线的解决方法
  12. signature=530d9c5e7e99d796faa35352560aede4,Visual Detection of Volcanic Plumes
  13. LeetCode-86
  14. 六轴机器人轨迹规划之五段位置s曲线插补
  15. 自定义Spark累加器
  16. 输入过压保护电路OVP原理和仿真
  17. .NET报错:所生成项目的处理器框架“MSIL”与引用“xxx”的处理器架构“AMD64”不匹配
  18. k8s学习笔记——k8s pv rbd手动挂载
  19. 启示录:TOD分类及用地功能结构组成
  20. db2 - 统计上一月,前两周的数据

热门文章

  1. 绘制一个五角星和六角形
  2. 【学习方式】开源项目
  3. mac下通过gcc命令手动编译动态链接库示例
  4. spring boot如何进行统一版本的管理呢
  5. JS之简易日历的制作
  6. 电容器法拉、库仑、放电毫安时换算
  7. Python脚本批量读取哨兵2号(Sentinel2)影像并另存为Geotiff格式
  8. spark求共同好友
  9. MySql 8.0新特性:窗口函数
  10. mysql 证书双向认证_https证书双向验证