yii2项目实战-第三方登录的实现

第三方登陆,想必很多网站都会支持,比如国内常见的qq登录,微博登录,当然国外的google,facebook等等。虽然各网站都支持OAuth2的方式接入,但是,如果一个应用要支持很多第三方登录,就需要我们根据各平台的文档,写很多接口,很繁琐的一件事。今天我们就准备借助yii2-authclient组件,化繁为简。

本文我们将以一个完整版的web端实现QQ登录为例,来了解那些基于OAuth2.0标准协议的开放授权。

首先我们先解释几个名词,方便各位了解

1、OAuth: OAuth(开放授权)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的所有内容。

2、OAuth2.0:对于用户相关的OpenAPI(例如获取用户信息,动态同步,照片,日志,分享等),为了保护用户数据的安全和隐私,第三方网站访问用户数据前都需要显式的向用户征求授权。

QQ登录OAuth2.0采用OAuth2.0标准协议来进行用户身份验证和获取用户授权,相对于之前的OAuth1.0协议,其认证流程也更简单和安全。

继续来看一下OAuth2.0总体处理流程

Step1:在各平台申请接入,获取appid和apikey;
Step2:开发应用,并设置协作者帐号进行测试联调;
Step3:放置第三方登录按钮(创建可访问链接);
Step4:通过用户登录验证和授权,获取Access Token;
Step5:通过Access Token获取用户的OpenID;
Step6:调用OpenAPI,来请求访问或修改用户授权的资源。
如果你是第一次接触第三方登录,上面Step1-Step6共6个步骤,还希望你能看上个两三遍,下面我们的实现也会按照上面的6个步骤进行。

以Web应用接入QQ登录为例,Step1~Step2就不说了,很简单,去“qq互联”申请帐号并获取appid和apikey即可(如果是其他平台,请自行搜索去哪里申请哦)。另外需要提醒的是,个人的应用用自己的qq申请是没问题的,如果是公司的应用,建议不要使用个人的微博来接入应用,避免各位离开当前公司后带来不必要的麻烦。

Step3,其实就是我们应用的一个可访问地址,我们访问这个地址,随后让用户在qq平台用他自己的qq帐号进行登录(这已经是Step4了)。通常为了获取Access Token,我们需要先获取Authorization Code,拿着这个Authorization Code才能获取Access Token。结合Step5~Step6,我们来看下稍微比上面细节化的一些分析

请求https://graph.qq.com/oauth2.0/authorize 获取Authorization Code
携带上面的Code码,请求https://graph.qq.com/oauth2.0/token 获取Access Token
携带上面的Access Token,请求https://graph.qq.com/oauth2.0/me 获取用户的OpenID
调用OpenAPI等接口获取用户的信息
从上面的步骤来看,qq的稍微麻烦些,这个等各位看完本文后,再去接入其他平台登录就有体会。

也就是说,我们要在Step3中,请求一个你的应用地址,随后完成上面一系列的动作,才能正确的获取用户在qq平台的一些个人信息。来一张图加深下理解

当然,上面我们所描述的一大堆,其实你可以在qq开放平台的文档内找到。

有同学有想法了,我自己写一个类,接二连三的发请求就能解决这个问题。没错,实际上我们要借助的authclient组件他也是这么干的。

下面我们看下如何借助yii2-authclient组件实现这一切操作。

利用composer安装authclient组件,此时此刻各位安装的应该是2.1版本的authclient,鉴于网络上很多对2.0版本的封装,还请各位能够慧眼识别。

1
composer require --prefer-dist yiisoft/yii2-authclient

在应用的配置文件中添加authClientCollection组件

1
2
3
4
5
6
7
8
9
10
11
12
'authClientCollection' => [
'class' => 'yii\authclient\Collection',
'clients' => [
// qq这个键名我们后面访问链接的使用有用到
'qq' => [
'class' => 'frontend\components\AuthClientQq',
'clientId' => '你的appid',
'clientSecret' => '你的apikey',
],
// etc.
],
],

上面的配置项各位需要注意两点

1、clients是所有第三方登录的配置,key值我们这里写的qq,你也可以在下面继续罗列weibo,github等等

2、frontend\components\AuthClientQq这个类是yii\authclient\OAuth2的子类,用于配置一些最基本的信息,以后我们有新增的第三方登录,凡是遵循OAuth标准的,拷贝一份AuthClientQq类,改改配置即可

