登陆流程介绍
正常登陆
- 前端提交账号密码
- 后端验证并通过
- 从数据库读取该用户的数据,并存入
session
- 登陆成功,跳转到其他页面,到达目标方法前,会经过中间键。
- 中间键:在每次调用方法前,判断有无
session
,有的话,去目标地址。没有的话,跳转到登陆页面。
记住我登陆
- 前端提交账号密码
- 后端验证并通过
- 从数据库读取该用户的数据,并存入
session
;然后生成一串,独一无二的随机字符串,例如:Y2fcNHO761x7cdo7H4Yf
,存入用户数据表中。同时,给前端返回一个cookie,例如:"remember"=>Y2fcNHO761x7cdo7H4Yf
- 登陆成功,跳转到其他页面,到达目标方法前,会经过中间键。
- 中间键:在每次调用方法前,判断有无
session
,有的话,去目标地址。没有的话,判断访问用户有无携带key
为remember
的cookie
,如果有,则通过Session
中的uid
和remember
去查找用户数据表有无匹配数据。有的话,读取用户信息,并写入session,跳转到目标页面;没有的话,返回登陆页面
什么情况下会导致通过cookie找不到数据库中的用户数据
1. 客户端浏览器cookie过期
2. 在另一个终端进行了【记住我登陆】,更新了数据库中的remember随机字符串
<?php
namespace App\Http\Controllers;
class LoginController extends Controller
{
public function index(Request $request)
{
if ($request->method() == 'POST') {
$remember_token = "";
User::query()->where('id', $user->id)->update(['last_login' => time()]);
if ($request->get('remember')) {
$remember_token = makeRandStr(20);
User::query()->where('id', $user->id)->update(['last_login' => time(), "remember_token" => $remember_token]);
} else {
User::query()->where('id', $user->id)->update(['last_login' => time()]);
}
$userInfo = User::query()->where('id', $user->id)->first();
$request->session()->put('user', $userInfo->toArray());
return Redirect::to('user')->cookie('remember', $remember_token, 36000);
}
}
}
<?php
namespace App\Http\Middleware;
use Closure;
use Redirect;
use App\Http\Models\User as U;
class User
{
public function handle($request, Closure $next)
{
if (!$request->session()->has('user')) {
if ($request->cookie("remember")) {
$u = U::query()->where("remember_token", $request->cookie("remember"))->first();
if ($u) {
$request->session()->put('user', $u->toArray());
return $next($request);
}
}
return Redirect::to('login');
}
return $next($request);
}
}
Route::group(['middleware' => ['user']], function () {
Route::any('user/index', 'UserController@index');
})
Cookie机制描述
Cookie可以理解为,保存在客户端,浏览器生成并可读取的一个文件。
只存在与客户端,用于向服务器传递历史访问数据,并可以记录将来的访问数据。
Session机制描述
当用户访问到一个服务器,服务器就要为该用户创建一个`SessionID`
服务器首先会检测请求有无提交SessionID:
如果有,说明该用户已经登陆过,并创建了SessionID,则服务器会去内存中查找对应的Session
如果没有,则会创建,并生成相关的SessionID,SessionID是唯一的,不重复的,不容易找到规律的字符串。这个SessionID会在本次响应中返回到客户端保存,而保存这个SessionID的就是Cookie。并且在下次请求时,浏览器会携带此SessionID
Cookie机制与Session机制的区别和联系
敲黑板!!!敲黑板!!!
具体来说cookie机制采用的是在客户端保持状态的方案,而Session机制采用的是在服务器端保持状态的方案。同时我们也看到,由于在服务器端保持状态的方案在客户端也需要保存一个标识,所以Session机制可能需要借助于cookie机制来达到保存标识的目的,但实际上还有其他选择。
例如,我们经常用到的会员卡,也就相当于这种情况。消费到了一定程度就有奖
就如下面例子说明:
1.发给顾客一张卡片,上面记录着消费的数量,一般还有个有效期限。每次消费时,如果顾客出示这张卡片,则此次消费就会与以前或以后的消费相联系起来。这种做法就是在客户端保持状态。
2.发给顾客一张会员卡,除了卡号之外什么信息也不纪录,每次消费时,如果顾客出示该卡片,则店员在店里的纪录本上找到这个卡号对应的纪录添加一些消费信息。这种做法就是在服务器端保持状态。
通过redis进行单点登陆
很多情况下,需要限制用户,保持单点登陆。我们借助Redis,可以很容易的实现。
- 前端提交账号密码
- 后端验证并通过
- 从数据库读取该用户的数据,并存入
session
;然后生成一串,独一无二的随机字符串,例如:Y2fcNHO761x7cdo7H4Yf
。随机字符串作为token
,存入session中;并且按照uid=>随机字符串的格式,存入redis
中例如:"20"=>"Y2fcNHO761x7cdo7H4Yf"
- 登陆成功,跳转到其他页面,到达目标方法前,会经过中间键。
- 中间键:在每次调用方法前,从
session
中获取uid
,通过此uid
到redis
中查找对应的随机字符串str
。将str
与session
中的token
进行比较,如果一致,可以跳转到下一步;如果不一致,清除之前的session
- 判断有无
session
,有的话跳转到目标地址;没有的话,跳转到登陆页面
if($this->id){
$this->redis=$this->connect_redis();
$session_id=$this->redis->get("manager_".$this->id);
$check_token=session('token');
if($check_token!=$session_id){
$this->username=null;
$this->id=null;
$this->loginname=null;
$this->ulevel=null;
session(null);
}
}
$this->checkLogin();
总结:
其实【记住我登陆】和【通过redis进行单点登陆】是共通的,redis和mysql数据库都只是一种第三方媒介,区别在于不同媒介的时效性和IO效率。
redis存储在内存中,因此IO特别快,适合于调用频繁的数据。【通过redis进行单点登陆】作为前置操作,在调用大部分方法前,都需要调用,所以讲究效率。并且数据更新快,不需要长期保存。因此用redis
mysql存储在硬盘上,适合长期保存。【记住我登陆】的时效性取决于客户端cookie有效期的设置,因此,数据可能需要长期保存。并且在这个情景下,只有在服务端session失效的前提下,才会去调用一次数据库,调用完毕以后,又有了一个session有效期。所以使用频率很低。所以使用mysql
感谢 :
【转】WEB应用中的SESSION知多少?