前言

单位需要对接浙政钉,实现扫码登录,这里记录一下对接过程。

浙政钉扫码登录

登录入口

开发者登录

扫码流程图

扫码登录准备工作

创建轻应用

创建轻应用

获取appKey和appSecret

获取

配置回调地址

配置回调地址

扫码登录对接

各环境域名/登录域名

环境 开放平台域名(调接口使用) 登录域名(构造登录页面)
Saas openplatform.dg-work.cn login.dg-work.cn
浙政钉 openplatform-pro.ding.zj.gov.cn(域名对应政务外网IP:59.202.52.1) login-pro.ding.zj.gov.cn

构造扫码登录页面

使用专有钉钉提供的扫码登录页面

在企业Web系统里,用户点击使用钉钉扫码登录,第三方Web系统跳转到如下地址:

1
https://login.dg-work.cn/oauth2/auth.htm?response_type=code&client_id=应用标识&redirect_uri=回调地址&scope=get_user_info&authType=QRCODE

URL中的client_idredirect_uri两个参数的值填入第三方web系统的应用标识和回调地址。专有钉钉用户扫码登录并确认后,会302到你指定的redirect_uri,并向url参数中追加临时授权码code

codeauthcodestate两个参数。
authcodeweb端使用jsapi获取的临时code
参数redirect_uri=回调地址”涉及的域名,需和创建扫码登录应用授权时填写的回调域名一致,否则会提示无权限访问

支持网站将专有钉钉登录二维码内嵌到自己页面中

通过方式一构造的地址增加embedMode=true的参数

1
https://login.dg-work.cn/oauth2/auth.htm?response_type=code&client_id=应用标识&redirect_uri=回调地址&scope=get_user_info&authType=QRCODE&embedMode=true

扫码成功后需要在页面中监听结果
1
2
3
4
5
6
7
<script type="application/javascript">
window.addEventListener('message', function(event) {
// 这里的event.data 就是登录成功的信息
// 数据格式:{ "code": "aaaa", "state": "bbbb" }
alert(JSON.stringify(event.data));
});
</script>

生成的二维码size固定为 200*200px,不支持修改

获取应用access_token

获取access_token,请参考获取access_token。注意请使用扫码应用的ak/sk获取access_token

请求方式

GET(HTTPS)

接口名

/gettoken.json

请求参数

参数名 类型 是否必须 说明
appkey string 应用唯一标识,创建应用后获得
appsecret string 应用密钥,创建应用后获得

例子(PHP)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php

namespace App\Handlers;

use App\Services\Zwdd\ExecutableClient;
use Exception;
use Illuminate\Support\Facades\Log;

class DingHandler
{
private static string $getAccessTokenApi = "/gettoken.json";

private static function getAccessToken():string{
$form_params = array('appkey' : config('isv.login_ak'), 'appsecret' : config('isv.login_sk'));
$ret = self::get(self::$getAccessTokenApi, $form_params);
return $ret['data']['accessToken'];
}
private static function get($api,$form_params = []) {
$domain = config('isv.domain');
$ak = config('isv.login_ak');
$sk = config('isv.login_sk');

try {
$executableClient = new ExecutableClient();
$executableClient->setDomain($domain);
$executableClient->setAccessKey($ak);
$executableClient->setSecretKey($sk);
$executableClient->setApiName($api);
foreach ($form_params as $key : $value) {
$executableClient->addParameter($key,$value);
}
$ret = $executableClient->epaasCurlGet(3);
return $ret;
} catch (Exception $e) {
$msg = "getFilterWords|err, code: ". $e->getCode() . "|message: ". $e->getMessage();
error_log($msg);
}
}

}

返回结果

1
2
3
4
5
6
7
8
9
10
11
{
"data": {
"expiresIn": 7200,
"accessToken": "app_xxxxxxxxxxxxxxxxxxxxxxxxx"
},
"success": true,
"requestId": "ac111111111111111111111111111",
"responseMessage": "OK",
"responseCode": "0",
"bizErrorCode": "0"
}
参数名 类型 说明
access_token string 应用的access_token
expires_in int access_token的过期时间,单位为秒

获取授权用户的个人信息

服务端通过临时授权码获取授权用户的个人信息

请求方式

POST(HTTPS)

接口名

/rpc/oauth2/getuserinfo_bycode.json

注意:请使用接口域名调用接口,不能使用登录域名调接口。

请求参数

参数名 类型 是否必须 说明
access_token string 应用的access_token
code string 用户授权的临时授权码code,只能使用一次;在前面步骤中跳转到redirect_uri时会追加code参数

例子(PHP)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php

namespace App\Handlers;

use App\Services\Zwdd\ExecutableClient;
use Exception;
use Illuminate\Support\Facades\Log;

class DingHandler
{
private static string $getUserInfoByCodeApi = "/rpc/oauth2/getuserinfo_bycode.json";

private static function getUserInfoByCode():string{
$form_params = array('code' : $code,'access_token' : self::getAccessToken());
$ret = self::post(self::$getUserInfoByCodeApi, $form_params);
}
private static function post($api,$form_params = []) {
$domain = config('isv.domain');
$ak = config('isv.login_ak');
$sk = config('isv.login_sk');

try {
$executableClient = new ExecutableClient();
$executableClient->setDomain($domain);
$executableClient->setAccessKey($ak);
$executableClient->setSecretKey($sk);
$executableClient->setApiName($api);
foreach ($form_params as $key : $value) {
$executableClient->addParameter($key,$value);
}
$ret = $executableClient->epaasCurlPost(3);
return $ret;
} catch (Exception $e) {
$msg = "getFilterWords|err, code: ". $e->getCode() . "|message: ". $e->getMessage();
error_log($msg);
}
}

}

返回结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"data": {
"lastName": "测试",
"accountId": 1,
"realmId": 1,
"clientId": "client_id",
"tenantName": "xx",
"realmName": "xx",
"namespace": "local",
"tenantId": 1,
"nickNameCn": "测试",
"tenantUserId": "1",
"account": "cs-xxx",
"employeeCode": "GE_0bd0c7e84baa4dxxxxxxxf334e6f"
},
"success": true,
"responseMessage": "成功",
"responseCode": "0"
}
参数名 类型 说明
accountId int 账号id
realmId int 租户id
clientId string 应用id
tenantName string 租户名称
realmName string 租户名称
namespace string 租户命名空间
tenantId int 租户id
tenantUserId string 租户用户id
account string 账号
employeeCode string 员工编码