JWT鉴权
JWT全称 JSON Web Token,是一套开放的标准(RFC 7519),它定义了一种紧凑且自URL安全的方式,以JSON对象的方式在各方之间安全地进行信息传输。
使用密钥 ( secret ) ( HMAC算法生成 ) 或者 使用RSA或ECDSA的 公有/私有密钥 对JWT进行签名。
JSON Web Token
一些常用到JWT的情况:
- 授权:这是使用JWT的最常见方案。一旦用户登录,每个后续请求将包括JWT,从而允许用户访问该令牌允许的路由,服务和资源。单点登录是当今广泛使用JWT的一项功能,因为它的开销很小并且支持跨域。
- 信息交换:JWT是在各方之间安全地传输信息的好方法。因为可以对JWT进行签名(例如,使用公钥/私钥对)。此外,由于签名是使用Header和Payload计算的,因此还可以验证内容是否遭到篡改。
JWT 数据结构
JWT 以紧凑的形式由三部分组成,这些部分由点(.)分隔,分别是:
- Header — base64转码显示的头部信息 (明文)
- Payload — base64转码显示的签发信息(明文)
- Signature — hs256加密显示的密码 ( 密文 )
JWT 使用流程
- 登录 ---- 成功 ---- 根据密钥生成 token ( 两段明文和一段密文 ) 像门票的存在
- token ---- 存储; 获取到 token ---- 请求到头部 携带 token ---- 服务端
- 服务端 ---- 验证通过 ---- 返还数据
- 服务端 ---- 验证不通过 ---- 返回 401
实际使用案例
登录时验证并签发token,前端保存
- 前端页面核心代码
<div class="loginContainer">
<h1>登录</h1>
<form action="/checkUser" method="post" onsubmit="return false;" >
姓名:<input class="inputStyle" type="text" name="username" /><br />
密码:<input class="inputStyle" type="password" name="pwd" /><br />
<input class="loginStyle" type="submit" value="登录" />
<button class="btn">点击 - 认证接口</button>
</form>
</div>
<script>
// 登录按钮
document.querySelector(".loginStyle").onclick = function(){
let username = document.getElementsByName("username")[0].value;
let password = document.getElementsByName("pwd")[0].value;
let xhr = new XMLHttpRequest;
xhr.open("post","/checkUser",true);
// 设置头部信息的位置 必须写在 open 下面
// post 传参不设置头部的话 服务器拿到的数据就是字符串(不转格式的情况下)
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
// 接收服务器端返回的数据
xhr.onload = function(){
console.log(xhr.responseText);
// 数据类型 --> 对象 --> 获取token
let token = JSON.parse(xhr.responseText).token;
// 本地存储 token
localStorage.setItem("token",token);
// 后续功能可以写跳转页面
}
// 将用户的登录信息发送到后端
let data = `username=${username}&pwd=${password}`;
xhr.send(data);
}
</script>
- 后端服务器核心代码
注意token的有效时间设置
在实际使用中 有效时间越短越安全
// 直接使用 不需要通过app
const jwt = require("jsonwebtoken"); // 签发 token
router.post("/checkUser",ctx=>{
console.log(ctx.request.body);
let {username,pwd} = ctx.request.body;
// 信息对象 用于返还到客户端
let info;
if (username === "秦兟" && pwd === "123") {
// 验证成功,签发token
// 参数1 : { } 信息对象 -- 用户信息,前后端交互
// 参数2 : 密钥 -- 后端保存,视情况给前端
// 参数3 : { } 时效性 -- 签发之后,时效性内不可修改 时效性越短越好
const token = jwt.sign({
_id:1
},"mytoken",{expiresIn:"2h"});
info = {
message:"正确",
status:1,
token //让 info携带 token 发给前端
}
}else{
info = {
message:"错误",
status:0
}
}
ctx.body = info;
})
需要使用 token 验证的场景
- 前端核心代码
<button class="btn">点击 - 认证接口</button>
<script>
document.querySelector(".btn").onclick =function(){
let xhr = new XMLHttpRequest();
xhr.open("post","/apiCheck",true);
// 获取 本地保存的token
let token = localStorage.getItem("token");
// 前端的认证
if (token) {
// Authorization : 告诉浏览器 携带着 token 属性
// Bearer空格:固定方式 + token
// Bearer 带有空格 注意必须带
xhr.setRequestHeader("Authorization","Bearer " + token)
}
// 接收后端验证token信息的返回值
xhr.onload = function(){
// Authentication Error 验证不通过 token错误
console.log(xhr.responseText);
}
xhr.send();
}
</script>
- 后端服务器核心代码
const koajwt = require("koa-jwt"); // 验证 token
// token 认证的接口 jwt在这里验证
// koajwt() 验证密码
// Authentication Error 验证不通过 token错误
router.post("/apiCheck",koajwt({secret:"mytoken"}),ctx=>{
ctx.body = {
name:"来自验证接口"
}
})