3

jwt实现token鉴权(nodejs koa)

 2 years ago
source link: https://segmentfault.com/a/1190000040633809
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

为什么需要token?

在后台管理系统中,我们通常使用cookie-session的方式用于鉴权,如何通过cookie、session鉴权(nodejs/koa) 但这种方式存在着以下问题

  1. 比如cookie的容量太小
  2. 浏览器端和app端发送http请求时携带cookie会有差异
  3. 分布式系统和服务器集群保证如何保证sessionId是相同

基于以上问题,有了token这种方式,token的鉴权不受浏览器或app端的限制,通用性安全性都更强。

数据格式实现token的鉴权方式通常使用jwt,即json web token,jwt的格式如 xxx.yyy.zzz

  • xxx的部分用来描述使用什么样的加密方式
  • yyy的部分是携带的数据,比如id,name,通常还会携带 iat(issue at)发布时间, exp(expiration time)过期时间,用于鉴权的时候判断此token是否在有效期内,以上xxx和yyy都是对json数据以base64编码的方式进行转换
  • zzz是对xxx.yyy再加上密钥进行加密,加密的方式在header中。

比如上图中,服务器生成token使用的加密方式是 HS256,需保存的内容为 id 和 name,密钥为123456

  • header 部分

    {"alg":"HS256","typ":"JWT"}
    // base64编码结果:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
  • playload部分

    {"id":1,"name":"Alice","iat":1630814528619,"exp":1630816048023}
    // base64编码结果:eyJpZCI6MSwibmFtZSI6IkFsaWNlIiwiaWF0IjoxNjMwODE0NTI4NjE5LCJleHAiOjE2MzA4MTYwNDgwMjN9
  • signature部分

    // 加密结果为:B2df_qYbivZcjpJ_QtIyRu4ts6n_pwxlSQl41Bpsxz8

最后的结果就是把三部分拼接起来,以 . 分隔

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwibmFtZSI6IkFsaWNlIiwiaWF0IjoxNjMwODE0NTI4NjE5LCJleHAiOjE2MzA4MTYwNDgwMjN9.B2df_qYbivZcjpJ_QtIyRu4ts6n_pwxlSQl41Bpsxz8

可以看到jwt的header和payload都是用base64进行编码的,也可解码,所以并不能存放重要信息,而jwt数据的传递也不是为了加密重要信息,jwt的singature部分是需要通过密钥来加密的,只要密钥不泄露,身份就不容易被伪造。

jwt可以用于客户端向服务器发送的请求的时候携带,放置到 header中,使用 authorization 这个字段,使用 Bearer的方式

公钥和私钥

  • 对称加密算法,只用一个密钥加密和解密
  • 非对称加密算法,公钥用于加密,私钥用于解密
    openssl中可以生成公钥和私钥
// 生成公钥
genrsa -out private.key 2048
// 生成私钥
rsa -in private.key -puout -out public.key 

分别生成 public.key 和 private.key 文件

服务器如何鉴权

用户登录成功后,服务器返回token,以Koa来做个演示

const jwt = require("jsonwebtoken")
const PRIVATE_KEY = fs.readFileSync('./private.key')

const user = { id: 1, name: 'kiki'}
const token = jwt.sign(user, PRIVATE_KEY, {
    expiresIn: 10, // 单位s
    algorithm: "RS256"
})

客户端将在header中的authorization携带token数据,服务器校验token的有效性和正确性

const PUBLIC_KEY = fs.readFileSync('./public.key')

const authorization = ctx.headers.authorization
const token = authorization.replace("Bearer ", "")

// 如果失败会直接报错, 所以需要捕获
try {
    const result = jwt.verify(token, PUBLIC_KEY, {
        algorithms: ["RS256"]
    })
    // 拿到的信息是 { id: 1, name: 'kiki', iat: '', exp: ''}
} catch(error){
    
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK