原文链接:https://www.cnblogs.com/helloweba/p/8616332.html
上一篇文中,我们学习了什么是JWT(Json Web Token),今天我们来结合实例给大家讲述JWT的实战应用,就是如何使用前端Axios与后端PHP实现用户登录鉴权认证的过程。
查看演示 下载源码
文中涉及的重要知识点有:
因此在阅读这边文章之前,请先了解以上知识点以及JWT的基本概念,这样你会很快理解我们这篇文章中的实例代码。
准备
在本站上篇文章《有关JWT(Json Web Token)的那些事》有介绍用户登录鉴权流程:
用户使用用户名密码来请求服务器 服务器进行验证用户的信息 服务器通过验证发送给用户一个token 客户端存储token,并在每次请求时附送上这个token值 服务端验证token值,并返回数据
那么现在我们就按这个流程开始。
HTML
我们的HTML结构是这样的:一个登录表单,供用户输入用户名和密码,以及提交按钮;一个是登录成功后的显示信息。
<div id="showpage" style="display: none">
<div class="form-group">
<label for="username">用户名</label>
<input type="text" class="form-control" id="username" placeholder="请输入用户名">
</div>
<div class="form-group">
<label for="password">密码</label>
<input type="password" class="form-control" id="password" placeholder="请输入密码">
</div>
<button type="submit" id="sub-btn" class="btn btn-default">登录</button>
<br/>
<p class="bg-warning" style="padding: 10px;">演示用户名和密码都是<code>demo</code>。</p>
</div>
<div id="user" style="display: none"><p>欢迎<strong id="uname"></strong>,您已登录,<a href="javascript:;" id="logout">退出>></a></p></div>
详细的代码,可以下载demo源码中查看,这里样式我们使用的是Bootstrap3的经典样式。
Javascript
前端Javascript异步请求,我们使用Axios库,当然你也可以使用jQuery的Ajax方法。
首先引入axios库:
1
<
script
src="https://cdn.bootcss.com/axios/0.17.1/axios.min.js"></
script
>
按照流程,1.提交登录表单,发送用户名和密码到PHP后端,2.后端验证成功后,会发送一个token给前端,3.前端再拿这个token去请求需要用户权限访问,4.后端验证toen,鉴权,返回相应结果。下面的js代码实现了1,3两步。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<script>
document.querySelector(
'#sub-btn'
).onclick =
function
() {
let
username = document.querySelector(
'#username'
).value;
let
password = document.querySelector(
'#password'
).value;
var
params =
new
URLSearchParams();
params.append(
'user'
, username);
params.append(
'pass'
, password);
axios.post(
'user.php?action=login'
,
params
)
.then((response) => {
if
(response.data.result ===
'success'
) {
// 本地存储token
localStorage.setItem(
'jwt'
, response.data.jwt);
// 把token加入header里
axios.defaults.headers.common[
'X-token'
] = response.data.jwt;
axios.get(
'user.php'
).then(
function
(response) {
if
(response.data.result ===
'success'
) {
document.querySelector(
'#showpage'
).style.display =
'none'
;
document.querySelector(
'#user'
).style.display =
'block'
;
document.querySelector(
'#uname'
).innerHTML = response.data.info.data.username;
}
else
{
}
});
}
else
{
console.log(response.data.msg);
}
})
.
catch
(
function
(error) {
console.log(error);
});
}
</script>
很显然,当登录成功后,立马使用本地存储 token,然后把这个token放在请求头header里,再次去请求后端另一个用户信息接口,如果成功了就显示用户信息。
如果要退出登录,我们不需要再次去请求后端接口,直接前端清空本地存储就OK了。
1
2
3
4
5
document.querySelector(
'#logout'
).onclick =
function
() {
localStorage.removeItem(
'jwt'
);
document.querySelector(
'#showpage'
).style.display =
'block'
;
document.querySelector(
'#user'
).style.display =
'none'
;
}
登录成功后,当我们刷新页面(再次请求需要登录后才能访问的页面),需要进行判断,判断本地存储中是否有token,如果有token,那就拿去给后端接口验证下token是否合法,如果没问题就显示用户相关信息,如果验证失败,那可能是token过去或者伪造的token等原因。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let
jwt = localStorage.getItem(
'jwt'
);
if
(jwt) {
axios.defaults.headers.common[
'X-token'
] = jwt;
axios.get(
'user.php'
)
.then(
function
(response) {
if
(response.data.result ===
'success'
) {
document.querySelector(
'#showpage'
).style.display =
'none'
;
document.querySelector(
'#user'
).style.display =
'block'
;
document.querySelector(
'#uname'
).innerHTML = response.data.info.data.username;
}
else
{
document.querySelector(
'#showpage'
).style.display =
'block'
;
console.log(response.data.msg);
}
})
.
catch
(
function
(error) {
console.log(error);
});
}
else
{
document.querySelector(
'#showpage'
).style.display =
'block'
;
}
PHP
后端我们使用了一个专门的JWT库:php-jwt
使用composer安装php-jwt,接收到登录用户名和密码后,PHP验证用户名和密码是否正确(实际开发中应该结合数据库,从数据库里拿用户名和密码比对,本实例为了演示只做简单验证),如果用户名和密码准确无误,那么就签发token,在token中,我们可以定义token的签发者、过期时间等等,并返回给前端。注意在签发token时,我们需要定义一个密钥,这个密钥是一个私钥,实际应用中是保密的不可告诉别人。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
require
'vendor/autoload.php'
;
use
\Firebase\JWT\JWT;
define(
'KEY'
,
'1gHuiop975cdashyex9Ud23ldsvm2Xq'
);
//密钥
$res
[
'result'
] =
'failed'
;
$action
= isset(
$_GET
[
'action'
]) ?
$_GET
[
'action'
] :
''
;
if
(
$action
==
'login'
) {
if
(
$_SERVER
[
'REQUEST_METHOD'
] ==
'POST'
) {
$username
= htmlentities(
$_POST
[
'user'
]);
$password
= htmlentities(
$_POST
[
'pass'
]);
if
(
$username
==
'demo'
&&
$password
==
'demo'
) {
//用户名和密码正确,则签发tokon
$nowtime
= time();
$token
= [
'iss'
=>
'http://www.helloweba.net'
, //签发者
'aud'
=>
'http://www.helloweba.net'
, //jwt所面向的用户
'iat'
=>
$nowtime
,
//签发时间
'nbf'
=>
$nowtime
+ 10,
//在什么时间之后该jwt才可用
'exp'
=>
$nowtime
+ 600,
//过期时间-10min
'data'
=> [
'userid'
=> 1,
'username'
=>
$username
]
];
$jwt
= JWT::encode(
$token
, KEY);
$res
[
'result'
] =
'success'
;
$res
[
'jwt'
] =
$jwt
;
}
else
{
$res
[
'msg'
] =
'用户名或密码错误!'
;
}
}
echo
json_encode(
$res
);
}
else
{
$jwt
= isset(
$_SERVER
[
'HTTP_X_TOKEN'
]) ?
$_SERVER
[
'HTTP_X_TOKEN'
] :
''
;
if
(
empty
(
$jwt
)) {
$res
[
'msg'
] =
'You do not have permission to access.'
;
echo
json_encode(
$res
);
exit
;
}
try
{
JWT::
$leeway
= 60;
$decoded
= JWT::decode(
$jwt
, KEY, [
'HS256'
]);
$arr
= (
array
)
$decoded
;
if
(
$arr
[
'exp'
] < time()) {
$res
[
'msg'
] =
'请重新登录'
;
}
else
{
$res
[
'result'
] =
'success'
;
$res
[
'info'
] =
$arr
;
}
}
catch
(Exception
$e
) {
$res
[
'msg'
] =
'Token验证失败,请重新登录'
;
}
echo
json_encode(
$res
);
}
用户每次请求都要带上后端签发的token,后端获取请求中的token,PHP中使用$_SERVER['HTTP_X_TOKEN']
就可以获取token值。这个X_TOKEN
就是在我们前端的请求header头信息中。
然后PHP拿到这个token后,解密分析token值,返回给前端即可。
结束语
以上就是整个JWT的实战应用,我们可以看到,在用户鉴权的过程中并没有使用Session或者Cookie,服务端无需存储用户会话信息。只用了一个Token串,建立前后端的验证的数据传递,实现了有效的登录鉴权过程。