75142913在线留言
【Laravel实战】2、用户登陆、注册及相关事件处理_PHP技术_网络人

【Laravel实战】2、用户登陆、注册及相关事件处理

Kwok 发表于:2022-04-10 12:10:15 点击:27 评论: 0

做好了初始化工作以后,下一步我们就需要用户注册、然后登陆到网站的操作,目前我还没有接入手机号验证的功能,所以暂时先使用用户名的方式去登陆到网站。

Laravel内置了一套非常好用的用户验证助手,所以我决定在此基础上直接修改成为我需要的结构即可。

首先可以参考一下我目前的用户表设计,字段信息与索引信息等:

一、用户表结构信息

我创建的表结构相对比较多,而且更接近实际项目中使用到的用户表,可以使用下面的结构做为参考,根据自己的需求增减。

1、用户表(users),记录用户的基本信息:

CREATE TABLE `meishi_users` (
  `id` mediumint unsigned NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `group_id` smallint unsigned NOT NULL DEFAULT '0' COMMENT '用户组ID',
  `is_vip` tinyint NOT NULL DEFAULT '0' COMMENT '是否vip',
  `username` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户名',
  `password` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '密码',
  `title` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户属性描述',
  `sex` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '姓别:0未知,1男,2女',
  `mobile` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '手机号码',
  `email` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '邮箱地址',
  `signature` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '个性签名',
  `register_ip` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '注册IP',
  `last_login_ip` varchar(45) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '最后登陆IP',
  `experience` int NOT NULL DEFAULT '0' COMMENT '经验值',
  `follow_count` int unsigned NOT NULL DEFAULT '0' COMMENT '关注数',
  `fans_count` int unsigned NOT NULL DEFAULT '0' COMMENT '粉丝数',
  `liked_count` int unsigned NOT NULL DEFAULT '0' COMMENT '被点赞总数',
  `post_count` int unsigned NOT NULL DEFAULT '0' COMMENT '投稿总数',
  `comment_count` int unsigned NOT NULL DEFAULT '0' COMMENT '回复总数',
  `avatar` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '头像URL',
  `avatar_at` datetime DEFAULT NULL COMMENT '头像修改时间',
  `created_at` datetime DEFAULT NULL COMMENT '注册时间',
  `updated_at` datetime DEFAULT NULL COMMENT '最后更新时间',
  `login_at` datetime DEFAULT NULL COMMENT '最后登陆时间',
  `last_comment_at` datetime DEFAULT NULL COMMENT '最后评论时间',
  `last_post_ate` datetime DEFAULT NULL COMMENT '最后投稿时间',
  `identity` char(18) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '身份证号码',
  `realname` varchar(20) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '身份证姓名',
  `status` tinyint NOT NULL DEFAULT '0' COMMENT '用户状态:0正常,1禁用,2审核,3审核拒绝,4审核忽略',
  PRIMARY KEY (`id`),
  UNIQUE KEY `email` (`email`) USING BTREE COMMENT '邮箱不能重复',
  UNIQUE KEY `username` (`username`) USING BTREE COMMENT '用户名不可重复',
  KEY `groupid` (`group_id`) USING BTREE COMMENT '搜索用户组索引'
) ENGINE=InnoDB AUTO_INCREMENT=1000000 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='用户表';

2、用户组表(user_groups),分类用户所在组及其所可使用的权限:

