我最近在我工作的其中一个项目中实现了 双因子认证
. Antonio Ribeiro 是一个很好的包,使用它非常简单实现, 并且 Christopher Thomas 发布了一个很酷的策略. 让我们来看看实现这些的具体步骤.
1- 安装google2fa-laravel
composer require pragmarx/google2fa-laravel
2- 生成二维码
用户首先需要的是一种激活或禁用多重要素验证的方法。一种方法是开放一个profile/token
的GET请求,它会向没有私钥的用户渲染出激活视图,向有私钥的用户渲染出禁用视图.
<?php
namespace App\Http\Controllers\Profile;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Facades\PragmaRX\Google2FA\Google2FA;
class GoogleTokenController extends Controller
{
/**
* Create a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$user = auth()->user();
if (is_null($user->google_token)) {
return $this->showEnableTokenForm($user);
}
return view('app.profile.token.disable', ['user' => $user]);
}
/**
* Show Form with Key and QRCode for the User to enable it.
*
* @param $user
* @return mixed
*/
private function showEnableTokenForm($user)
{
$key = Google2FA::generateSecretKey(64);
$google2fa_url = Google2FA::getQRCodeGoogleUrl(
'Application Name',
$user->email,
$key
);
return view('app.profile.token.enable', [
'user' => $user,
'key' => $key,
'QRCode' => $google2fa_url
]);
}
}
在方法 showEnableTokenForm
中,Google 2fa Facede将会生成密钥及由密钥生成的二维码,用户可以扫描二维码得到秘钥.
记得使用图片标签展示二维码.
<img src="{{ $QRCode }}" alt="">
3- 存储/移除令牌
一旦用户读取二维码,它们可以输入一次性密码并提交给应用程序以验证其是否激活.
<?php
/**
* @param Request $request
* @return \Illuminate\Http\RedirectResponse
*/
public function update(Request $request)
{
if (is_null($request->get('token'))) {
return $this->disableToken();
}
$secretKey = $request->get('secret');
$token = $request->get('token');
if (Google2FA::verifyKey($secretKey, $token)) {
auth()->user()->update(['google_token' => $secretKey]);
return redirect('/profile/token')->with('success', 'Google Token successfully enabled!');
}
return redirect('/profile/token')->withErrors(['error' => 'The provided token does not match.']);
}
/**
* @return \Illuminate\Http\RedirectResponse
*/
private function disableToken()
{
auth()->user()->update(['google_token' => null]);
return redirect('/profile/token')->with('success', 'Google Token successfully removed!');
}
如果用户提交了正确的一次性密码, Google2FA 门面将会验证并将这个秘钥存储在用户表中.
4- 身份验证方法
激活令牌之后, 下一步是在登录进程中使用它。使用Laravel默认的身份验证系统, LoginController
自带了一个 authenticated
的方法用于触发身份验证之后的操作。 请求标记的完美位置。
<?php
protected function authenticated(Request $request, $user)
{
if (is_null($user->google_token)) {
return redirect()->intended($this->redirectTo);
}
Auth::logout();
$request->session()->put('user-id', $user->id);
return redirect('/token');
}
这个策略检查通过身份认证
的用户是否拥有一个令牌和一个一次性的时间密码。如果令牌是空的,常规的行为是将应用重定向到主页。如果不是这样的话,用户将被重定向到/token
路由上。
注意: 确保在users数据表中添加goole_oken列。
5- 登录时请求一次性密码
TokenController
将显示一个简单的视图,输入字段需要的一次性密码。
在此视图的表单提交中,目标是检索用户并根据他们的谷歌令牌验证他们的一次性密码。 如果匹配,则认证,否则再询问。
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Models\Main\Admin;
use Facades\PragmaRX\Google2FA\Google2FA;
use Illuminate\Http\Request;
class TokenController extends Controller
{
public function index()
{
return view('auth.token');
}
public function authenticate(Request $request)
{
$user = Admin::findOrFail($request->session()->get('user-id'));
$token = $request->get('token');
if (Google2FA::verifyKey($user->google_token, $token)) {
$request->session()->remove('user-id');
auth()->loginUsingId($user->id);
return redirect('/home');
}
return redirect('/token')->withErrors(['error' => __('Invalid Token')]);
}
}
6- 结语
该软件包使得在任何 Laravel
应用程序中实现多因素身份验证变得非常简单。 Google2FA Facade 专注于生成密钥并在必要时进行验证,完美地处理这项工作。
另一个有意思的地方是使用 Auth Facade 在请求一次性密码时强制注销并且在令牌匹配时依靠 loginUsingId
的策略。