摘要:需求一个用户不能重复登录后登录者可以踢掉前者设计思路核心概念用户是用户表主键算法用户用户登录的时间戳中存储一份中存储一份登录的时间戳根据中登录时间戳运算后得到用户访问时如果那么认为重复登陆销毁登录信息跳转到登录页面流程描述用户登录的时候使用
需求
一个用户不能重复登录. 后登录者可以踢掉前者.
设计思路: 核心概念用户ID: 是用户表主键 singleToken 算法: singleToken = md5(用户IP + 用户ID + 登录的Unix时间戳) SESSION 中存储一份 SESSION_SINGLE_TOKEN REDIS 中存储一份 登录的Unix时间戳 REDIS_SINGLE_TOKEN = 根据REDIS中登录时间戳运算后得到token 用户访问时: 如果 SESSION_SINGLE_TOKEN != REDIS_SINGLE_TOKEN 那么 认为重复登陆,销毁登录信息,跳转到登录页面流程描述
用户登录的时候使用用户IP+用户表主键+Unix时间戳组成的字符串, 经过md5运算生成一个singleToken 字符串. 并且存入session.
在redis中保存登录时的 Unix时间戳,redis中保存的内容应该有过期时间, 通常和session过期时间一致.
key : SINGLE_TOKEN + 用户id value : 登录时 unix时间戳
每一次用户请求需要登录验证的url, 那么用session中的singleToken 和 经过md5运算的 登录IP+用户ID+redis中的Unix时间戳 字符串作比较.
如果一致那么方可访问.
如果redis中的时间戳为空,那么只是返回login页面.
如果redis中时间戳不为空且两个计算后的token不一致那么说明两个账户同时登录了, 那么返回login画面并提示您的账户在其他位置登录,不能重复登录之类的消息.
开始实现: 建立测试项目(准备工作)为了展示我们的功能, 创建一个名为singleLogin的新项目.
composer create-project --prefer-dist laravel/laravel singleLogin
创建系统自带的认证
php artisan make:auth
php artisan route:list
+--------+----------+------------------------+----------+------------------------------------------------------------------------+--------------+ | Domain | Method | URI | Name | Action | Middleware | +--------+----------+------------------------+----------+------------------------------------------------------------------------+--------------+ | | GET|HEAD | / | | Closure | web | | | GET|HEAD | api/user | | Closure | api,auth:api | | | GET|HEAD | home | | AppHttpControllersHomeController@index | web,auth | | | GET|HEAD | login | login | AppHttpControllersAuthLoginController@showLoginForm | web,guest | | | POST | login | | AppHttpControllersAuthLoginController@login | web,guest | | | POST | logout | logout | AppHttpControllersAuthLoginController@logout | web | | | POST | password/email | | AppHttpControllersAuthForgotPasswordController@sendResetLinkEmail | web,guest | | | GET|HEAD | password/reset | | AppHttpControllersAuthForgotPasswordController@showLinkRequestForm | web,guest | | | POST | password/reset | | AppHttpControllersAuthResetPasswordController@reset | web,guest | | | GET|HEAD | password/reset/{token} | | AppHttpControllersAuthResetPasswordController@showResetForm | web,guest | | | GET|HEAD | register | register | AppHttpControllersAuthRegisterController@showRegistrationForm | web,guest | | | POST | register | | AppHttpControllersAuthRegisterController@register | web,guest | +--------+----------+------------------------+----------+------------------------------------------------------------------------+--------------+安装redis扩展
composer require predis/predis修改配置文件
配置一下数据库(根目录下的.env文件)
DB_CONNECTION=mysql DB_HOST=你的数据库IP DB_PORT=3306 DB_DATABASE=你的数据库名 DB_USERNAME=你的用户名 DB_PASSWORD=你的密码 REDIS_HOST=192.168.1.100 REDIS_PASSWORD=null REDIS_PORT=6379
配置好之后执行migrate命令
php artisan migrate
输出内容
Migration table created successfully. Migrated: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_100000_create_password_resets_table
经过以上的操作准备工作就已经做好了
创建单用户中间件接下来为了验证每次的url访问请求, 我们需要1个middleware
php artisan make:middleware SingleLoginMiddleware
系统会生成一个文件 app/Http/Middleware/SingleLoginMidleware.php
把他修改成下面的样子
guest()) { if ($request->ajax() || $request->wantsJson()) { return response("Unauthorized.", 401); } else { return redirect()->guest("/login"); } } if ($this->isRelogin($request)) { //清空登录数据, 重定向 $request->session()->flush(); $request->session()->regenerate(); return redirect()->guest("/login"); } return $next($request); } /** * 判断用户是否 重复登录 * @param $request * @return bool */ protected function isRelogin($request) { $user = Auth::user(); if ($user) { $cookieSingleToken = session("SINGLE_TOKEN"); if ($cookieSingleToken) { // 从 Redis 获取 time $lastLoginTimestamp = Redis::get("SINGLE_TOKEN_" . $user->id); // 重新获取加密参数加密 $ip = $request->getClientIp(); $redisSingleToken = md5($ip . $user->id . $lastLoginTimestamp); if ($cookieSingleToken != $redisSingleToken) { //认定为重复登录了 return true; } return false; } } return false; } }注册单用户中间件
注册 SingleLoginMiddleware 到 kernel
打开 path/singleLogin/src/app/Http/Kernel.php
//在下面添加singleLogin一行 protected $routeMiddleware = [ "auth" => IlluminateAuthMiddlewareAuthenticate::class, ... IlluminateRoutingMiddlewareThrottleRequests::class, "auth.singleLogin" => AppHttpMiddlewareSingleLoginMiddleware::class, ];配置中间件保护URL
设置 SingleLoginMiddleware 来保护 /home url,
修改 routes/web.php ,修改后如下
"auth.singleLogin"], function() { # 用户登录成功后的路由 Route::get("/home", "HomeController@index"); });
修改 app/Http/Controllers/HomeController.php 删掉部分代码, 修改后如下
重写登录功能验证登录操作我们还需要一个登录功能.
建立 app/Foundation/SingleLoginAuthenticatesUsers.php 文件内容如下
这个文件的主要目的是改写系统生成的 src/vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php
traits 的一个登录后方法, 以实现我们登录之后的一些处理.session()->regenerate(); $this->clearLoginAttempts($request); #这里来做登录后的操作 $this->singleLogin($request); return $this->authenticated($request, $this->guard()->user()) ?: redirect()->intended($this->redirectPath()); } /** * 执行单用户登录, 存储必要数据 * @param Request $request * @throws Exception */ protected function singleLogin(Request $request) { try { $timeStampNow = time(); $userLoginIp = $request->getClientIp(); $user = Auth::user(); $singleToken = md5($userLoginIp . $user->id . $timeStampNow); Redis::set("SINGLE_TOKEN_" . $user->id, $timeStampNow); session(["SINGLE_TOKEN" => $singleToken]); } catch (Exception $exception) { throw new Exception($exception); } } }然后我们修改 app/Http/Controllers/Auth/LoginController.php 中关于上面AuthenticatesUsers trait 的引用的地方, 修改后如下:
!!注意别忘了引入命名空间!!
use AuthenticatesUsers, SingleLoginAuthenticatesUsers{ SingleLoginAuthenticatesUsers::sendLoginResponse insteadof AuthenticatesUsers; }测试结果这样我们就替换掉了系统中的 sendLoginResponse
方法取而代之的是我们 SingleLoginAuthenticatesUsers 中定义的 sendLoginResponse 方法分别使用两个浏览器访问 localhost/home,
第一浏览器登录之后, 再去第二浏览器进行登录
然后再回到第一个浏览器的 localhost/home 刷新一下 发现跳转到了 localhost/login
这样就完成简单的单用户登录功能.参考文档:
Laravel 单用户登录 作者:Destiny
PHP中的Traits详解 作者:tabalt
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/22217.html
摘要:本文经授权转自社区说明发布临近,大体构建已经完成,文档整理完成后即可发布。附带了一个响应式邮件模板,通知类中唯一需要做的就是像下面这样发送消息错误处理是一个可选的扩展包,提供了完整可用的服务。 本文经授权转自 PHPHub 社区 说明 Laravel 5.3 发布临近,大体构建已经完成,文档整理完成后即可发布。 下面是对 Laravel 5.3 新特性的整理,不完整列表。 1、全文搜...
摘要:最佳实践良好的编码规范单元测试持续集成文档,从一开始就形成良好的编码习惯。真实的电商业务所有的业务需求来自真实的客户,并且线上良好运营中。 重要通知: Laravel + 小程序的开源电商版本源码已经在 github 上拉,欢迎提交 issue 和 star :) 开源电商 Server 端: Laravel API源码 开源电商 client 端:小程序源码 iBrand 简介...
摘要:提供了一种全新的发送通知的方式。个人理解是可以基于某事件操作触发一系列的通知任务,而通知方式由通知渠道接管,这样使得通知或推送逻辑更抽象,更易于管理和重构。在之前,我是利用的来完成这一系列通知。使用的配置文件还是原来的,无需重新配置。 Laravel Notification Laravel 5.3 提供了一种全新的发送通知的方式:Notification 。个人理解是可以基于某事件(...
摘要:问题介绍同一个浏览器登录后台,再打开前台页面,前台有轮训请求数据,会出现后台莫名其妙登出。问题排查检查日志没有发现问题,检查没有发现问题。 1.(环境介绍) laravel 5.3做的后台,5.1做的前台 两个网站项目放在一台服务器上后台使用8080端口,前台使用80端口,后台需要登录前台不需要登录。2.(问题介绍)同一个浏览器登录后台,再打开前台页面,前台有js轮训请求数据,会出现...
阅读 3402·2023-04-25 20:41
阅读 2636·2023-04-25 16:40
阅读 1391·2021-09-23 11:44
阅读 1231·2021-09-10 10:51
阅读 1635·2021-09-07 09:59
阅读 1595·2019-12-27 12:08
阅读 524·2019-08-30 15:44
阅读 3317·2019-08-30 11:08