Node JS通过jwt设置token

发布时间 2023-09-01 16:52:27作者: RicardoX3

token(身份令牌),其实就是用加密算法加密少量用户信息,以及记录创建时间与其他少量配置项,聚合而成的一个字符串。

如果你的服务端只有登陆时需要验证,之后都处于无信任状态——譬如用户权限、路由等信息都存储在客户端缓存内,那token就没必要了;

如果需要进行验证,那token就能很好的完成这个任务了。

 

token需要每次请求都要发送,因此考虑将其生成后,放置在请求拦截器中

const Axios = axios.create({
    baseURL: baseUrl,// 后台服务地址,这里是开发所以改为本机,后面发布后要改地址为8.188
    timeout: 15000,               // 请求超时时间1分钟
    responseType: "json",
    withCredentials: false,    // 是否允许带cookie这些
});

Axios.interceptors.request.use(config => {
    const token = JSON.parse(sessionStorage.getItem("token"))
    // 若是没有token以及设置了跳过token——登录——则不设置
    if (token?.token && !config.headers?.skipToken) {
        config.headers['Authorization'] = `Bearer ${token.token}`
    }
    return config
}, (error => {
    console.log(error)
    // 错误请求的处理
    return Promise.reject(error)
}))

登陆时因为没有token,所以跳过这一步。之后有的,就在请求头中的属性“Authorization”中设置,这是约定俗成的token字段;

Bearer:这是翻译当前token采用的类型,但一般后端服务器也是协商好的用同种类型,所以这里是可以省略该部分,直接加上服务器传递过来的token字符串

 

后端部分,需要注意的是,若是提示“Authorization”或者“skiptoken”存在跨域问题,无法访问后端接口的话,请在后端加上这部分

//nodejs
let express = require('express')
let app = express()

//添加中间件,自动解析请求内容
app.all('*', function (req, res, next) {
    res.header('Access-Control-Allow-Origin', '*')
    res.header('Access-Control-Allow-Headers', 'content-type,Authorization,skipToken')
    res.header('Access-Control-Allow-Methods', 'DELETE,PUT,POST,GET,OPTIONS')
    if (req.method.toLowerCase() === 'options') res.sendStatus(200)
    else next()
})

这是nodejs的解决跨域方式,其他语言请自行查找。

 

生成token部分:

const jwt = require('jsonwebtoken')
const secret = 'RicardoX3' //自定义密钥
const token = jwt.sign({username: req.body.userName, password: req.body.UserPwd}, secret, {expiresIn: 3600 * 24}) //过期时间为24小时,基础时间为秒

 

接着继续添加中间件进行拦截,注意,请确保这些都在所有请求接口上面,因为nodejs是从上往下去对照的

app.use(function (req, res, next) {
    if (!req.headers.skiptoken) {
        const token = jwt.decode(req.headers?.authorization.slice(7))
        //超过24小时则发送令牌过期信息
        if (new Date().getTime() - token.exp * 1000 > 0 || token.iat * 1000 - new Date().getTime() > 0) {
            res.sendStatus(424)
        } else next()
    } else next()
})

 

需要注意的是,jwt的时间戳是以秒为单位的,所以要计算的时候记得带上1000转换为毫秒。

jwt.sign第一个部分为你要加密的部分,第二个为加密密钥,第三个为自定义配置项;官网给的解码是分为三部分(当然密文也是3部分,xxxx.yyyy.zzzz);

第一部分是加密算法,这部分默认的;

第二部分是加密的内容,这部分解码后会自带token创建时间——即使你没在配置里加上这个——以及自定义配置项内的部分标签(譬如过期时间);

第三部分为加密密钥。

但从给的sign()方法看来,其官网演示的参数似乎不是很明确?譬如文档里就没有"expiresIn"这个参数,但是你必须得在sign里放在第三个参数内才生效,解码时会变成exp,就挺奇怪的……

如果你自己写了个加密算法的话,那也可以不用jwt;

后端在调用登录接口时顺带将生成的token发送给前端,让其存储在缓存中即可。