Php 通过电子邮件而不是短信发送代码来保护帐户安全:Laravel 5.2

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帐户时,或者在删除缓存和cookie后,我们会在窗口中键入一个发送到手机的代码

我试图实现这一点,但通过电子邮件而不是短信。下面是我实现这一点的方法

并在数据库中创建一个
会话表。我还可以在会话表记录中查看我的浏览器详细信息。我不确定这是不是正确的方法

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
         }
    }
}