登陆几乎是每个系统必备的,在这里和大家分享两种常用的登陆功能的设计。
一、session登陆:
网页登陆一般是将登陆信息存放在 session 中,最简单的登陆,当验证用户名密码成功后,将用户的id保存在 session中。例如
session('login_user',$user['id']);
这时一般会有一个is_login函数,功能很简单,去验证session('login_user')是否存在,如果存在就返回这个用户id,用户后面的业务,
例如:获取当前登录用户的个人信息。
反之,如果不存在,则跳转到登陆页面。
$user = session('login_user');
if (empty($user)) {
$this->redirect('login');
} else {
return $user;
}
这时候,对于需要控制登陆的页面,比如个人中心,只需要在相关的控制器的业务代码之前,加上is_login(),就可以判断登陆了。
登出也比较简单,情况这个session就好:
session('login_user',null);
但是这样设计的登陆有个问题,就是在不同的电脑上,同一个用户名可以同时登陆。所以一般还会在用户表中增加一个表示此用户
已经登陆的字段:例如status为1表示已登陆,0表示未登录。每次在用户登录的时候,都去验证这个用户的status,如果是0,则登
陆成功并且将status改为1,这时候如果改用户名被再次登陆,则提示用户此账号已登陆,不能重复登陆。但是很多时候,我们还是
希望像qq一样的登陆,在一台电脑上登陆,就踢掉其他电脑上已经登陆的该账号,那就继续看下面关于token的登陆。
二、token登陆:
token就是令牌,在app登陆和第三方接口授权登陆的时候经常用到。在验证用户名与密码成功后,后台会生成一个token返回给前端,
且token不重复,例如:
$token = md5(sha1(time().rand(0,10)));
上面代码就生成了一个简单的token(理论上不是完全没可能重复,但是几率非常非常小)。这个token后台也需要保存起来,对于一般
的网站,可以保存在数据库中,如果访
问量比较大,保存在nosql中也是ok的,比如redis。一般情况下,还需要为每个token设置一个过期时间,比如10分钟。同时,app在
后台返回这个token的时候,也要将token保存在本地。在app以后请求后台的时候,都需要带上这个token。后
台验证token的代码如下:
public function isLogin() {
$header = getallheaders();
$token = $header['token'];
if(empty($token)){
$this->Response(3,'请登录',array());
}
$map['token'] = $token;
$map['deadline'] = array('egt',time());
$arr = M("token")->field("uid,token,deadline")->where($map)->find();
if(!$arr) {
$this->Response(3,'请登录',array());
}else{
$res = M("token")->where('uid=%d',$arr['uid'])->setField('deadline',intval(time())+20*60);
if($res){
return $arr['uid'];
}
}
}
如上代码:前端将token放在http请求的头部,后台获取token,如果没获取到就返回请登录。我们这里是把token存在数据库中的,获
取token后,我们去验证我们数据库里是否有这个token,且这个token没过期。一般情况下,是多少分钟内用户不操作变自动退出登
录。所以上面代码中,如果token验证成功,我们就把token的过期时间延后20分钟。验证成功后,返回用户id给其他业务逻辑使用。
用token登陆就不会存在重复登陆的问题了,因为每次用户登陆成功就会生出新的token,且一个token只针对一个用户,所以之前登
陆的用户的token就失效了,需要重新登陆。虽然可以把token作为用户表中的一个字段,然后不少系统也是有单独的token表来管理
token的,这样会灵活许多,如果你想提示被踢掉的用户,您被提掉了,那边token作为一个字段是做不到的,我们只知道用户那个
token不存在了。但是如果有个token表记录历史的token,那我们就可以发现这个token是存在且没过期的,然而却不是这个账号最新
的,这时候就可以提示用户,您被踢掉了。当然坏处就是需要保存token的历史数据,需要额外存储比较多的数据。