Php 通过电子邮件而不是短信发送代码来保护帐户安全:Laravel 5.2
当我们第一次登录我们的gmail帐户时,或者在删除缓存和cookie后,我们会在窗口中键入一个发送到手机的代码 我试图实现这一点,但通过电子邮件而不是短信。下面是我实现这一点的方法 : 并在数据库中创建一个Php 通过电子邮件而不是短信发送代码来保护帐户安全:Laravel 5.2,php,laravel,laravel-5,laravel-5.1,laravel-5.2,Php,Laravel,Laravel 5,Laravel 5.1,Laravel 5.2,当我们第一次登录我们的gmail帐户时,或者在删除缓存和cookie后,我们会在窗口中键入一个发送到手机的代码 我试图实现这一点,但通过电子邮件而不是短信。下面是我实现这一点的方法 : 并在数据库中创建一个会话表。我还可以在会话表记录中查看我的浏览器详细信息。我不确定这是不是正确的方法 Gmail提供了跟踪多个浏览器的功能。这意味着,如果我上次从Firefox登录,这次从Chrome登录,那么我将再次被要求输入代码。接下来,如果不删除缓存/cookie,我将不会被要求填写Chrome和Firef
会话表。我还可以在会话表记录中查看我的浏览器详细信息。我不确定这是不是正确的方法
Gmail提供了跟踪多个浏览器的功能。这意味着,如果我上次从Firefox登录,这次从Chrome登录,那么我将再次被要求输入代码。接下来,如果不删除缓存/cookie,我将不会被要求填写Chrome和Firefox的代码
有人能给我一些链接来解释如何在缓存/cookie保存时为多个浏览器做准备吗?这样我就可以发送电子邮件获取安全代码创建一个额外的表(除了会话1)
差不多
用户ID |用户代理| IP
当他们登录时,对照$\u服务器
数组中的当前值检查。如果它在那里,一切都很好,如果不中断登录,并向他们发送一个链接,以确认新的数据。您可能希望在原始登录上执行某种ajax来检查他们何时登录,然后一旦发生这种情况,就重定向到他们要去的地方
有道理
正如我在维修性评论中所说的,我将自己处理,不使用任何第三方API,数据很容易验证。这一部分相对来说很简单,继续登录过程并不多。您可以通过发出额外的cookie(比如browser\u cookie)来记住已经通过身份验证的浏览器来实现这一点
实施:
创建下表(浏览器管理):
其中:
- 令牌:发给用户的令牌的散列形式(使用bcrypt或类似算法)(发给用户的令牌本身是从适当大的空间中随机生成的不可用密钥)
- series_identifier:从适当大的空间中随机生成的不可用密钥
无论何时,用户登录都会检查浏览器\u cookie
案例1:用户是第一次登录
考虑到用户是第一次登录浏览器\u cookie
将不存在。因此,您将发送一封带有身份验证代码的电子邮件
验证后,为令牌
和系列\u标识符
分别生成两个随机数。将散列的令牌
和序列标识符
存储在浏览器管理
表中,供用户id
标识的用户使用
另外,将browser\u cookie
发送给具有token
和series\u标识符的用户
案例2:用户下次将重新登录
现在,当同一用户下次登录时,使用令牌
并在浏览器(u management
表中使用哈希令牌
查找条目
如果找到,请检查用户标识
和系列标识
是否匹配
案例2.1:匹配的条目:
允许用户进入系统而无需重新验证电子邮件代码
生成另一个令牌,并将cookie
中的令牌以及表中的令牌替换为新令牌。(这将降低会话劫持的风险)
案例2.2:条目不匹配:
按照电子邮件身份验证的步骤进行操作,并通知用户可能的盗窃行为(如gmail通知新的浏览器登录)
参考资料:
更新:
示例代码:
迁移:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class browser_management extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('browser_management', function (Blueprint $table) {
$table->string('token');
$table->string('user_id');
$table->string('series_identifier');
$table->timestamps();
$table->primary('token');
$table->foreign('user_id')->references('id')->on('users');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('users');
}
}
用户模型:将以下方法添加到您的用户模型中
// method to retrieve series_identifier related to token
public function series_identifier($token){
return $this->hasMany(Browser_management::class)->where('token',$token);
}
//method to retriev the tokens related to user
public function tokens (){
return $this->hasMany(Browser_management::class);
}
浏览器管理模型:创建一个模型来表示浏览器管理表
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Browser_management extends Model
{
protected $primaryKey = 'token';
protected $fillable = array('token','series_identifier');
public function User(){
return $this->hasOne('App\Models\User');
}
}
路由:添加这些路由以处理电子邮件验证请求。我们还将向其添加电子邮件验证中间件
Route::get('/auth/email_verification',`AuthController@getVerification')->middleware('email_verification');
Route::post('/auth/email_verification',`AuthController@postVerification')->middleware('email_verification');<br/>
Route::get('/auth/email_-verification'`AuthController@getVerification“)->中间件(“电子邮件验证”);
路由::post(“/auth/email_-verification”`AuthController@postVerification“)->中间件(“电子邮件验证”)
更新2:
关于gmail的流量。
我遵循以下步骤:
1) 登录gmail,然后进行两步验证
2) 注销
3) 清除缓存
4) 再次登录
当我再次登录时,在清除缓存后,它没有要求我进行两步验证
但是,如果您清除cookies,它将要求进行两步验证。
原因:
标识用户的所有用户数据(此处为令牌
)都存储在cookie中。如果清除cookies,服务器将没有识别用户的机制。
更新3:
Gmail要求两步验证:
首先,Gmail或任何其他网站都不会收到清除缓存的通知
如期
缓存只不过是硬盘上
浏览器保留下载一次的内容,以备需要
再说一遍
现在,cookies是服务器发布的用于存储用户相关信息的小文本文件。如期
cookie的主要用途是识别用户并可能准备
自定义网页或为您保存网站登录信息
因此,基本上,当您清除浏览器中的cookie时,Web服务器将不会获得任何用户数据。因此,用户将被视为客人,并将得到相应的对待。OP,如果我清楚地理解您的意思,您只需要
// method to retrieve series_identifier related to token
public function series_identifier($token){
return $this->hasMany(Browser_management::class)->where('token',$token);
}
//method to retriev the tokens related to user
public function tokens (){
return $this->hasMany(Browser_management::class);
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Browser_management extends Model
{
protected $primaryKey = 'token';
protected $fillable = array('token','series_identifier');
public function User(){
return $this->hasOne('App\Models\User');
}
}
public function getVerification(Request $request){
//Create a random string to represent the token to be sent to user via email.
//You can use any string as we are going to hash it in our DB
$token = str_random(16);
//Generate random string to represent series_identifier
$series_identifier = str_random(64);
//Issue cookie to user with the generated series_identifier
Cookie::queue('series_identifier', $series_identifier,43200,null,null,true,true);
//Store the hashed token and series_identifier ini DB
Auth::user()->tokens()->create(['token'=>Hash::make($token)]);
//Your code to send an email for authentication
//return the view with form asking for token
return view('auth.email_verification');
}
public function postVerification(Request $request){
//Retrieve the series_identifier issued to the user in above method
$series_identifier = $request->cookie('series_identifier');
//Retrieve the token associated with the series_identifier
$token = Auth::user()
->tokens()
->where('series_identifier',$series_identifier)
->first()
->value('token');
//Check if the user's token's hash matches our token entry
if(Hash::check($request->token,$token)){
// If token matched, issue the cookie with token id in it. Which we can use in future to authenticate the user
Cookie::queue('token', $token,43200,null,null,true,true);
return redirect('dashboard');
}
//If token did not match, redirect user bak to the form with error
return redirect()->back()
->with('msg','Tokens did not match');
}
Route::get('/auth/email_verification',`AuthController@getVerification')->middleware('email_verification');
Route::post('/auth/email_verification',`AuthController@postVerification')->middleware('email_verification');<br/>
Schema::create('sessions', function ($table) {
$table->string('id')->unique();
$table->integer('user_id')->nullable();
$table->string('ip_address', 45)->nullable();
$table->text('user_agent')->nullable();
$table->text('payload');
$table->integer('last_activity');
});
public function authenticate()
{
$data = Input::all();
$user = User::where('email', '=', $data['email'])->first();
if($user != null)
{
//check if user agent different from session
if($request->header('User-Agent') != session('user_agent'))
{
//do some extra login/password validation check
}
if(Auth::attempt($data))
{
//here you now may manually update the session ID on db
}
}
}