扩展Laravel认证组件功能

Wednesday, April 26, 2017

Laravel 自带的认证组件很方便,集成了常用的认证相关的功能,满足项目开发的基本需求,但一些常用的功能却没有,这篇文章将会介绍如果增加一些常见的基础功能。

在开始之前,需要先生成认证组件,在命令行中使用如下命令即可:

php artisan make:auth

验证码

验证码可以说是网站中最常见的一个功能,以前的图形验证码已经很落后,现在,很多厂商都开发了新一代的验证码,这篇文章主要来说明 极验验证码

极验验证码的最新版本是 v3.0,在之前的版本中,我一直使用的是 Germey/LaravelGeetest ,不过最新版的代码还没有更新到 v3.0,所以我参照这个扩展,结合官方的 3.0SDK 自己制作了一个 轮子 ,下面就开始扩展认证组件的验证码功能。

引入扩展包

  1. 安装包文件

    $ composer require jormin/laravel-geetest
    
  2. 注册 ServiceProvider:

    Jormin\Geetest\GeetestServiceProvider::class,
    
  3. 添加 Alias

    'Geetest' => Jormin\Geetest\Facades\Geetest::class,
    
  4. 创建配置文件、视图级资源文件:

    php artisan vendor:publish --provider='Jormin\Geetest\GeetestServiceProvider'
    
  5. .env 文件增加配置项 GEETEST_IDGEETEST_KEY

  6. 自定义配置项

修改项目代码

  1. 前端页面验证

    在页面 \resources\views\auth\login.blade.php 的登录表单中增加如下代码

    {!! Geetest::render() !!}
    
  2. 服务端页面二次验证

    修改 app\Http\Controllers\Auth\LoginController.php 文件,覆盖 Trait AuthenticatesUsersvalidateLogin 函数,完整代码如下:

        /**
         * Validate the user login request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return void
         */
        protected function validateLogin(Request $request)
        {
            $this->validate($request, [
                $this->username() => 'required',
                'password' => 'required',
                'geetest_challenge' => 'required|geetest',
            ], [
                'geetest' => config('laravel-geetest.server_fail_alert')
            ]);
        }
    

至此,极验验证码就引入到项目的登录流程中了,其他地方需要使用的话方法类似。

登录日志

项目中经常需要对用户的登录信息做些统计,用于后期的数据分析,比如账号安全鉴定,活跃时常统计等等。

最基本登录日志包含登录时间、退出时间及登录地址,登录时间和退出时间我们可以监听认证组件的一些事件来处理,登录地址可以通过反查IP来处理。

创建登录记录模型及迁移文件

  1. 我们来创建数据模型及迁移文件,在命令行中使用如下命令即可, 生成的迁移文件存储在 database\migrations 目录下。

    php artisan make:model Models/SigninLog -m
    
  2. 修改生成的迁移文件 2017_04_26_081110_create_signin_logs_table,加入基本的统计字段:

    /**
         * Run the migrations.
         *
         * @return void
         */
        public function up()
        {
            Schema::create('signin_logs', function (Blueprint $table) {
                $table->increments('id');
                $table->integer('user_id')->comment("用户ID")->unsigned();
                $table->string('ip',15)->comment("IP地址");
                $table->string('ip_area')->comment("IP地区");
                $table->timestamp('login_time')->comment("登录时间");
                $table->timestamp('logout_time')->comment("退出时间")->nullable();
    
                $table->foreign('user_id')->references('id')->on('users')
                    ->onUpdate('cascade')->onDelete('cascade');
            });
        }
    
  3. 运行迁移文件:

    php artisan migrate
    
  4. 修改模型文件,增加批量赋值属性:

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'user_id','ip','ip_area','login_time'
    ];
    

生成认证组件的监听类

  1. 配置监听类

    认证组件 提供了一些认证相关的事件,这里我们只需要监听 登录成功 退出成功 事件即可。

    app\Providers\EventServiceProvider.php 文件中配置我们要监听的事件以及相关的监听类,代码如下:

    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        // 登录监听
        'Illuminate\Auth\Events\Login' => [
            'App\Listeners\LogSuccessfulLogin',
        ],
    
        // 退出监听
        'Illuminate\Auth\Events\Logout' => [
            'App\Listeners\LogSuccessfulLogout',
        ],
    
    ];
    
  2. 生成配置的监听类

    在命令行中使用如下命令,生成的监听类存放于 app\Listeners 目录中。

    php artisan event:generate
    

记录登录时间和IP。

接下来我们先记录用户的登录时间。LogSuccessfulLogin.phphandle 函数的参数是一个 Illuminate\Auth\Events\Login 对象,包含用户对象信息,所以这里我们只需要记录用户的登录时间和IP信息即可。

  1. 使用Carbon类生成当前时间。

    $login_time = Carbon::now();
    
  2. 获取访问IP并转换地址

    获取IP:

    $ip = request()->getClientIp();
    

    反查IP可以使用 IPIP 的服务,我已经将服务封装了一个扩展包 jormin/laravel-ip ,这里我们使用这个扩展包即可。

    引入扩展包

    $ composer require jormin/laravel-ip
    

    反查IP,反查的结果是一个数组,需要拼成字符串:

    $ip_area = implode(Jormin\IP\IP:ip2addr($ip),' ');
    

    ``

    至此,用户的登录信息就记录完成了,完整代码如下:

    /**
     * Handle the event.
     *
     * @param  Login  $event
     * @return void
     */
    public function handle(Login $event)
    {
        $user = $event->user;
        $login_time = Carbon::now();
        $login_ip = request()->getClientIp();
        $login_ip_area = implode(IP::ip2addr($login_ip),' ');
    
        SigninLog::create([
            'user_id' => $user->id,
            'ip' => $login_ip,
            'ip_area' => $login_ip_area,
            'login_time' => $login_time
        ]);
    }
    

记录退出时间

退出时间和登录时间记录的方式类似,代码如下:

```php
	/**
     * Handle the event.
     *
     * @param  Logout  $event
     * @return void
     */
	public function handle(Logout $event)
	{
        $user = $event->user;
        $signinLog = SigninLog::where('user_id',$user->id)->orderBy('id','desc')->first();
        if($signinLog){
            $signinLog->logout_time = Carbon::now();
            $signinLog->save();
        }
	}
```
Laravel Laravel

书童机器人--果冻陪你聊书童造轮子之极验验证码