![最终产品图片](https://i-blog.csdnimg.cn/blog_migrate/9927e5475c468eb4659c8a767b9913c5.png)
本教程是Envato Tuts +上的“ 使用PHP构建启动”系列的一部分。 在本系列文章中,我将以我的Meeting Planner应用程序作为真实示例,指导您完成从概念到现实的启动。 在此过程的每一步中,我都会将Meeting Planner代码作为开放源代码示例发布,您可以从中学习。 我还将解决与启动相关的业务问题。
在本教程中,我将指导您完成与常见社交网络的OAuth集成 ,以使注册和重复使用更加轻松和高效。 我将探索Facebook,Google,Twitter和LinkedIn,这是我认为最适合Meeting Planner的目标用户的网络。
Meeting Planner的所有代码都是在PHP的Yii2框架中编写的。 如果您想了解有关Yii2的更多信息,请查看Envato Tuts +上的并行系列“ 使用Yii2编程” 。
如果您还没有尝试过Meeting Planner,请立即尝试安排您的第一次会议 。 今年真的开始融合了。 最终,我能够使用Yii2的内置AuthClient支持来从上述所有网络提供登录,因此您可以立即使用它们进行注册。
欢迎反馈。 如果您有任何问题或建议,请在下面发表评论。 您也可以通过Twitter @reifman与我联系 。
什么是AuthClient?
AuthClient是Yii的内置支持,可让您的应用程序通过具有OpenID , OAuth或OAuth2的第三方服务进行身份验证。
如果您在2015年6月遵循我的Yii2系列,您会看到我使用AuthClient通过OpenID与Google集成 ,但是该公司不久之后就停止了对该规范的支持。 然后,在12月,我编写了一个教程,该教程使用Yii2-User扩展来添加Google OAuth支持 -Yii2 Framework尚无此功能。 但是,Yii2-User无法与已经具有面向用户的代码库的已建立代码库很好地集成。 但幸运的是,此后Yii2框架增加了对Google OAuth的支持,并且一切都变得更加简单了。
在本教程中,我将指导您使用新的AuthClient功能与各种流行的社交网络集成。 开箱即用,Yii为以下客户提供支持:
支持通过社交网络连接到Meeting Planner的另一个动机是,它允许人们露面并轻松地与我们分享他们的姓名和电子邮件。 通过电子邮件和密码注册,我们实际上从未得知它们的名称。 但是,与其他社交网络不同,Twitter为获取用户的电子邮件地址造成了很大的问题,最终导致我暂时将其禁用。
让我们开始进行代码集成。
在我们的应用程序中安装AuthClient
首先,我们需要为OAuth安装Yii组件,即Yii的AuthClient 。
将AuthClient添加到Composer
让我们将AuthClient库添加到composer.json中:
"minimum-stability": "stable",
"require": {
"php": ">=5.4.0",
"yiisoft/yii2": "*",
"yiisoft/yii2-bootstrap": "*",
"yiisoft/yii2-swiftmailer": "*",
"2amigos/yii2-google-maps-library": "*",
"2amigos/yii2-google-places-library": "*",
"stichoza/google-translate-php": "~2.0",
"2amigos/yii2-date-time-picker-widget": "*",
"yiisoft/yii2-jui": "*",
"cebe/yii2-gravatar": "*",
"kartik-v/yii2-widget-fileinput": "*",
"kartik-v/yii2-widget-switchinput": "*",
"yiisoft/yii2-imagine": "*",
"2amigos/yii2-resource-manager-component": "0.1.*",
"yiisoft/yii2-authclient": "~2.0.0"
},
然后,我们需要更新作曲家:
sudo composer update
Password:
Loading composer repositories with package information
Updating dependencies (including require-dev)
- Updating 2amigos/yii2-date-time-picker-widget (0.1.0 => 0.1.1)
Checking out 572e2448ba1cd207b339dd5d117e3d1d23f0bbc3
- Installing yiisoft/yii2-authclient (2.0.2)
Loading from cache
Writing lock file
Generating autoload files
配置AuthClient支持
并且,我们需要将AuthClient配置设置添加到\frontend\config\main.php
配置文件中。
为您希望支持的所有第三方服务添加数组元素(有关详细信息,请参见AuthClient指南 ):
'components' => [
'authClientCollection' => [
'class' => 'yii\authclient\Collection',
'clients' => [
'facebook' => [
'class' => 'yii\authclient\clients\Facebook',
'clientId' => $config['oauth_fb_id'],
'clientSecret' => $config['oauth_fb_secret'],
],
'google' => [
'class' => 'yii\authclient\clients\GoogleOAuth',
'clientId' => $config['oauth_google_client_id'],
'clientSecret' => $config['oauth_google_client_secret'],
],
'linkedin' => [
'class' => 'yii\authclient\clients\LinkedIn',
'clientId' => $config['linkedin_client_id'],
'clientSecret' => $config['linkedin_client_secret'],
],
'twitter' => [
'class' => 'yii\authclient\clients\Twitter',
'consumerKey' => $config['oauth_twitter_key'],
'consumerSecret' => $config['oauth_twitter_secret'],
],
],
],
为了获得所有这些密钥和机密的代码,您需要在每个社交网络中注册您的应用程序。 这通常很耗时。
注册开发人员应用程序
在我逐步引导您完成一些网络以及其他一些较深层的配置方面的学习时,请继续进行。
向Twitter注册
在Twitter Application Dashboard上创建一个新的Twitter应用程序 :
![建立您的启动OAuth-创建应用](https://i-blog.csdnimg.cn/blog_migrate/3fca583c6cff1cce7fe50d5ba9f61910.png)
单击“ 创建新应用” —我发现回调URL是不必要的,但现在我使用了占位符http://mydomain.com/user/security/auth 。
![建立您的启动OAuth-Twitter Dev App详细信息](https://i-blog.csdnimg.cn/blog_migrate/b60ac82c352349d184ac9c280bc1b56c.png)
这是我们的应用程序的新页面:
![建立您的启动OAuth-Twitter应用页面](https://i-blog.csdnimg.cn/blog_migrate/e836773635957a6b542c2e98fde5c834.png)
这是“ 设置”页面:
![建立您的启动OAuth-Twitter Dev App设置](https://i-blog.csdnimg.cn/blog_migrate/b5684782d303de4bbceaec607c6c8ea6.png)
这是“ 密钥和访问令牌”页面。 在这里,我们需要复制使用者密钥(API密钥)和使用者密钥(API密钥) :
![建立您的启动OAuth-Twitter Dev应用程序密钥和令牌](https://cms-assets.tutsplus.com/uploads/users/317/posts/23512/image/mp-app-keys.jpg)
这些密钥位于我们的mp.ini文件中,该文件被读入上面的$config
变量中,以为Twitter配置AuthClient。
注册我们的Facebook应用程序
接下来,让我们访问Facebook开发者控制台并添加一个新应用 :
![建立您的启动OAuth-Facebook开发控制台](https://cms-assets.tutsplus.com/uploads/users/317/posts/23512/image/fb-app-dash.jpg)
我们现在选择创建一个WWW网站应用程序:
![建立您的启动OAuth-Facebook开发控制台添加应用](https://i-blog.csdnimg.cn/blog_migrate/e720f96c7bc651ea233f4361baae50a5.png)
提供我们的应用程序的名称:
![建立您的启动OAuth-Facebook开发控制台生成应用程序ID](https://i-blog.csdnimg.cn/blog_migrate/34e9e0c78296e4eb95786eacc4919538.png)
并收集我们的新App ID :
![构建您的启动OAuth-Facebook开发控制台创建应用对话框](https://i-blog.csdnimg.cn/blog_migrate/a6c87cfe366a3a3f55caaf7705c9437f.png)
他们要求提供所有常规信息,例如URL:
![建立您的启动OAuth-Facebook开发控制台应用程序网页URL](https://i-blog.csdnimg.cn/blog_migrate/0ac56afd0219e5750dbdb331ca599499.png)
然后,您可以在列表中找到我们的会议计划程序应用程序:
![建立您的启动OAuth-列出应用的Facebook开发控制台](https://i-blog.csdnimg.cn/blog_migrate/42ef5cb561a8b2124f3a599ce21ef2ab.png)
这是您的应用程序的Facebook仪表板:
![建立您的启动OAuth-Facebook开发控制台完成的应用页面](https://i-blog.csdnimg.cn/blog_migrate/a44326bbd26708c0a48620670271ee6a.png)
向Google注册
Google API比Twitter和Facebook复杂一点,因此UX很难遵循。 但基本上,一旦创建了应用程序,就需要OAuth 2.0密钥,您可以通过在凭据屏幕上打开应用程序区域来获得该密钥:
![建立您的启动OAuth-Google Dev App凭据](https://i-blog.csdnimg.cn/blog_migrate/feacb2f6d8dd124969ce3be5e0c4e845.png)
这将带您到这里:
![建立您的启动OAuth-Google Dev应用程序密钥和重定向URL](https://i-blog.csdnimg.cn/blog_migrate/38c38a9f20f31fe79b0e68a74c999cf5.png)
出于安全原因,Google(和LinkedIn)要求完整列出在OAuth序列中可能使用的URL路径和参数。 在开发过程中,这可能需要进行大量调整,甚至需要从本地主机进行测试。
输入它们后,您会在下面看到它们:
![建立启动OAuth-所有这些网址的Google Dev App](https://cms-assets.tutsplus.com/uploads/users/317/posts/23512/image/google%20credential%20urls.jpg)
Google可以很好地帮助您配置同意屏幕,当用户尝试注册或将其Google帐户链接到Meeting Planner时,该屏幕将显示:
![建立您的启动OAuth-Google Dev应用程序凭据预览](https://i-blog.csdnimg.cn/blog_migrate/542c91889487d940f1ea8edaba537b08.png)
在领英注册
与Google相比,LinkedIn相当简单。 您需要应用程序的基本详细信息:
![建立启动OAuth-LinkedIn Dev App Settings](https://cms-assets.tutsplus.com/uploads/users/317/posts/23512/image/linked%20in%20config.jpg)
与Google一样,它们要求您在开发和生产中使用的所有URL。 您也可以在此页面上获取密钥:
![建立您的启动OAuth-再次使用LinkedIn开发键和重定向URL](https://i-blog.csdnimg.cn/blog_migrate/f257a6e64c4a9ade1134c3ab58bfed24.png)
在我们的配置文件中放置密钥
在“ 从GitHub保护密钥”中 ,我详细描述了如何使用配置文件存储除GitHub存储库之外的所有密钥。 然后,将此文件包含在我的Yii配置文件的开头。 这样可以避免我不小心签入我的存储库密钥并破坏我的帐户。
我们将Twitter和Facebook应用程序的密钥和秘密都放入存储库外部的/var/secure/mp.ini
:
oauth_fb_id="154xxxxxxxxxxxxxx33"
oauth_fb_secret="bcxxxxxxxxxxxxxxdda"
oauth_twitter_key ="JCpxxxxxxxxxxxxxxnsF"
oauth_twitter_secret="f3xxxxxxxxxxxxxxxxxxxxxxxxxxxxu37"
oauth_twitter_token="153xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxfBj"
oauth_twitter_token_secret="Synxxxxxxxxxxxxxxxxxxxxxxxxxxxx4X"
oauth_google_client_id = "1xxxxxxxxxxxxxxxxxxxxxxq.apps.googleusercontent.com"
oauth_google_client_secret = "cfkxxxxxxxxxxxxxxox"
linkedin_client_id = "7xxxxxxxxxxxxxxq"
linkedin_client_secret ="IxxxxxxxxxxxxxxI"
这里再次是\frontend\config\main.php
的代码,其中包括以下设置并设置各个配置变量:
<?php
$config = parse_ini_file('/var/secure/mp.ini', true);
$params = array_merge(
require(__DIR__ . '/../../common/config/params.php'),
require(__DIR__ . '/../../common/config/params-local.php'),
require(__DIR__ . '/params.php'),
require(__DIR__ . '/params-local.php')
);
return [
'id' => 'app-frontend',
'basePath' => dirname(__DIR__),
'bootstrap' => ['log'],
'controllerNamespace' => 'frontend\controllers',
'components' => [
'authClientCollection' => [
'class' => 'yii\authclient\Collection',
'clients' => [
'google' => [
'class' => 'yii\authclient\clients\GoogleOpenId'
],
'facebook' => [
'class' => 'yii\authclient\clients\Facebook',
'clientId' => $config['oauth_fb_id'],
'clientSecret' => $config['oauth_fb_secret'],
],
'twitter' => [
'class' => 'yii\authclient\clients\Twitter',
'consumerKey' => $config['oauth_twitter_key'],
'consumerSecret' => $config['oauth_twitter_secret'],
],
],
],
'urlManager' => [
更新架构以存储会话密钥
现在我们已经准备好编写代码来集成社交注册和登录,我们需要数据库创建一个Auth
表,该表将在Meeting Planner中存储社交服务,该人的ID和该人的user_id
:
./yii migrate/create create_auth_table
Yii Migration Tool (based on Yii v2.0.2)
Create new migration '/Users/Jeff/Sites/mp/console/migrations/m150227_235635_create_auth_table.php'? (yes|no) [no]:yes
New migration created successfully.
迁移如下所示:
<?php
use yii\db\Schema;
use yii\db\Migration;
class m150227_235635_create_auth_table extends Migration
{
public function up()
{
$tableOptions = null;
if ($this->db->driverName === 'mysql') {
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
}
$this->createTable('{{%auth}}', [
'id' => Schema::TYPE_PK,
'user_id' => Schema::TYPE_BIGINT.' NOT NULL',
'source' => Schema::TYPE_STRING.' NOT NULL',
'source_id' => Schema::TYPE_STRING.' NOT NULL',
], $tableOptions);
$this->addForeignKey('fk-auth-user_id-user-id', '{{%auth}}', 'user_id', '{{%user}}', 'id', 'CASCADE', 'CASCADE');
}
public function down()
{
$this->dropForeignKey('fk-auth-user_id-user-id', '{{%auth}}');
$this->dropTable('{{%auth}}');
}
}
运行结果如下:
./yii migrate/up
Yii Migration Tool (based on Yii v2.0.2)
Total 1 new migration to be applied:
m150227_235635_create_auth_table
Apply the above migration? (yes|no) [no]:yes
*** applying m150227_235635_create_auth_table
> create table {{%auth}} ... done (time: 0.016s)
> add foreign key fk-auth-user_id-user-id: {{%auth}} (user_id) references {{%user}} (id) ... done (time: 0.012s)
*** applied m150227_235635_create_auth_table (time: 0.033s)
Migrated up successfully.
我再次使用Yii的代码生成器Gii创建Auth模型:
![建立您的启动OAuth-Auth模型的Yiis Gii模型生成器](https://cms-assets.tutsplus.com/uploads/users/317/posts/23512/image/auth-model-gii.jpg)
最终,Auth表将包含以下内容:
![构建您的启动OAuth-Auth表的数据库视图](https://i-blog.csdnimg.cn/blog_migrate/09420c7cf3cfb2425214fbc18329ad9a.png)
将AuthChoice小部件添加到会议计划器
Yii2的AuthChoice小部件在为您配置的每个服务实现登录按钮方面做得非常出色。 它按照设置服务和键的顺序进行操作(因此您可以更改它)。
将小部件添加到位于login.php和signup.php的表单中非常简单:
<div class="row">
<div class="col-lg-5">
<p>Or, login with one of the following services:</p>
<?= yii\authclient\widgets\AuthChoice::widget([
'baseAuthUrl' => ['site/auth','mode'=>'login'],
'popupMode' => false,
]) ?>
</div> <!-- end col-lg-5 -->
</div> <!-- end row -->
现在是我们的注册页面:
![建立您的启动OAuth-带有社交网络的AuthChoice窗口小部件按钮的新登录屏幕](https://cms-assets.tutsplus.com/uploads/users/317/posts/23512/image/mp-login.jpg)
对于已登录的现有用户,我为他们创建了一种简单的方法来链接他们的帐户。 称为链接社交帐户 在个人资料设置页面上:
![建立您的启动OAuth-新链接社交帐户](https://i-blog.csdnimg.cn/blog_migrate/ba2f050e8b19bf88bb25396d0f2f6ffa.png)
如果您单击LinkedIn , 这是他们的OAuth屏幕,将要求您授予会议策划者权限:
![建立您的启动OAuth-LinkedIn权限页面](https://i-blog.csdnimg.cn/blog_migrate/261c5c13cc9e3bf6c850b6cc414b331d.png)
这是Google的屏幕:
![建立启动OAuth-Google权限页面](https://i-blog.csdnimg.cn/blog_migrate/92c04b92479f6781a0f5c9525660e4dc.png)
但是,当用户允许我们共享他们的社交帐户详细信息时,真正发生了什么? 让我们看一下我编写的用于处理用户操作的代码。
处理OAuth权限
\frontend\controllers\SiteController.php
处理对函数onAuthSuccess
的传入auth
操作:
/**
* @inheritdoc
*/
public function actions()
{
return [
'error' => [
'class' => 'yii\web\ErrorAction',
],
'captcha' => [
'class' => 'yii\captcha\CaptchaAction',
'fixedVerifyCode' => YII_ENV_TEST ? 'testme' : null,
],
'auth' => [
'class' => 'yii\authclient\AuthAction',
'successCallback' => [$this, 'onAuthSuccess'],
],
];
}
除Twitter之外,大多数优质的OAuth客户端都以相似的属性数组提供相似的信息。 Twitter在共享电子邮件地址的游戏中起步较晚,对于我的MVP来说,现在不值得进行额外的配置工作。 Google和Facebook更为流行。
首先,我正在收集服务详细信息并收集尽可能多的个人数据:电子邮件,名字和姓氏,全名,尤其是该用户在该社交网络上的外部ID:
public function onAuthSuccess($client)
{
$mode = Yii::$app->getRequest()->getQueryParam('mode');
$attributes = $client->getUserAttributes();
$serviceId = $attributes['id'];
$serviceProvider = $client->getId();
$serviceTitle = $client->getTitle();
$firstname ='';
$lastname='';
$fullname ='';
switch ($serviceProvider) {
case 'facebook':
$username = $email = $attributes['email'];
$fullname = $attributes['name'];
break;
case 'google':
$email = $attributes['emails'][0]['value'];
if (isset($attributes['displayName'])) {
$fullname = $username = $attributes['displayName'];
}
if (isset($attributes['name']['familyName']) and isset($attributes['name']['givenName'])) {
$lastname = $attributes['name']['familyName'];
$firstname = $attributes['name']['givenName'];
}
break;
case 'linkedin':
$username = $email = $attributes['email-address'];
$lastname = $attributes['first-name'];
$firstname = $attributes['last-name'];
$fullname = $firstname.' '.$lastname;
break;
case 'twitter':
$username = $attributes['screen_name'];
$fullname = $attributes['name'];
// to do - fix social helpers
$email = $serviceId.'@twitter.com';
break;
}
// to do - split names into first and last with parser
$auth = Auth::find()->where([
'source' => (string)$serviceProvider,
'source_id' => (string)$serviceId,
])->one();
在上述代码的最后几行中,我们在Auth
表中搜索该人的外部ID。 如果不存在,则它们是Meeting Planner的新功能。 如果它们存在,那么我们会认出它们。
同样,我们需要检查其电子邮件地址是否已经存在,因为使用该电子邮件地址的人可能先前已在Meeting Planner中注册。
当MeetingPlanner.io上没有当前经过身份验证的用户时,下面的代码将查看传入的用户数据。
如果外部ID已经在我们的Auth表中,我们将其登录。(对于他们而言)很简单!
如果我们无法识别ID,但是我们已经注册了电子邮件地址,请他们通过用户名和密码登录,然后链接他们的帐户。
if (Yii::$app->user->isGuest) {
if ($auth) {
// if the user_id associated with this oauth login is registered, try to log them in
$user_id = $auth->user_id;
$person = new \common\models\User;
$identity = $person->findIdentity($user_id);
Yii::$app->user->login($identity);
} else {
// it's a new oauth id
// first check if we know the email address
if (isset($email) && User::find()->where(['email' => $email])->exists()) {
// the email is already registered, ask person to link accounts after logging in
Yii::$app->getSession()->setFlash('error', [
Yii::t('frontend', "The email in this {client} account is already registered. Please login using your username and password first, then link to this account in your profile settings.", ['client' => $serviceTitle]),
]);
$this->redirect(['login']);
} else {
if ($mode == 'login') {
// they were trying to login with an unconnected account - ask them to login normally and link after
Yii::$app->getSession()->setFlash('error', [
Yii::t('frontend', "We don't recognize the user with this email from {client}. If you wish to sign up, try again below. If you wish to link {client} to your Meeting Planner account, login first with your username and password. Then visit your profile settings.", ['client' => $serviceTitle]),
]);
$this->redirect(['signup']);
}
![建立您的启动OAuth-先前我们收到您的电子邮件的错误消息](https://i-blog.csdnimg.cn/blog_migrate/adf09d606eab486da12bbfdc48e72a43.png)
接下来,如果他们单击社交帐户按钮时开始在登录页面上,但是我们无法识别外部ID或电子邮件地址,则会将其重定向到注册页面,并要求他们从注册页面重试。
如果他们从注册页面链接 ,我们确保新用户不会冒重复的用户名(先前存在的会议计划者用户)的风险。 在这种情况下,我们现在仅使用随机字符串扩展用户名。 然后,我们使用密码(实际上并不需要)将他们注册为Meeting Planner的新用户。
else if ($mode == 'signup') {
// sign up a new account using oauth
// look for username that exists already and differentiate it
if (isset($username) && User::find()->where(['username' => $username])->exists()) {
$username.=Yii::$app->security->generateRandomString(6);
}
$password = Yii::$app->security->generateRandomString(12);
$user = new User([
'username' => $username, // $attributes['login'],
'email' => $email,
'password' => $password,
'status' => User::STATUS_ACTIVE,
]);
$user->generateAuthKey();
$user->generatePasswordResetToken();
$transaction = $user->getDb()->beginTransaction();
if ($user->save()) {
$auth = new Auth([
'user_id' => $user->id,
'source' => $serviceProvider, // $client->getId(),
'source_id' => $serviceId, // (string)$attributes['id'],
]);
if ($auth->save()) {
$transaction->commit();
Yii::$app->user->login($user);
} else {
print_r($auth->getErrors());
}
} else {
print_r($user->getErrors());
}
} // end signup
}
}
在上述最后步骤中,我们将其外部社交帐户详细信息添加到Auth
表以供将来识别。
链接现有的会议计划者帐户
如果它们来自用户个人资料页面(而不是我们的登录或注册页面)上的“链接社交帐户”标签,那么我们只需要将其外部帐户详细信息添加到“身份Auth
,并将其登录名移至User::STATUS_ACTIVE
。 (请记住,从会议计划者邀请链接到达但从未注册的User::STATUS_PASSIVE
具有User::STATUS_PASSIVE
模式。)
} else {
// user already logged in, link the accounts
if (!$auth) { // add auth provider
$auth = new Auth([
'user_id' => Yii::$app->user->id,
'source' => $serviceProvider,
'source_id' => $serviceId,
]);
$auth->validate();
$auth->save();
$u = User::findOne(Yii::$app->user->id);
$u->status = User::STATUS_ACTIVE;
$u->update();
Yii::$app->session->setFlash('success', Yii::t('frontend', 'Your {serviceProvider} account has been connected to your Meeting Planner account. In the future you can log in with a single click of its logo.',
array('serviceProvider'=>$serviceTitle)));
}
}
看起来是这样的(将来,我将从OAuth信息中填写命名信息-尚未完成):
![建立您的启动OAuth-成功的帐户关联](https://i-blog.csdnimg.cn/blog_migrate/a702c35e9643db68083be76737f999d0.png)
收盘时
我必须承认,与主要服务(例如Google,Facebook和LinkedIn)建立OAuth连接的影响非常明显。 它使注册和定期使用Meeting Planner变得如此容易,并加快了以后的身份验证。 确实是不可思议的。
在过去的几个月中,Meeting Planner确实聚会了。 请立即尝试社交登录和注册 ! 在我们的“ 用PHP构建您的启动”系列中观看即将推出的教程- 随着产品迈向MVP,将出现许多有趣的功能。
我还将根据SEC新的众筹规则的实施情况,开始对WeFunder进行试验。 请考虑关注我们的个人资料 。 在我们的系列文章中,我可能会写得更多。
请随时在下面添加您的问题和评论; 我通常会参与讨论。 您也可以通过Twitter @reifman与我联系 。 我欢迎功能和主题要求。
如果您想知道下一个Yii2教程何时到达, 请在Twitter上关注我@reifman或查看我的讲师页面 。 发布后,我的讲师页面将包含本系列中的所有文章。