CREATE TABLE `meishi_user_groups` (
  `id` smallint unsigned NOT NULL AUTO_INCREMENT COMMENT '用户组ID',
  `name` char(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户组名',
  `color` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户组颜色',
  `icon` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户组图标',
  `type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '组类型:-1系统,0自定义',
  `explower` int unsigned NOT NULL DEFAULT '0' COMMENT '升级本组所需的经验',
  `allow_post` tinyint(1) NOT NULL DEFAULT '0' COMMENT '允许投稿',
  `allow_comment` tinyint(1) NOT NULL DEFAULT '0' COMMENT '允许评论',
  `allow_upload` tinyint(1) NOT NULL DEFAULT '0' COMMENT '允许上传',
  `allow_vote` tinyint(1) NOT NULL DEFAULT '1' COMMENT '允许投票',
  `is_vip` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否VIP:0否,1是',
  `fee` int unsigned NOT NULL DEFAULT '0' COMMENT '收费金额(分)',
  `days` smallint unsigned NOT NULL DEFAULT '0' COMMENT '付费获得天数',
  `description` varchar(255) COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT '用户组说明',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=103 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=COMPACT COMMENT='用户组';

用户组需要与用户表关联关系:

ALTER TABLE `meishi_users` ADD CONSTRAINT `user_group_ship` FOREIGN KEY (`group_id`) REFERENCES `meishi_user_groups`(`id`) ON DELETE RESTRICT ON UPDATE RESTRICT;

后期可能还会有部分关联表创建,这里只做简单的演示。

3、用户组内置:

一般情况下我们需要内置一些系统用户,如:管理员、VIP、游客等,限制其使用的权限:

INSERT INTO `meishi_user_groups` (`id`, `name`, `color`, `icon`, `type`, `explower`, `allow_post`, `allow_comment`, `allow_upload`, `allow_vote`, `is_vip`, `fee`, `days`, `description`) VALUES
(1, '超级管理员组', '#000000', '', -1, 0, 1, 1, 1, 1, 0, 0, 0, '拥有系统管理的最高权限用户组'),
(2, '管理员', '#111111', '', -1, 0, 1, 1, 1, 1, 0, 0, 0, '网站普通管理员组'),
(3, '游客组', '#666666', '', -1, 0, 0, 0, 0, 1, 0, 0, 0, '网站普通访客组'),
(4, '禁止访问', '#cccccc', '', -1, 0, 0, 0, 0, 0, 0, 0, 0, '禁止访问网站内容的用户组'),
(5, '禁止发言', '#444444', '', -1, 0, 0, 0, 0, 1, 0, 0, 0, '禁言用户(不能投稿、评论等)'),
(6, '待审核', '#555555', '', -1, 0, 0, 0, 0, 1, 0, 0, 0, '正在等待审核的新注册会员(系统设置是否开启)'),
(7, '网站编辑', '#222222', '', -1, 0, 1, 1, 1, 1, 0, 0, 0, '网站编辑(员工)'),
(88, '贵宾VIP', 'red', '', -1, 0, 1, 1, 1, 1, 1, 3000, 30, '超级VIP用户'),
(99, 'VIP', 'orange', '', -1, 0, 1, 1, 1, 1, 1, 2000, 30, 'VIP用户'),
(100, '初级会员', '', '', 0, 10, 0, 1, 0, 1, 0, 0, 0, '初始等级会员'),
(101, '中级会员', '', '', 0, 200, 0, 0, 0, 1, 0, 0, 0, '中等级会员'),
(102, '高级会员', '', '', 0, 1000, 1, 1, 1, 1, 0, 0, 0, '高等级会员');
COMMIT;

 完成用户与用户组的初始化工作后,我们就可以进行下一步,开始使用Laravel操作数据库表,完成会员注册、登陆、退出等工作了。

二、用户注册并写入到表

 目前我们只是建立了用户表users,表里的数据目前还是空空如也,所以第一步我们应该尝试注册用户。

1、注册路由

待下面的控制器实现后,需要将所需要的所有控制器都导入到此包里哦~

use AppHttpControllersAuthRegisteredUserController; //用户注册
use AppHttpControllersAuthAuthenticatedSessionController; //登陆验证
use IlluminateSupportFacadesRoute; //路由

//路由经过guest中间件
Route::middleware('guest')->group(function () {
    //GET 用户注册 视图
    Route::get('register', [RegisteredUserController::class, 'create'])->name('register');
    //POST接收注册信息
    Route::post('register', [RegisteredUserController::class, 'store']);
    //GET用户登陆视图
    Route::get('login', [AuthenticatedSessionController::class, 'create'])->name('login');
    //POST接收登陆信息
    Route::post('login', [AuthenticatedSessionController::class, 'store']);
});

//路由经过 auth(验证后) 中间件
Route::middleware('auth')->group(function () {
    //POST 用户退出
    Route::post('logout', [AuthenticatedSessionController::class, 'destroy'])->name('logout');
});

为了整理路由,我们可以将上面的路由使用一个单独的文件存放:routes/auth.php 然后在routes/web.php引入此路由文件即可:

require __DIR__ . '/auth.php';//验证用户登陆、注册、邮件

 注册好路由后,理论上我们就可以通过路由访问每个请求了,目前还没有用户模型与控制器,当然会报相关的错误,所以我们接着先建立用户模型。 

2、用户模型

 快速建立用户模型可以使用下面的命令:

php artisan make:model user #报错Model already exists!

这是因为,刚好Laravel内置了用户模型,所以我不并不需要使用命令再重复新建一次,由于我们的用户表结构与内置是不一样的。我们需要打开:app/Models/User.php 修改里面的内容,以匹配我们自己的用户表。

将原来的内容简单的修改如下:

<?php

namespace AppModels;

use IlluminateContractsAuthMustVerifyEmail;
use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateFoundationAuthUser as Authenticatable;
use IlluminateNotificationsNotifiable;
use LaravelSanctumHasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    /**
     * 允许通过Model操作的字段
     * @var array<int, string>
     */
    protected $fillable = [
        'username',
        'email',
        'password',
    ];

    /**
     * 序列化时(如:Json),需要隐藏的字段
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
    ];
}

 有点小不同的地方,原来是name的地方,我数据表是username,所以在后面的调用中,所有的name都将改为username。

3、用户控制器

使用下面的命令批量新建所需要的控制器:

php artisan make:controller Auth/RegisteredUserController #用户注册相关控制器
php artisan make:controller Auth/AuthenticatedSessionController #用户登陆及验证控制器

但现在我们要修改的控制器是:app/Http/Controllers/Auth/RegisteredUserController.php,内容如下:

<?php

namespace AppHttpControllersAuth;

use AppHttpControllersController;
use IlluminateHttpRequest; //接收用户输入
use IlluminateValidationRules; //密码验证规则
use AppModelsUser; //用户模型
use IlluminateSupportFacadesHash; //密码加密
use IlluminateSupportFacadesAuth; //注册成功后自动登陆
use IlluminateAuthEventsRegistered; //事件注册
use AppProvidersRouteServiceProvider; //路由服务提供者:/home跳转
use IlluminateValidationRulesPassword; //密码验证规则
use IlluminateSupportStr; //字符串处理工具

class RegisteredUserController extends Controller
{
    //显示注册界面的View
    public function create()
    {
        return view('auth.register');
    }

    /**
     * 处理传入的注册请求。
     *
     * @param  IlluminateHttpRequest  $request
     * @return IlluminateHttpRedirectResponse
     *
     * @throws IlluminateValidationValidationException
     */
    public function store(Request $request)
    {
        //请求数据验证
        $request->validate([
            'username' => ['required', 'string', 'min:5', 'max:64'], //必填,字符串,最小5,最大64
            'email' => ['required', 'string', 'email', 'max:128', 'unique:users'], //必填,字符串,Email规则,最大128,users表不可重复
            'password' => ['required', 'confirmed', Password::min(6)], //必填,2次确认,密码规则最少6位:https://learnku.com/docs/laravel/9.x/validation/12219#785748
        ]);
        //处理待写入的数据
        $user = User::create([
            'username' => $request->username,
            'email' =>  Str::lower($request->email),
            'password' => Hash::make($request->password),
        ]);
        event(new Registered($user)); //注册事件
        Auth::login($user); //注册后自动登陆
        return redirect(RouteServiceProvider::HOME); //跳转到注册成功后的页面
    }
}

 注册成功后,默认会跳转到:RouteServiceProvider::HOME,这个定义可以跳过去查看,我本地是/home所以我要需要为其注册一个路由方便控制:

Route::get('/home', function () {
    return view('auth.home');
})->middleware(['auth'])->name('home');

逻辑代码编写完成后,我们需要写一下简单的注册页与登陆成功后的home页。

4、注册显示页视图:resources/views/auth/register.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>用户注册 - {{ config('app.name', '美食圈') }}</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body> 
    <h1>{{ __('Register') }}</h1>
<div class="p-5">

@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif
<form method="POST" action="{{ route('register') }}">
    @csrf
    <div class="mb-3">
        <label for="inputName" class="form-label">用户名 *</label>
        <input type="text" class="form-control" id="inputName" name="username" required value="{{ old('username') }}">
        <div id="usernameHelp" class="form-text">请输入您要注册用户名</div>
      </div>   
    <div class="mb-3">
      <label for="inputEmail" class="form-label">{{ __('Email') }}</label>
      <input type="email" class="form-control" name="email" id="inputEmail" aria-describedby="emailHelp" value="{{ old('email') }}">
      <div id="emailHelp" class="form-text">请输入您要注册使用的邮件地址</div>
    </div>
    <div class="mb-3">
      <label for="inputPassword1" class="form-label">{{ __('Password') }} *</label>
      <input type="password" class="form-control" name="password" id="inputPassword1" required autocomplete="new-password">
    </div>
    <div class="mb-3">
        <label for="inputPassword2" class="form-label">{{ __('Confirm Password') }} *</label>
        <input type="password" class="form-control" name="password_confirmation" required id="inputPassword2">
      </div>
    <button type="submit" class="btn btn-primary"> {{ __('Register') }}</button>
  </form>
</div>   
</body>
</html>

5、用户中心页视图:resources/views/auth/home.blade.php

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>用户中心 - {{ config('app.name', '美食圈') }}</title>
</head>
<body>
    <h1>用户中心</h1>
    欢迎您:{{ Auth::user()->username }}    
    <form method="POST" action="{{ route('logout') }}">
        @csrf
        <a href="{{ route('logout') }}"  onclick="event.preventDefault();this.closest('form').submit();">
            {{ __('Log Out') }}
        </a>
    </form>    
</body>
</html>

小提示,虽然我们使用闭包方式调用home模板,但依然可以使用Auth::user等方式,查询到当前用户的登陆信息。

三、登陆/退出操作

上面我们注册后使用了一个自动登陆的方法,现在我们需要先退出登陆,然后再测试重新登陆。

1、退出登陆

在上面的路由规则中可以看到,我们需要的登陆、退出,使用的是app/Http/Controllers/Auth/AuthenticatedSessionController.php 控制器,所以下面是此控制器的所有内容:

<?php

namespace AppHttpControllersAuth;

use AppHttpControllersController;
use AppHttpRequestsAuthLoginRequest; //验证登陆信息
use IlluminateHttpRequest; //用户输入接收
use AppProvidersRouteServiceProvider; //登陆成功后的路由

use IlluminateSupportFacadesAuth; //退出验证
class AuthenticatedSessionController extends Controller
{
    //显示登陆的View
    public function create()
    {
        return view('auth.login');
    }
    //验证登陆信息
    public function store(LoginRequest $request)
    {
        $request->authenticate(); //身份验证
        $request->session()->regenerate(); //生成新的session。
        return redirect()->intended(RouteServiceProvider::HOME); //跳转到登陆后的页面
    }
    //退出登陆
    public function destroy(Request $request)
    {
        Auth::guard('web')->logout(); //登出系统
        $request->session()->invalidate(); //刷新并重新生成sessionID
        $request->session()->regenerateToken(); //重新生成CSRF令牌值。
        return redirect('/'); //跳转到网站首页
    }
}

控制器最后一项则是处理退出操作,最后将跳转到网站的首页。

2、用户登陆

当用户登陆时,我们需要对登陆信息验证,所以上面的控制器里还需要我们手工创建一个请求验证器:

php artisan make:request Auth/LoginRequest #新建一个登陆验证器

此命令会生成:app/Http/Requests/Auth/LoginRequest.php 文件,内容如下:

<?php

namespace AppHttpRequests;

use IlluminateFoundationHttpFormRequest; //继承表单验证
use IlluminateSupportFacadesAuth; //验证器
use IlluminateSupportFacadesRateLimiter; //限流器
use IlluminateSupportStr; //字符串处理器
use IlluminateValidationValidationException; //验证异常
use IlluminateAuthEventsLockout;

class AuthLoginRequest extends FormRequest
{
    //确定用户是否被授权发出此请求。
    public function authorize()
    {
        return true;
    }

    //表单请求的验证规则。
    public function rules()
    {
        return [
            'username' => ['required', 'string'],
            'password' => ['required', 'string'],
        ];
    }

    //校验用户名密码
    public function authenticate()
    {
        $this->ensureIsNotRateLimited(); //检测是否超过限制

        if (!Auth::attempt($this->only('username', 'password'), $this->boolean('remember'))) {
            RateLimiter::hit($this->throttleKey()); //总尝试次数限制:默认60
            //抛出一个验证未成功的错误
            throw ValidationException::withMessages([
                'username' => trans('auth.failed'),
            ]);
        }

        RateLimiter::clear($this->throttleKey()); //清除限流
    }

    //检测登陆次数是否已超过了限制
    public function ensureIsNotRateLimited()
    {
        //每分钟不能超过5次
        if (!RateLimiter::tooManyAttempts($this->throttleKey(), 5)) {
            return;
        }
        event(new Lockout($this)); //锁定事件
        //返回在更多尝试可用之前剩余的秒数
        $seconds = RateLimiter::availableIn($this->throttleKey());
        //抛出错误信息
        throw ValidationException::withMessages([
            'username' => trans('auth.throttle', [
                'seconds' => $seconds, //多少秒后可以再次尝试登陆
                'minutes' => ceil($seconds / 60), //每分钟可以尝试多少次
            ]),
        ]);
    }

    //通过username与IP生成一个用于限流的Key
    public function throttleKey()
    {
        return Str::lower($this->input('username')) . '|' . $this->ip();
    }
}

现在程序逻辑部分的代码搞定了,下一步,我们将再新一个简单的登陆视图文件:

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    <title>用户登陆 - {{ config('app.name', '美食圈') }}</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
</head>
<body> 
    
<div class="p-5">
  <h1>{{ __('Login') }}</h1>
@if ($errors->any())
    <div class="alert alert-danger">
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif
<form method="POST" action="{{ route('login') }}">
    @csrf
    <div class="mb-3">
        <label for="inputName" class="form-label">用户名 *</label>
        <input type="text" class="form-control" id="inputName" name="username" required value="{{ old('username') }}">
        <div id="usernameHelp" class="form-text">请输入您要登陆的用户名</div>
      </div>   
  <div class="mb-3">
      <label for="inputPassword1" class="form-label">{{ __('Password') }} *</label>
      <input type="password" class="form-control" name="password" id="inputPassword1" required autocomplete="new-password">
    </div>
    <div class="mb-3">
      <input type="checkbox" class="form-check-input" name="remember" id="remember_me"> 
      <label class="form-check-label" for="remember_me">{{ __('Remember me') }}</label>  
    </div>
    
    <button type="submit" class="btn btn-primary"> {{ __('Login') }}</button>
    </form>
</div>   
</body>
</html>

 3、通过事件处理登陆信息

我希望用户每次登陆后,将自动更新数据表里的最后登陆时间、登陆IP等信息,在这里我们可以通过事件监听的方式处理:

php artisan make:event UserLogin #新建一个用户登陆事件

 此命令会自动生成文件:app/Events/UserLogin.php。

我们需要接收事件参数并交给下面的监听者处理:

<?php

namespace AppEvents;

use IlluminateBroadcastingInteractsWithSockets;
use IlluminateFoundationEventsDispatchable;
use IlluminateQueueSerializesModels;

class UserLogin
{
    use Dispatchable, InteractsWithSockets, SerializesModels;
    public $user;
    //创建一个新的事件实例。
    public function __construct($user)
    {
        $this->user = $user; //传参
    }
}

下面我们还需要通过命令创建一个监听者并与事件绑定,一个事件可以由多少监听者绑定:

php artisan make:listener UpdateUserLoginInfo --event=UserLogin #创建一个监听者并与UserLogin绑定

此命令会自动生成文件:app/Listeners/UpdateUserLoginInfo.php,在代码里可以看到与UserLogin的绑定信息:

<?php

namespace AppListeners;

use AppEventsUserLogin; //登陆事件
use CarbonCarbon; //时间处理

class UpdateUserLoginInfo
{
    //处理事件
    public function handle(UserLogin $event)
    {
        //更新用户最后登陆时间与IP        
        try {
            $user = $event->user;
            $user->login_at = Carbon::now()->toDateTimeString();
            $user->last_login_ip = request()->getClientIp();
            $user->save();
        } catch (Throwable $th) {
            report($th);
        }
    }
}

以上完成后,我们需要在系统里注册事件,打开:app/Providers/EventServiceProvider.php 找到protected $listen 属性,在里面增加:

protected $listen = [
    //注册用户登陆事件
    UserLogin::class => [
        UpdateUserLoginInfo::class, //可以存放多个监听者
    ],
];

注册好事件以后,我们需要去触发事件才可以,所以我们将在:app/Http/Controllers/Auth/AuthenticatedSessionController.php 的 store 方法里去触发登陆事件,在跳转前增加下面的代码:

event(new UserLogin(Auth::user())); //登陆事件

通过事件处理用户更新登陆时间与IP的方式是Laravel优雅的实现。到此,我们实现了基本的用户登陆、注册等功能。

除非注明,网络人的文章均为原创,转载请以链接形式标明本文地址:https://www.55mx.com/post/213
标签:laravel实战登陆注册验证Kwok最后编辑于:2022-04-11 10:11:53
0
感谢打赏!

《【Laravel实战】2、用户登陆、注册及相关事件处理》的网友评论(0)

本站推荐阅读

热门点击文章