来看下 frontend\components\AuthClientQq类的具体实现,基于yii2-authclient 2.1的实现

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<?php
namespace frontend\components;

use yii\authclient\OAuth2;
use yii\web\HttpException;
use Yii;

class AuthClientQq extends OAuth2
{
/**
* @inheritdoc
*/
public $authUrl = 'https://graph.qq.com/oauth2.0/authorize';
/**
* @inheritdoc
*/
public $tokenUrl = 'https://graph.qq.com/oauth2.0/token';
/**
* @inheritdoc
*/
public $apiBaseUrl = 'https://graph.qq.com';

/**
* @inheritdoc
*/
public function init()
{
parent::init();
if ($this->scope === null) {
$this->scope = implode(' ', [
'get_user_info',
]);
}
}

protected function initUserAttributes()
{
$userAttributes = $this->api(
'user/get_user_info',
'GET',
[
'oauth_consumer_key' => $this->user->client_id,
'openid' => $this->user->openid
]
);

$userAttributes['id'] = $this->user->openid;
$userAttributes['login'] = $userAttributes['nickname'];
return $userAttributes;
}

/**
* @inheritdoc
*/
protected function getUser()
{
$result = file_get_contents($this->apiBaseUrl . '/oauth2.0/me?access_token=' . $this->accessToken->token);

if (strpos($result, "callback") !== false) {
$result = str_replace(['callback( ', ' );'], '', $result);
}

return json_decode($result);
}

/**
* @inheritdoc
*/
protected function defaultName()
{
return 'qq';
}
/**
* @inheritdoc
*/
protected function defaultTitle()
{
return 'QQ';
}
}

有没有发现我们配置的是啥?没错,我们配置的就是获取授权码、token的地址以及获取api的域名,这样就行了?来看看呗

回到Step3,我们要创建一个可访问的链接,如此,才能更好的衔接起这一切。

这个链接创建起来可没那么轻松,来看下怎么创建

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 frontend\controllers;

use Yii;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\helpers\ArrayHelper;

/**
* UserController
*/
class UserController extends Controller
{
/**
* @inheritdoc
*/
public function actions()
{
return [
'auth' => [
'class' => 'yii\authclient\AuthAction',
'successCallback' => [$this, 'onAuthSuccess'],
],
];
}

public static function onAuthSuccess ($client)
{
$attributes = $client->getUserAttributes();
$email = ArrayHelper::getValue($attributes, 'email');
$id = ArrayHelper::getValue($attributes, 'id');
$nickname = ArrayHelper::getValue($attributes, 'login');

yii::info($email, 'qq-successCallback-email');
yii::info($id, 'qq-successCallback-id');
yii::info($nickname, 'qq-successCallback-nickname');
}
}

来谈一下上文的注意点

1、此处的访问地址很明显是 /user/auth,但是,请一定要保证该地址跟你当初申请appid时的那个应用填写的回调地址一致!不然会失败哦

2、successCallback指定qq登录成功后的将要调用的处理函数,少不得,这个也是我们将要把获取到的信息进一步处理的方法

现在,你只需要访问 /user/auth?authclient=qq(authclient的值等同于clients配置的key哦)就会跳转到qq登录的页面了。如果你能正确的看到下面这个相似页面,恭喜你,你离成功还差一小步

接着登录试试,看看有什么小惊喜?

我们在debug中记录了用户的email,openId以及nickname,各位可以在debug中查看。但是请先不要happy,我们还差最后一步,把该用户的信息同步到我们自己的数据库中,而且下次用户登录的时候,我们要更新用户的信息,比如昵称等。

UserController的onAuthSuccess回调方法我们不准备再实现了,毕竟一来没有什么知识点要说,二来每个人的表设计不一,这里列出authclient官方给出的一个例子参考 https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/quick-start.md

到此为止呢,各位qq登录应该都实现了,有时间和精力的话,不妨再利用authclient实现其他平台的登录,authclient默认有facebook、github等众多平台,其他平台的实现位于 vendor\yiisoft\yii2-authclient\clients目录下,注意哦,凡是支持OAuth1,OAuth2的第三方登录,都只需要简单的配置就好了。第三方登录以后都不是事!