Laravel 5.2或5.3:如何正确实施检查以查看会话是否已登录

时间:2016-09-22 16:16:07

标签: laravel laravel-5 laravel-5.2 laravel-routing laravel-middleware

我正在使用Laravel 5.2.45进行应用程序,该应用程序与离子前端交互,并且使用Postman对服务器端进行测试。关于如何正确实施检查以查看用户的会话是否已经激活并登录,我有点困惑。下面是概述的场景:

删除本地存储空间 假设用户向系统注册并登录。在离子浏览器和邮递员中测试时,将返回所有适当的信息。此外,会话也在数据库中生成而不是文件(按照预期,不,我们不想将文件用于会话)。 现在说用户检查浏览器并删除其本地存储数据并删除所有缓存的信息和cookie。删除所有客户端存储的数据后,用户尝试使用相同的凭据登录。这是问题发生的地方。

问题:
当用户点击/ login路由时,这将自动在数据库中生成另一个新会话,而无需先检查DB中是否已存在另一个活动会话。每次ping / login路由时都会发生这种情况。基本上,如果有人登录,然后删除他们的本地存储并再次登录(并且执行1000次以上),他们最终可能会在会话表中使用错误的会话充满数据库,所有这些都附加到用户的帐户。

在会话表中有人应该有多个会话的唯一时间是他们从2个不同的设备登录。但在这种情况下,当时只有1个会话处于活动状态,但在数据库中仍然会为该用户记录2个会话。

问题: 怎么样或在哪里 我是否会为系统实施干净,正确的方法来检查中间件数据库中是否存在实时/活动会话 和 根据数据库中的活动会话,对用户尝试重新登录的凭据进行身份验证/附加到该活动会话?

此问题基于完全安装Laravel(5.2.45)或更高版本后。没有向服务器端添加其他代码且未使用任何刀片模板的情况。通过离子平台进行重定向,并且在Postman中进行测试时,只能预期数据返回。

我去的地方:

下面的链接准确但不具有描述性,如何实现它并进一步采取它因为我在进行Auth :: check()之后需要进行其他过程 how to check if user is logged in by his session in route and then call controller method in laravel?

非常感谢您提供的任何帮助。 谢谢!

1 个答案:

答案 0 :(得分:2)

我做了以下事情:

1)在routes.php中我定义了中间件来路由组:

Route::group(['prefix' => 'auth'], function() {
  Route::get('/', ['as' => 'auth', 'uses' => 'AuthController@index']);
  Route::post('/', ['as' => 'auth.attempt', 'uses' => 'AuthController@attempt']);
  Route::delete('/', ['uses' => 'AuthController@destroy']);
  Route::any('destroy', ['as' => 'auth.destroy', 'uses' => 'AuthController@destroy']);
});

Route::group(['prefix' => 'billing', 'namespace' => 'Billing', 'middleware' => ['App\Http\Middleware\HasAccessToBilling']], function()
{
    Route::any('/', ['as' => 'billing', 'uses' => 'DashboardController@index']);
    Route::get('profile', ['as' => 'billing.profile', 'uses' => 'ProfileController@index']);
});

2)在app/Http/Middleware/HasAccessToBilling.php我定义:

<?php namespace App\Http\Middleware;

use App\Library\Auth;
use Closure;
use Illuminate\Http\Request;

class HasAccessToBilling
{

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        if (Auth::hasAccessTo('billing', $request)) {
            return $next($request);
        }
        return redirect()->route('auth');
    }
}

3)在app/Library/Auth.php :(自定义Auth lib)

<?php namespace App\Library;

use \App\Models\User;  // I keep Models in app/Models folder and define namespace App\Models;
use Illuminate\Http\Request;
use Crypt;

class Auth
{
    const REALMS = 'api,billing';

