钉钉扫码登录-PHP版本
今天写了一个第三方登录的功能,使用的是钉钉,实现的功能就是打开网页,使用的钉钉APP扫描二维码,快捷登录网站,下面一起来看一下!
钉钉开放平台
首先,登录管理后台,点击右上角进行登录,这里的登录需要是管理员身份或者授权权限的子管理员身份,其他的身份不好使,如果没有管理员身份或子管理员身份(如我一样),那么就只能自己创建一个团队了,里面邀请了好友就可以了。这样你就是拥有管理员身份了。继而可以登录这个管理后台了(第一次登录需要设置个密码,后续登录时需要输入的)。
创建应用
进入管理页面后,我们进入应用开发菜单,找到最下方的“移动接入应用”,进入子级菜单中的“登录”,在里面创建一个应用。如下图:
创建应用后,回到页面中,我们可以看到 appid 和 appSecret 这两项参数,后续我们会用到。
授权流程
第三方发起钉钉授权登录请求,钉钉用户允许授权第三方应用后,钉钉会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数。
通过code调用接口getuserinfo_bycode获取授权登录用户信息。
构造扫码登录页面
构建登录页面有两种方式,我们以跳转方式为例,这种方式使用得较多,也非常方便。在企业Web系统里,用户点击使用钉钉扫描登录,第三方Web系统跳转到如下地址:地址就不做展示了,说一下地址的参数:
获取用户信息
首先说一下,我们获取到的用户信息只有三项,如下表:
但是在下午的实际测试中发现,接口返回的值还多了两项,文档中没有做出说明,猜测是权限字段和权限标识字段。
在获取用户信息时我们要使用到的参数有如下:
在请求的时候需要使用POST方式并传递数据,数据如下:
{"tmp_auth_code": "23152698ea18304da4d0ce1xxxxx"}
这里需要注意一点,传递数据为json格式,如果使用CURL进行请求时会出现post请求数据格式错误的提示,我们需要在curl请求头上面做出说明,代码如下:
$header = [ "Content-Type: application/json; charset=utf-8", "Content-Length:" . strlen(json_encode($postFields)) ]; curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
代码
<?php /** * Created by PhpStorm. * User: Administrator * Date: 2020/4/3 0003 * Time: 11:27 */ namespace app\controller; use think\Controller; class Login extends Controller { /** * 登录 * @return \think\response\View */ public function index() { // 临时关闭模板布局 $this->view->engine->layout(false); return view("login/index"); } public function out() { } public function back() { $code = input('get.code'); $state = input('get.state'); if(!$code or !$state) { $this->error('参数缺失'); } if($state > time()) { $this->error('参数异常'); } $accessKey = 'dingoa9f8qj1**********'; $timestamp = $this->mTime(); $signature = $this->signature($timestamp); $url = 'https://oapi.dingtalk.com/sns/getuserinfo_bycode?accessKey=' . $accessKey . '×tamp=' . $timestamp . '&signature=' . $signature; $data = [ 'tmp_auth_code' => $code ]; $userInfo = $this->curl_json($url, $data); $res = json_decode($userInfo, true); if(isset($res['errcode']) and $res['errcode'] == 0) { //登录成功 echo 1; } } /** * 计算签名 * @param $timestamp * @return string */ public function signature($timestamp) { // 根据timestamp, appSecret计算签名值 $s = hash_hmac('sha256', $timestamp, '**********G6KaiRey7NFJxXHyBthsPL5Q4rBSvlJhQvREadhO__uHhDs', true); $signature = base64_encode($s); $urlEncode_signature = urlencode($signature); return $urlEncode_signature; } /** * 毫秒级时间戳 * @return float */ public function mTime() { list($s1, $s2) = explode(' ', microtime()); $mTime = (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000); return $mTime; } public function curl_json($url, $postFields = null) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_FAILONERROR, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, "dingtalk-sdk-php"); //https 请求 if(strlen($url) > 5 && strtolower(substr($url, 0, 5)) == "https") { curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); } curl_setopt($ch, CURLOPT_POST, true); $header = [ "Content-Type: application/json; charset=utf-8", "Content-Length:" . strlen(json_encode($postFields)) ]; curl_setopt($ch, CURLOPT_HTTPHEADER, $header); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postFields)); $reponse = curl_exec($ch); if(curl_errno($ch)) { throw new Exception(curl_error($ch), 0); } else { $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); if(200 !== $httpStatusCode) { throw new Exception($reponse, $httpStatusCode); } } curl_close($ch); return $reponse; } }