首页  >  问答  >  正文

PHP判断用户登录状态,效率并且安全的方案是什么?

本人比较菜,目前使用的方案是

1.在客户端COOKIES中保存用户ID和一个加密码(规则只有我知道)
2.如果程序检测到客户端保存的COOKIES ID。就去跟数据库验证加密码,如果一致则返回对应用户的登录信息,否则返回FALSE

感觉效率和安全性都不是很好

1.用户访问每个页面都要去跟数据库验证一遍
2.加密码虽然规则很复杂,但是保存在客户端依然存在被破解的可能性

迷茫迷茫2749 天前724

全部回复(5)我来回复

  • 大家讲道理

    大家讲道理2017-04-10 14:26:47

    “用户访问每个页面都要去跟数据库验证一遍” 这怎么会呢?

    1,浏览器URL访问页面资源,
    2,查看SESSION会话是否记录登陆状态,如“否”从3继续,如“是”则到5
    3,获取浏览器客户端的COOKIE用户标识信息,如果存在用户信息则继续4,如“否”或者不符合既定原则 则到6
    4,判断用户标识是否可信,比如将加密的字串解密,取出字串中的id和密码与数据库中信息对比是否匹配,如果匹配则到5,如果不匹配则6
    5,验证登陆状态通过
    6,验证登陆状态不通过

    如此看怎么会老是读数据库呢?

    分割线

    一般常规“记住登陆”方法,可以将ID和密码组合成字符串再salt加密后存到浏览器客户端。每次和服务器端验证时,再解密分割取得ID和密码与数据库比对。如此安全性还是可以的。

    比如这是存到客户端COOKIE

    $data      = $id . "\t" . md5( $password . $slat); //$slat可以是硬编或者随机存在用户列的值
    $identity  = base64_encode( encrypt( $data , $key ) );//encrypt为自实现的加密函数或方法,$key 可以是硬编或者随机存在用户列的值
    setcookie("testuser", $identity, time()+3600);

    比如这是取

    if(isset($_COOKIE['testuser']))
    {
        $identity = $_COOKIE['testuser'];
        list($id, $password) = explode("\t", decrypt( base64_decode( $identity ) ,  $key));//decrypt为自实现的解密函数或方法,$key 可以是硬编或者随机存在用户列的值
        
        //todo  与数据库列值比对
        //...
    }

    回复
    0
  • PHP中文网

    PHP中文网2017-04-10 14:26:47

    将用户信息保存至COOKIES中。
    用户信息包括:UID,USERNAME,EMAIL,PASSWORD。
    其中 EMAIL,PASSWORD进行可逆加密。
    每次登录只须将COOKIES进行一次可逆加密和你数据库对比一次若相等则登录,否则进行正常的登录操作。

    ===============

    PS

    ======================

    关于cookies中是否可以存放用户信息,一直都是业界存在争议的一点。
    目前我的解决方法是:
    cookies中存放有关于邮箱、QQ号码、用户密码、用户名等信息均需要进行可逆加密。
    如有用户信息:

    array("uid"=>1,"username"=>"b","password"=>"1234567","email"=>"abc@abc.com");

    那么,我将uid,username,password,email等信息分别存放与cookies中,并且将username,password,email通过key(key只能自己知道和设置)进行可逆加密。当每一次需要操作的时候,我只需要$_COOKIE['password']然后将其解密还原为原始的1234567即可,然后将其进行查询匹配。若查询相同则认为该COOKIES有效,若不匹配则删除cookies。

    那么,解密之后查询认证有两种方法:

    1.直接连接数据库进行SQL查询,这是一种消耗性能的低效方法。

    select username,uid,password from xxxx where uid='xxxx',username='xxxxx' LIMIT 1;

    这种方法没操作一次需要进行一次SQL查询,将大大增加性能开销。

    2.将用户第一次登录查询出来的信息加密保存在cookies的同时,copy保存一份至memcached内存中,并增加标识 uid_status(可自取) 为 1 (登录状态),每一个用户拥有一个唯一的uid_status,并且设置为长期有效。

    判断是否登录的过程则更加高效和快速。

    将cookies中的信息解密之后,查看uid_status的状态,若为1,直接认定该用户处于登录状态,不删除cookies信息。若为0,非登录状态,则将cookies和memcached中的用户信息进行匹配。匹配包括:password,uid,username。若其中一项不正确则删除cookies,更新uid_status状态。

    以上就是我判断用户是否登录过程。

    ========

    P.S

    ===========

    DISCUZ!系列是采用cookies加密后直接查询数据库进行cookies有效判断的。

    uc_home核心代码是:

    <?php
    //判断当前用户登录状态
    function checkauth() {
    	global $_SGLOBAL, $_SC, $_SCONFIG, $_SCOOKIE, $_SN;
    
    	if($_SGLOBAL['mobile'] && $_GET['m_auth']) $_SCOOKIE['auth'] = $_GET['m_auth'];
    	if($_SCOOKIE['auth']) {
    		@list($password, $uid) = explode("\t", authcode($_SCOOKIE['auth'], 'DECODE'));
    		$_SGLOBAL['supe_uid'] = intval($uid);
    		if($password && $_SGLOBAL['supe_uid']) {
    			$query = $_SGLOBAL['db']->query("SELECT * FROM ".tname('session')." WHERE uid='$_SGLOBAL[supe_uid]'");
    			if($member = $_SGLOBAL['db']->fetch_array($query)) {
    				if($member['password'] == $password) {
    					$_SGLOBAL['supe_username'] = addslashes($member['username']);
    					$_SGLOBAL['session'] = $member;
    				} else {
    					$_SGLOBAL['supe_uid'] = 0;
    				}
    			} else {
    				$query = $_SGLOBAL['db']->query("SELECT * FROM ".tname('member')." WHERE uid='$_SGLOBAL[supe_uid]'");
    				if($member = $_SGLOBAL['db']->fetch_array($query)) {
    					if($member['password'] == $password) {
    						$_SGLOBAL['supe_username'] = addslashes($member['username']);
    						$session = array('uid' => $_SGLOBAL['supe_uid'], 'username' => $_SGLOBAL['supe_username'], 'password' => $password);
    						include_once(S_ROOT.'./source/function_space.php');
    						insertsession($session);//登录
    					} else {
    						$_SGLOBAL['supe_uid'] = 0;
    					}
    				} else {
    					$_SGLOBAL['supe_uid'] = 0;
    				}
    			}
    		}
    	}
    	if(empty($_SGLOBAL['supe_uid'])) {
    		clearcookie();
    	} else {
    		$_SGLOBAL['username'] = $member['username'];
    		if($_SGLOBAL['connect']) {
    			cloud_token();
    		}
    	}
    }
    ?>

    回复
    0
  • 高洛峰

    高洛峰2017-04-10 14:26:47

    cookie中怎么能够保存密码呢?

    你的做法已经可以了,不过有如下几点建议:
    1. 客户端可以保存两种数据,一种是原数据(比如user_id),一种是对所有原数据的签名(你所说的加密码)
    2. 原数据的保存可以看具体情况保存原字符串或者可逆加密算法加密后的字符串
    3. 针对所有的原数据的签名的算法,最好是不可逆的
    4. 服务器端只要获取到原数据,重新计算签名,比如和cookie中的签名是否一致即可。

    最简单的cookie的样子:
    A=uid=123&sign=xxxxxxxx

    cookie生成方法:
    sign = md5(secure_key + uid);
    cookie = 'uid=' + uid + '&sign=' + sign
    secure_key 是一个私有的串,谁也不能告诉哦。

    cookie校验的方法:
    获取到uid和sign之后
    sign == md5(secure_key + uid)

    当然如果觉得md5不可靠的话,可以选择更好的算法。

    回复
    0
  • 巴扎黑

    巴扎黑2017-04-10 14:26:47

    一般这样的不是用$_SESSION变量的么,COOKIES肯定不能保存密码额。我一般是这样用的,用$_SESSION保存登陆状态,用$_COOKIES保存一个用户ID什么的。

    回复
    0
  • PHP中文网

    PHP中文网2017-04-10 14:26:47

    只在session中存放UID行不行?

    每个页面判断是否存在UID,该UID只有在登录页面才会被添加进session,在登出的时候清空该session

    回复
    0
  • 取消回复