    public static function attempt($realm, Request $request)
    {
        $username = $request->input('username');
        $password = $request->input('password');
        $remember = $request->input('remember', false);

        $User = (filter_var($username, FILTER_VALIDATE_EMAIL)) ?
            User::whereEmail($username)->first()
            : User::whereUsername($username)->first();
        if (!$User) {
            return false;
        }

        if (!$User->checkPassword($password)) {
            return false;
        }

        $realms = (is_array($realm) AND !empty($realm)) ? $realm : [$realm];
        $auth = [
            'timestamp' => time(),
            'user_id' => $User->id,
            'access_to' => [],
            'roles' => [],
            'permissions' => []
        ];
        $auth = $request->session()->get('auth', $auth);
        foreach ($realms AS $realm) {
            if (!in_array($realm, $auth['access_to'])) {
                $auth['access_to'][] = $realm;
            }
        }

        if($remember) {
            $rememberToken = Crypt::encrypt(json_encode($auth));
            $auth['remember-token'] = $rememberToken;
        }
        $request->session()->put('auth', $auth);

        return $auth;
    }

    public static function destroy(Request $request, $realm = null)
    {
        if (is_null($realm)) {
            $request->session()->forget('auth');
            return true;
        }

        $auth = $request->session()->get('auth');
        if (isset($auth['access_to'])) {
            $realms = (is_array($realm) AND !empty($realm)) ? $realm : [$realm];
            foreach ($realms AS $realm) {
                $key = array_search($realm, $auth['access_to']);
                unset($auth['access_to'][$key]);
            }
            $auth['access_to'] = array_values($auth['access_to']);
            if(sizeof($auth['access_to']) > 0) {
                $request->session()->put('auth', $auth);
            }
            else {
                $request->session()->forget('auth');
            }
            return true;
        }
        return false;
    }

    public static function recoverSession(Request $request)
    {
        $rememberToken = $request->cookie('remember-token', null);
        if(is_null($rememberToken)) {
            return null;
        }

        try{
            $rememberToken = Crypt::decrypt($rememberToken);
            $auth = json_decode($rememberToken, true);
            $request->session()->set('auth', $auth);
        }
        catch(\Exception $ex) {}

        return $request->session()->get('auth');
    }

    public static function hasAccessTo($realm, Request $request)
    {
        $auth = $request->session()->get('auth', null);
        if (is_null($auth)) {
            $auth = self::recoverSession($request);
        }

        return (isset($auth['access_to']))?
                in_array($realm, $auth['access_to'])
                : false;
    }
}

4)在app/Models/User.php中:(不要忘记创建Models文件夹)

<?php namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Hash;
use Closure;

class User extends Model
{
    const USERNAME_MAXLEN = 2;
    const PASSWORD_MAXLEN = 5;
    protected $table = 'users';
    protected $fillable = ['username', 'email', 'password', 'active', 'deleted'];

    public function checkPassword($password)
    {
        return Hash::check($password, $this->password);
    }

    public function updateAndCall($attributes = [], Closure $closure) {
        if(isset($attributes['password'])) {
            $attributes['password'] = Hash::make($attributes['password']);
        }
        $this->update($attributes);
        return $closure($this);
    }

    public static function createAndCall($attributes = [], Closure $closure) {
        if(isset($attributes['password'])) {
            $attributes['password'] = Hash::make($attributes['password']);
        }
        $Record = self::create($attributes);
        return $closure($Record);
    }
}

5)在app\Http\Controllers\AuthController.php

<?php namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Library\Auth;

class AuthController extends Controller
{
    public function index()
    {

        return view('auth.index');
    }

    public function attempt(Request $request)
    {
        $realms = $request->get('realm', Auth::REALMS);
        if (!is_null($realms)) {
            $realms = explode(',', $realms);
        }

        $auth = Auth::attempt($realms, $request);
        if ($auth === false) {
            return $this->forbidden('Username and/or Password invalid!');
        }

        foreach ($realms AS $realm) {
            if (!Auth::hasAccessTo($realm, $request)) {
                return $this->forbidden('Access denied');
            }
        }

        if (isset($auth['remember-token'])) {
            $this->setCookie('remember-token', $auth['remember-token'], 525600); // 1 year
        }

        return $this->ok(null, ['redirectTo' => $realms[0]]);
    }

    public function destroy(Request $request)
    {
        $realms = $request->get('realm', Auth::REALMS);
        if (is_array($realms) AND !empty($realms)) {
            $realms = explode(',', $realms);
        }
        Auth::destroy($request, $realms);
        $this->deleteCookie('remember-token');

        return redirect()->route('auth');
    }
}



随意使用它你想要的(;