jsonweb token验证问题

jwt 原理
在这里插入图片描述

  1. 客户端用户使用用户名和密码通过 POST 请求登录或注册
  2. 服务端确认用户合法,生成一个 JWT
  3. 将 JWT 返回给客户端,客户端将其保存在本地(一般保存在 localStorage 中)
  4. 之后客户端向服务端发送 HTTP 请求需要将 JWT 加入请求头中
  5. 服务器解析 JWT,检查是否合法且有效
  6. 根据检查结果对客户端做出响应

JWT 结构

服务端生成的 JWT 是一段很长的字符串,由三部分组成,分别为 Header(头部)、Payload(负载)和 Signature(签名),中间用.分隔:
在这里插入图片描述
1. Header

头部 Header 是经过 Base64Url[1] 编码的 JSON 对象:

{
“alg”: “HS256”,
“typ”: “JWT”
}
其中,alg是 JWT 所使用的签名算法,默认为HS256,typ即 Token 的类型。

2. Payload

负载 Payload 是一个包含传递数据的 JSON 对象,同样经过了 Base64Url 编码,包含以下可选属性:

iss:发行人
sub:主题
aud:受众群体
exp:到期时间
nbf:生效时间
iat:签发时间
jti:JWT ID

详情请参考 Registered Claim Names。

Payload 中的属性也可以自行添加,但由于 JWT 的内容对任何人都可见,除非对 JWT 进行二次加密,否则不能将任何机密的数据写入其中。

3. Signature

Signature 签名操作是在获取到了 Header 和 Payload 后进行的,比如 Header 中指定的是 HS256 算法,那么会通过以下方式创建 Signature:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

其中的secret为保存在服务端的密钥,一般需要定期更新。完成签名后就将这三部分拼接在一起返回给客户端:

JWT = `${Header}.${Payload}.${Signature}`;

NodeJS 中实现 JWT

JWT 在各种语言中都有实现,如 java-jwt、angular2-jwt、go-jwt-middleware 等,更多的实现可在 auth0-docs 中查看,此处以 NodeJS 中的实现 jsonwebtoken 为例进行用户的认证。

先使用 express-generator 创建项目,安装需要的依赖:

npm install mongoose jsonwebtoken --save

连接 MongoDB 后添加 users 集合的数据库模型:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const userSchema = new Schema({
    "username": { type: String, required: true },
    "password": { type: String, required: true },
});

module.exports = mongoose.model("User",userSchema, "users");

生成 JWT

为了更好地复用,完成一个公共的生成 JWT 方法:

const jwt = require('jsonwebtoken');
const secret = "zander";

function createJWT(username, sub, exp, strTimer) {
  const jwt = jwt.sign({
    user: username, // 用户名
    sub: sub // 主题
  }, secret, {
    expiresIn: `${exp}${strTimer}` // 过期时间
  })
  return jwt;
}

注册接口

router.post('/register', async (req, res) => {
  const { username, password } = req.body;
  const userData = { username, password };

  const saveData = await new User(userData).save();
  const jwt = createJWT(username, 'register', 1, 'h');
  
  res.json({
    status: 200,
    data: saveData,
    token: jwt
  })
})

postman测试
在这里插入图片描述
登陆接口

router.post('/login', async (req, res) => {
  const { username, password } = req.body;
  
  const userData = await User.findOne({ username, password });
  if (!userData) {
    return res.json({
      status: 501,
      msg: '登录信息有误'
    })
  }
  const jwt = createJWT(username, 'login', 5, 'd');
  res.json({
    status: 200,
    data: userData,
    token: jwt
  })
})

在这里插入图片描述

验证 JWT

服务端生成了 JWT 后不保存,直接发送给客户端,而客户端拿到了 JWT 后将其保存下来,在发送其它请求时需要将 JWT 加入到请求头中:

Authorization: Bearer <token>

然后服务端验证 JWT 是否合法且有效:

// 验证token方法
function verifyJWT(token) {
  let decoded;
  try {
    decoded = jwt.verify(token.split(" ")[1], secret);
  } catch (err) {
    return err.message;
  }
  return decoded;
}

// 根据用户名获取密码接口
router.get('/password', async (req, res) => {
  const token = req.headers['authorization'];
  const { username } = req.query;
  
  if (!token) {
    return res.json({
      status: 501,
      msg: 'Not authorized'
    });
  }
  const info = verifyJWT(token);
  if(typeof info === "string"){
    return res.json({
      status: 501,
      msg: info
    });
  }
  const userData = await User.findOne({ username });
  res.json({
    status: 200,
    data: userData.password
  })
})

非法请求
非法的请求
正确的请求
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值