美文网首页
Laravel框架 之 RememberMe

Laravel框架 之 RememberMe

作者: 诺之林 | 来源:发表于2018-04-18 11:55 被阅读756次

    本文的示例代码参考rememberme

    目录

    开始

    composer create-project laravel/laravel rememberme --prefer-dist "5.5.*"
    
    # 创建数据库表
    php artisan migrate
    
    php artisan make:seed UsersTableSeeder
    
    vim database/seeds/UsersTableSeeder.php
    
    <?php
    
    use Illuminate\Database\Seeder;
    use App\User;
    
    class UsersTableSeeder extends Seeder
    {
        public function run()
        {
            // 生成数据集合
            $users = factory(User::class)
                ->times(2)
                ->make();
    
            // 让隐藏字段可见,并将数据集合转换为数组
            $user_array = $users->makeVisible(['password', 'remember_token'])->toArray();
    
            // 插入到数据库中
            User::insert($user_array);
    
            // 单独处理第一个用户的数据
            $user = User::find(1);
            $user->name = 'test';
            $user->email = 'test@gmail.com';
            $user->save();
        }
    }
    
    vim database/seeds/DatabaseSeeder.php
    
    <?php
    
    use Illuminate\Database\Seeder;
    
    class DatabaseSeeder extends Seeder
    {
        public function run()
        {
             $this->call(UsersTableSeeder::class);
        }
    }
    
    # 填充表假数据
    php artisan db:seed
    

    生产假数据的工厂方法在database/factories/UserFactory.php中

    $factory->define(App\User::class, function (Faker $faker) {
        return [
            'name' => $faker->name,
            'email' => $faker->unique()->safeEmail,
            'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret (假数据的密码)
            'remember_token' => str_random(10),
        ];
    });
    

    路由

    php artisan make:controller SessionsController
    
    vim routes/web.php
    
    <?php
    
    Route::get('/', function () {
        return view('welcome');
    })->name('index');
    
    Route::get('login', 'SessionsController@create')->name('login');
    Route::post('login', 'SessionsController@store')->name('login');
    Route::delete('logout', 'SessionsController@destroy')->name('logout');
    
    • 测试
    php artisan route:list
    
    +--------+----------+----------+--------+-------------------------------------------------+--------------+
    | Domain | Method   | URI      | Name   | Action                                          | Middleware   |
    +--------+----------+----------+--------+-------------------------------------------------+--------------+
    |        | GET|HEAD | /        | index  | Closure                                         | web          |
    |        | GET|HEAD | api/user |        | Closure                                         | api,auth:api |
    |        | GET|HEAD | login    | login  | App\Http\Controllers\SessionsController@create  | web          |
    |        | POST     | login    | login  | App\Http\Controllers\SessionsController@store   | web          |
    |        | DELETE   | logout   | logout | App\Http\Controllers\SessionsController@destroy | web          |
    +--------+----------+----------+--------+-------------------------------------------------+--------------+
    

    控制器

    vim app/Http/Controllers/SessionsController.php
    
    <?php
    
    namespace App\Http\Controllers;
    
    use Illuminate\Http\Request;
    use Auth;
    
    class SessionsController extends Controller
    {
        public function create()
        {
            return view('sessions.create');
        }
    
        public function store(Request $request)
        {
            $credentials = $this->validate($request, [
                'email' => 'required|email|max:255',
                'password' => 'required'
            ]);
    
            if (Auth::attempt($credentials)) {
                return redirect()->route('index');
            } else {
                return redirect()->back();
            }
        }
    
        public function destroy()
        {
            Auth::logout();
            return redirect()->route('index');
        }
    }
    

    视图

    登录

    mkdir resources/views/sessions
    
    vim resources/views/sessions/create.blade.php
    
    <!doctype html>
    <html lang="zh-CN">
    <head>
        <title>Laravel</title>
    </head>
    <body>
        <form method="POST" action="{{ route('login') }}">
            {{ csrf_field() }}
    
            <div class="form-group">
                <label for="email">邮箱:</label>
                <input type="text" name="email" class="form-control" value="{{ old('email') }}">
            </div>
    
            <div class="form-group">
                <label for="password">密码:</label>
                <input type="password" name="password" class="form-control" value="{{ old('password') }}">
            </div>
    
            <button type="submit" class="btn btn-primary">登录</button>
        </form>
    </body>
    </html>
    

    首页

    vim resources/views/welcome.blade.php
    
    <!doctype html>
    <html lang="zh-CN">
        <head>
            <title>Laravel</title>
        </head>
        <body>
            @if (Auth::check())
                <a id="logout" href="#">
                    <form action="{{ route('logout') }}" method="POST">
                        {{ csrf_field() }}
                        {{ method_field('DELETE') }}
                        <button type="submit" name="button">退出</button>
                    </form>
                </a>
            @else
                <a href="{{ route('login') }}">登录</a>
            @endif
        </body>
    </html>
    

    不记住我

    查看当前cookie:
    
    laravel_session Expires/Max-Age = +2小时
    
    查看当前cookie:
    
    laravel_session Expires/Max-Age = +2小时
    

    cookie有效期为2小时的配置详见: config/session.php

    'lifetime' => env('SESSION_LIFETIME', 120), // 单位: 分钟
    

    将cookie有效期修改为0 即关闭浏览器登录状态就失效

    #Linux
    sed -i "s/'expire_on_close' => false/'expire_on_close' => true/g" config/session.php
    
    # MacOS
    sed -i "" "s/'expire_on_close' => false/'expire_on_close' => true/g" config/session.php
    
    查看当前cookie:
    
    laravel_session Expires/Max-Age = 1969-12-31T23:59:59.000Z
    

    请记住我

    #Linux
    sed -i "s/credentials)/credentials, true)/g" app/Http/Controllers/SessionsController.php
    
    # MacOS
    sed -i "" "s/credentials)/credentials, true)/g" app/Http/Controllers/SessionsController.php
    
    查看当前cookie:
    
    laravel_session Expires/Max-Age = 1969-12-31T23:59:59.000Z
    
    remember_web_59ba36addc2b2f9401580f014c7f58ea4e30989d Expires/Max-Age = 2023-04-17T01:32:27.771Z
    
    cat $(find storage/framework/sessions -name "[0-9a-zA-Z]*" | tail -n1)
    # a:4:{s:6:"_token";s:40:"lW5xIbJucz7dL5GBquyqXrCM4kneybgETjhZCRvv";s:6:"_flash";a:2:{s:3:"old";a:0:{}s:3:"new";a:0:{}}s:9:"_previous";a:1:{s:3:"url";s:22:"http://rememberme.test";}s:50:"login_web_59ba36addc2b2f9401580f014c7f58ea4e30989d";i:2;}
    

    未关闭浏览器直接刷新源码流程

    // resources/views/welcome.blade.php
    Auth::check()
    
    // vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php
    class AuthManager implements FactoryContract
    {
        public function __call($method, $parameters)
        {
            return $this->guard()->{$method}(...$parameters);
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Auth/GuardHelpers.php
    trait GuardHelpers
    {
        public function check()
        {
            return ! is_null($this->user());
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php
    class SessionGuard implements StatefulGuard, SupportsBasicAuth
    {
        public function user()
        {
            // 从cookie laravel_session中获取user成功 和普通session流程相同
            $id = $this->session->get($this->getName());
            if (! is_null($id)) {
                if ($this->user = $this->provider->retrieveById($id)) {
                    $this->fireAuthenticatedEvent($this->user);
                }
            }
    
            return $this->user;
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Session/Store.php
    class Store implements Session
    {
        public function get($key, $default = null)
        {
            return Arr::get($this->attributes, $key, $default);
        }
    }
    

    关闭浏览器后再次刷新源码流程

    // resources/views/welcome.blade.php
    Auth::check()
    
    // vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php
    class AuthManager implements FactoryContract
    {
        public function __call($method, $parameters)
        {
            return $this->guard()->{$method}(...$parameters);
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Auth/GuardHelpers.php
    trait GuardHelpers
    {
        public function check()
        {
            return ! is_null($this->user());
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Auth/SessionGuard.php
    class SessionGuard implements StatefulGuard, SupportsBasicAuth
    {
        public function user()
        {
            // 尝试从cookie laravel_session中获取user 和普通session流程相同
            $id = $this->session->get($this->getName());
            if (! is_null($id)) {
                if ($this->user = $this->provider->retrieveById($id)) {
                    $this->fireAuthenticatedEvent($this->user);
                }
            }
    
            // 从cookie laravel_session中获取user失败 则从cookie remember_token中获取user
            $recaller = $this->recaller();
            if (is_null($this->user) && ! is_null($recaller)) {
                $this->user = $this->userFromRecaller($recaller);
    
                if ($this->user) {
                    $this->updateSession($this->user->getAuthIdentifier());
    
                    $this->fireLoginEvent($this->user, true);
                }
            }
    
            return $this->user;
        }
    
        protected function recaller()
        {
            if ($recaller = $this->request->cookies->get($this->getRecallerName())) {
                return new Recaller($recaller);
            }
        }
    
        protected function userFromRecaller($recaller)
        {
            // $this-> provider实例类型是:vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.php
            $this->viaRemember = ! is_null($user = $this->provider->retrieveByToken(
                $recaller->id(), $recaller->token()
            ));
    
            return $user;
        }
    }
    
    // vendor/symfony/http-foundation/ParameterBag.php
    class ParameterBag implements \IteratorAggregate, \Countable
    {
        public function get($key, $default = null)
        {
            return array_key_exists($key, $this->parameters) ? $this->parameters[$key] : $default;
        }
    }
    
    // vendor/laravel/framework/src/Illuminate/Auth/EloquentUserProvider.php
    class EloquentUserProvider implements UserProvider
    {
        public function retrieveByToken($identifier, $token)
        {
            $model = $this->createModel();
    
            $model = $model->where($model->getAuthIdentifierName(), $identifier)->first();
    
            $rememberToken = $model->getRememberToken();
    
            return $rememberToken && hash_equals($rememberToken, $token) ? $model : null;
        }
    }
    

    参考

    相关文章

      网友评论

          本文标题:Laravel框架 之 RememberMe

          本文链接:https://www.haomeiwen.com/subject/ryxpkftx.html