基于token的持久化登录讲解及其实现

目录

  • 前言
  • session的缺点
  • token简介
  • token两个性质
  • token简单实现思路
    • 分发token
    • 通过token验证身份
  • 代码实现
    • 登录处理程序loginRecv.php
    • 登录验证页面loginSuccessPage.php
    • 注销程序
  • 演示

前言

上回我们讲到【session+cookie简单讲解以及持久化登录实现】,我们通过在服务器端保存session,客户端保存cookie的方式,跳过繁琐的登录验证,快速验证用户是否登录,以及用户的身份信息。今天来学习另一种思路。

session的缺点

观察上一篇文章中的思路,我们不难看出:
基于token的持久化登录讲解及其实现_第1张图片
session存在于服务器内存,那么我们就不得不考虑高并发。我们很轻易的想到,高并发请求,将会快速的将服务器的内存占满,坏起来了!

如果我们非常有钱,我们可以购置114台服务器作为一个“集群”,存放与处理session的能力增加了。可是,用户两次身份验证,必须由同一台机器来完成,因为session存在于服务器,他们不共享。

如果我们很有钱,那么可以通过购置1919GB的内存,来缓解这种情况,但是现实往往事与愿违,我们希望找到一种节省空间的办法,来解决用户的登录问题。

token简介

说到token就不得不提一下新出的愚者2费token

token又名令牌,顾名思义,是一种身份验证标识。就如同校园卡一般,学校保安凭此确认你是本校学生,并且让你进门。因为校园卡只能由学校签发,而不是其他的机构。校园卡可理解为一种token。

token两个性质

校园卡只能由学校签发,这意味着我们只要给用户一种【只能由服务器下发】的令牌,可以不用查询数据库,就确认用户的信息。绕过数据库查询,能够减少数据库的压力,这是好的。除此之外我们还要能够确认,令牌来自服务器而不是个人伪造的。

综上所述,token需要有两个特性

  1. 只有服务器有能力签发token
  2. 服务器能够辨别每个token是否是自己亲手下发的

token简单实现思路

token分为分发token和验证token,分发token保证token的性质1,即只能由服务器签发,而验证token则维护了token的第二个性质,即服务器能够验证token是否出自自己签发。我们一个一个来看

分发token

初次登录的时候,我们将用户的信息(比如用户名),加上一个只有服务器知道的密钥,利用不可逆的加密算法,得到一个token。

因为密钥只有服务器知道,那么就保证了token的第一个特性:只有服务器有能力签发token。

我们将token通过cookie的形式下发给用户,这样每次用户访问的时候,都会带上token,方便服务器验证。除此之外,我们还将用户名存储在cookie中,作为用户的身份信息。注意token和用户身份信息的存放,是两个条目,即

key1 -> 身份信息
key2 -> token

基于token的持久化登录讲解及其实现_第2张图片

通过token验证身份

  1. 我们通过用户的cookie取出用户的用户身份信息,比如用户名
  2. 我们利用只有服务器才知道的密钥,将用户名加密,即再次制造token
  3. 将加密后的新token和用户cookie中的token对比,如果相同则表示认证成功

因为token只能由服务器制造,我们利用相同的密钥,再复现一次token的制造,如果两次制造的token相同,那么表示验证成功。这样做保证了token的第二个性质:服务器有能力确实用户的token是否由自己亲手签发的
基于token的持久化登录讲解及其实现_第3张图片

代码实现

我们编写登录处理程序loginRecv.php用来处理通过post提交的用户名与密码,用户登录程序写明了用户第一次登录要做的事情,即签发token。

然后我们编写登录验证页面loginSuccessPage.php来验证用户身份信息

最后我们编写注销程序logoutRecv.php来处理用户的注销请求

这里加密函数使用的是php自带的crypt()函数,密钥为$1$114#^514$

登录处理程序loginRecv.php

查询数据库并且分发token,这里使用密钥$1$114#^514$(即salt变量)来加密用户信息以制造token,

 
$input_username = $_POST["username"];
$input_password = $_POST["password"];

$sql_server = "localhost";
$sql_username = "root";
$sql_password = "";
$sql_database = "mydb";
$con = new mysqli($sql_server, $sql_username, $sql_password, $sql_database);
$sql = 'SELECT * FROM user_account WHERE username="' . $input_username . '"';

$res = $con->query($sql);

// 用户不存在
if($res==null || $res->num_rows==0) {
    echo "user not found";
} 
// 一个用户存在
else if($res->num_rows==1) {
    $user = $res->fetch_assoc();
    // 密码是否正确
    if($user["password"]==$input_password) {
        // 用户名存入cookie
        setcookie("username", $input_username, time()+99*365*24*60*60);
        // 加密后的用户名作为token存入cookie
        $salt = "$1$114#^514$";
        $token = crypt($input_username, $salt);
        setcookie("token", $token, time()+99*365*24*60*60);
        
        echo "login success";
    } else {
        echo "wrong password";
    }
} 
// 多个用户存在 查询出错
else if($res->num_rows>1) {
    echo "error";
} 
?>

登录验证页面loginSuccessPage.php

使用相同的密钥再次制造token,并且比对,从而判断用户信息。

 
// 检查是否携带cookie
if(!isset($_COOKIE["username"])) {
	die("请先登录");
}

// 使用相同密钥再次制造token并验证
$salt = "$1$114#^514$";
$token = crypt($_COOKIE["username"], $salt);
if($token!=$_COOKIE["token"]) {
	die("token验证失败, 登录失败");
}
?>

<!DOCTYPE html>
<html>
<head>
	<title>login success page</title>
	<meta charset="utf-8">
</head>
<body>
	<h1>登录成功页面</h1>
	<button onclick="javascrtpt:window.location.href='logoutRecv.php'">注销</button><br>
	 
	echo "欢迎: " . $_COOKIE["username"] . "
"
; ?> <a href="subPage1.php">页面1</a> </body> </html>

注销程序

直接将cookie设置为过期以销毁cookie即可

 
// 检查是否携带cookie
if(!isset($_COOKIE["username"])) {
	die("请先登录");
}
// 销毁cookie
setcookie("username", "", time()-99);	
setcookie("token", "", time()-99);	

echo "";
?>

演示

我们在登录页面登录
基于token的持久化登录讲解及其实现_第4张图片
然后我们跳转到登录成功页面,发现登录成功页面校验了我们的token,并且通过了校验,成功判断用户的身份
基于token的持久化登录讲解及其实现_第5张图片
点击注销,我们返回了登录页面
基于token的持久化登录讲解及其实现_第6张图片

我们再次造访登录成功页面,因为cookie过期,我们无权限访问登录成功页面
基于token的持久化登录讲解及其实现_第7张图片

你可能感兴趣的:(前后端,php,cookie,token)