一步一步搭建react应用-使用 jwt + redis 来做基于token的用户身份认证

[一步一步构建一个react应用-开篇](https://segmentfault.com/a/11...

git地址

  • 基于token的认证流程

  1. 客户端用户登录请求
  2. 服务端验证用户名密码
  3. 验证成功服务端生成一个token,响应给客户端
  4. 客户端之后的每次请求header中都带上这个token
  5. 服务端对需要认证的接口要验证token,验证成功接收请求

这里我们采用jsonwebtoken生成token,

jwt.sign(payload,secretorPrivateKey,[options,callback])

使用express-jwt验证token(验证成功会把token信息放在request.user中)

express_jwt({
        secret: SECRET,getToken: (req)=> {
        if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
            return req.headers.authorization.split(' ')[1];
        } else if (req.query && req.query.token) {
            return req.query.token;
        }
        return null;
    }
    }
  • 为什么使用redis

采用jsonwebtoken生成token时可以指定token的有效期,并且jsonwebtoken的verify方法也提供了选项来更新token的有效期,但这里使用了express_jwt中间件,express_jwt不提供方法来刷新token

思路:

  1. 客户端请求登录成功,生成token
  2. 将此token保存在redis中,设置redis的有效期(例如1h)
  3. 新的请求过来,先express_jwt验证token,验证成功, 再验证token是否在redis中存在,存在说明有效
  4. 有效期内客户端新的请求过来,提取token,更新此token在redis中的有效期
  5. 客户端退出登录请求,删除redis中此token
const express_jwt = require('express-jwt')
const redis = require('./redis')
const jwt = require('jsonwebtoken')
const unless = require('express-unless')
const SECRET = 'MOVIESKEY'

const token = {

    SECRET,sign: (user) => {
        return jwt.sign(user,SECRET)
    },getToken: function fromHeaderOrQuerystring(req) {
        if (req.headers.authorization && req.headers.authorization.split(' ')[0] === 'Bearer') {
            return req.headers.authorization.split(' ')[1];
        } else if (req.query && req.query.token) {
            return req.query.token;
        }
        return null;
    },validToken: express_jwt({
        secret: SECRET,getToken: this.getToken
    }),noAuthorization: (err,req,res,next) => {
        if (err.status == 401) {
            res.json(err)
            return
        }
        next()
    },//token在redis中存在,更新有效期,不存在说明已退出登录
    checkRedis: (req,next) => {
        const tok = token.getToken(req)
        redis.get(tok,(data) => {
            if (data) {
                // token 在redis中存在,延长过期时间
                redis.updateExpire(tok)
                next()
            } else {
                next(10005)
            }
        })
    },add:(tok)=>{
        redis.add(tok)
    },remove: (req) => {
        const tok = token.getToken(req)
        tok && redis.remove(tok)
    }
}
token.checkRedis.unless = unless

module.exports = token
  • 使用

routes/movies.js

const unlesspath = {
  path: [
    { url: '/api/movies',methods: ['GET'] },{ url: '/api/movies/search/by',{ url: /movies\/[^\/]+$/,]
}

if (process.env.NODE_ENV != 'test') {
  router.use(
    token.validToken.unless(unlesspath),token.noAuthorization,token.checkRedis.unless(unlesspath)
  )
}

router.get('/',(req,next)=>{})
router.post('/',next)=>{})
router.put('/:movieId',next)=>{})

相关文章

一、前言 在组件方面react和Vue一样的,核心思想玩的就是组件...
前言: 前段时间学习完react后,刚好就接到公司一个react项目...
前言: 最近收到组长通知我们项目组后面新开的项目准备统一技...
react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom...