摘要:需求一個用戶不能重復(fù)登錄后登錄者可以踢掉前者設(shè)計思路核心概念用戶是用戶表主鍵算法用戶用戶登錄的時間戳中存儲一份中存儲一份登錄的時間戳根據(jù)中登錄時間戳運(yùn)算后得到用戶訪問時如果那么認(rèn)為重復(fù)登陸銷毀登錄信息跳轉(zhuǎn)到登錄頁面流程描述用戶登錄的時候使用
需求
一個用戶不能重復(fù)登錄. 后登錄者可以踢掉前者.
設(shè)計思路: 核心概念用戶ID: 是用戶表主鍵 singleToken 算法: singleToken = md5(用戶IP + 用戶ID + 登錄的Unix時間戳) SESSION 中存儲一份 SESSION_SINGLE_TOKEN REDIS 中存儲一份 登錄的Unix時間戳 REDIS_SINGLE_TOKEN = 根據(jù)REDIS中登錄時間戳運(yùn)算后得到token 用戶訪問時: 如果 SESSION_SINGLE_TOKEN != REDIS_SINGLE_TOKEN 那么 認(rèn)為重復(fù)登陸,銷毀登錄信息,跳轉(zhuǎn)到登錄頁面流程描述
用戶登錄的時候使用用戶IP+用戶表主鍵+Unix時間戳組成的字符串, 經(jīng)過md5運(yùn)算生成一個singleToken 字符串. 并且存入session.
在redis中保存登錄時的 Unix時間戳,redis中保存的內(nèi)容應(yīng)該有過期時間, 通常和session過期時間一致.
key : SINGLE_TOKEN + 用戶id value : 登錄時 unix時間戳
每一次用戶請求需要登錄驗證的url, 那么用session中的singleToken 和 經(jīng)過md5運(yùn)算的 登錄IP+用戶ID+redis中的Unix時間戳 字符串作比較.
如果一致那么方可訪問.
如果redis中的時間戳為空,那么只是返回login頁面.
如果redis中時間戳不為空且兩個計算后的token不一致那么說明兩個賬戶同時登錄了, 那么返回login畫面并提示您的賬戶在其他位置登錄,不能重復(fù)登錄之類的消息.
開始實現(xiàn): 建立測試項目(準(zhǔn)備工作)為了展示我們的功能, 創(chuàng)建一個名為singleLogin的新項目.
composer create-project --prefer-dist laravel/laravel singleLogin
創(chuàng)建系統(tǒng)自帶的認(rèn)證
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擴(kuò)展
composer require predis/predis修改配置文件
配置一下數(shù)據(jù)庫(根目錄下的.env文件)
DB_CONNECTION=mysql DB_HOST=你的數(shù)據(jù)庫IP DB_PORT=3306 DB_DATABASE=你的數(shù)據(jù)庫名 DB_USERNAME=你的用戶名 DB_PASSWORD=你的密碼 REDIS_HOST=192.168.1.100 REDIS_PASSWORD=null REDIS_PORT=6379
配置好之后執(zhí)行migrate命令
php artisan migrate
輸出內(nèi)容
Migration table created successfully. Migrated: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_100000_create_password_resets_table
經(jīng)過以上的操作準(zhǔn)備工作就已經(jīng)做好了
創(chuàng)建單用戶中間件接下來為了驗證每次的url訪問請求, 我們需要1個middleware
php artisan make:middleware SingleLoginMiddleware
系統(tǒng)會生成一個文件 app/Http/Middleware/SingleLoginMidleware.php
把他修改成下面的樣子
guest()) { if ($request->ajax() || $request->wantsJson()) { return response("Unauthorized.", 401); } else { return redirect()->guest("/login"); } } if ($this->isRelogin($request)) { //清空登錄數(shù)據(jù), 重定向 $request->session()->flush(); $request->session()->regenerate(); return redirect()->guest("/login"); } return $next($request); } /** * 判斷用戶是否 重復(fù)登錄 * @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); // 重新獲取加密參數(shù)加密 $ip = $request->getClientIp(); $redisSingleToken = md5($ip . $user->id . $lastLoginTimestamp); if ($cookieSingleToken != $redisSingleToken) { //認(rèn)定為重復(fù)登錄了 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, ];配置中間件保護(hù)URL
設(shè)置 SingleLoginMiddleware 來保護(hù) /home url,
修改 routes/web.php ,修改后如下
"auth.singleLogin"], function() { # 用戶登錄成功后的路由 Route::get("/home", "HomeController@index"); });
修改 app/Http/Controllers/HomeController.php 刪掉部分代碼, 修改后如下
重寫登錄功能驗證登錄操作我們還需要一個登錄功能.
建立 app/Foundation/SingleLoginAuthenticatesUsers.php 文件內(nèi)容如下
這個文件的主要目的是改寫系統(tǒng)生成的 src/vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php
traits 的一個登錄后方法, 以實現(xiàn)我們登錄之后的一些處理.session()->regenerate(); $this->clearLoginAttempts($request); #這里來做登錄后的操作 $this->singleLogin($request); return $this->authenticated($request, $this->guard()->user()) ?: redirect()->intended($this->redirectPath()); } /** * 執(zhí)行單用戶登錄, 存儲必要數(shù)據(jù) * @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 中關(guān)于上面AuthenticatesUsers trait 的引用的地方, 修改后如下:
!!注意別忘了引入命名空間!!
use AuthenticatesUsers, SingleLoginAuthenticatesUsers{ SingleLoginAuthenticatesUsers::sendLoginResponse insteadof AuthenticatesUsers; }測試結(jié)果這樣我們就替換掉了系統(tǒng)中的 sendLoginResponse
方法取而代之的是我們 SingleLoginAuthenticatesUsers 中定義的 sendLoginResponse 方法分別使用兩個瀏覽器訪問 localhost/home,
第一瀏覽器登錄之后, 再去第二瀏覽器進(jìn)行登錄
然后再回到第一個瀏覽器的 localhost/home 刷新一下 發(fā)現(xiàn)跳轉(zhuǎn)到了 localhost/login
這樣就完成簡單的單用戶登錄功能.參考文檔:
Laravel 單用戶登錄 作者:Destiny
PHP中的Traits詳解 作者:tabalt
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/22217.html
摘要:本文經(jīng)授權(quán)轉(zhuǎn)自社區(qū)說明發(fā)布臨近,大體構(gòu)建已經(jīng)完成,文檔整理完成后即可發(fā)布。附帶了一個響應(yīng)式郵件模板,通知類中唯一需要做的就是像下面這樣發(fā)送消息錯誤處理是一個可選的擴(kuò)展包,提供了完整可用的服務(wù)。 本文經(jīng)授權(quán)轉(zhuǎn)自 PHPHub 社區(qū) 說明 Laravel 5.3 發(fā)布臨近,大體構(gòu)建已經(jīng)完成,文檔整理完成后即可發(fā)布。 下面是對 Laravel 5.3 新特性的整理,不完整列表。 1、全文搜...
摘要:最佳實踐良好的編碼規(guī)范單元測試持續(xù)集成文檔,從一開始就形成良好的編碼習(xí)慣。真實的電商業(yè)務(wù)所有的業(yè)務(wù)需求來自真實的客戶,并且線上良好運(yùn)營中。 重要通知: Laravel + 小程序的開源電商版本源碼已經(jīng)在 github 上拉,歡迎提交 issue 和 star :) 開源電商 Server 端: Laravel API源碼 開源電商 client 端:小程序源碼 iBrand 簡介...
摘要:提供了一種全新的發(fā)送通知的方式。個人理解是可以基于某事件操作觸發(fā)一系列的通知任務(wù),而通知方式由通知渠道接管,這樣使得通知或推送邏輯更抽象,更易于管理和重構(gòu)。在之前,我是利用的來完成這一系列通知。使用的配置文件還是原來的,無需重新配置。 Laravel Notification Laravel 5.3 提供了一種全新的發(fā)送通知的方式:Notification 。個人理解是可以基于某事件(...
摘要:的機(jī)器學(xué)習(xí)庫的機(jī)器學(xué)習(xí)庫,包括算法交叉驗證神經(jīng)網(wǎng)絡(luò)等內(nèi)容。在即將到來的大會上,她將和大家分享在機(jī)器學(xué)習(xí)領(lǐng)域的全新可能。入門總結(jié)入門相關(guān),如安裝配置基本使用等。 基于 Swoole 開發(fā) PHP 擴(kuò)展 Swoole-1.9.7 增加了一個新特性,可以基于 Swoole 使用 C++ 語言開發(fā)擴(kuò)展模塊,在擴(kuò)展模塊中可以注冊 PHP 內(nèi)置函數(shù)和類。現(xiàn)在可以基于 Swoole 來編寫 PHP ...
摘要:問題介紹同一個瀏覽器登錄后臺,再打開前臺頁面,前臺有輪訓(xùn)請求數(shù)據(jù),會出現(xiàn)后臺莫名其妙登出。問題排查檢查日志沒有發(fā)現(xiàn)問題,檢查沒有發(fā)現(xiàn)問題。 1.(環(huán)境介紹) laravel 5.3做的后臺,5.1做的前臺 兩個網(wǎng)站項目放在一臺服務(wù)器上后臺使用8080端口,前臺使用80端口,后臺需要登錄前臺不需要登錄。2.(問題介紹)同一個瀏覽器登錄后臺,再打開前臺頁面,前臺有js輪訓(xùn)請求數(shù)據(jù),會出現(xiàn)...
閱讀 3556·2023-04-25 20:41
閱讀 2671·2023-04-25 16:40
閱讀 1442·2021-09-23 11:44
閱讀 1260·2021-09-10 10:51
閱讀 1689·2021-09-07 09:59
閱讀 1661·2019-12-27 12:08
閱讀 562·2019-08-30 15:44
閱讀 3343·2019-08-30 11:08