Spring Boot 接入钉钉扫码登录

  • 公司如果有在使用钉钉,向企业管理员申请一个开发者权限。
  • 如果觉得麻烦,可以自己去钉钉平台注册一个企业,不需要认证的。

创建第三方授权应用

1、 选择 工作台 tab 页 2、 拉取至末尾,选择自建应用/或者直接进入 钉钉开发者后台:

3、 在开发者后台页面,选择企业内部开发,然后单击创建应用

4、 在弹出的页面中填写基本信息,然后单击确定创建。

  • 应用类型:选择H5微应用。
  • 开发方式:选择企业自主开发。

5、应用创建完成后,在基础信息页面,复制应用的AppKeyAppSecret备用,后面会使用到!

6、单击开发管理进入开发管理页面,然后单击修改,并根据以下内容配置开发信息。

注意:服务器出口IP是公网IP。 应用首页地址填写后端服务部署的服务器的IP或域名

添加接口权限

1.登录开发者后台-点击应用开发-企业内部应用,找到对应的应用并点击。

2.单击权限管理进入权限管理页面,根据以下配置添加接口调用权限。

(1)权限范围选择全部员工

(2)选择个人权限,申请个人手机号信息通讯录个人信息读权限。

配置花生壳域名

如果还没有的话,可以买一个。我记得当时花了 6 元,体验版内网穿透永久使用。如果价格变了,可以评论区联系我,我帮你进行映射。也可以自己去使用 natApp,其实无所谓使用什么,只要钉钉能请求到你的服务就行!

花生壳官网

设置第三方网站的回调域名

  1. 登录开发者后台,找到对应的应用,并点击应用。
  2. 单击登录与分享,填写回调域名,点击添加

    这个回调域名对应后端服务真实存在的接口。

编码

基本思路

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需要是当前用户所在的组织。
exclusiveLogintrue表示专属帐号登录,展示组织代码输入页。
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接口得到 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);
}
复制代码
/**
 * 获取用户通讯录个人信息
 * @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。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值