一步一步搭建react應用-使用 jwt + redis 來作基於token的用戶身份認證

[一步一步構建一個react應用-開篇](https://segmentfault.com/a/11...node

git地址react

  • 基於token的認證流程

  1. 客戶端用戶發登陸請求
  2. 服務端驗證用戶名密碼
  3. 驗證成功服務端生成一個token,響應給客戶端
  4. 客戶端以後的每次請求header中都帶上這個token
  5. 服務端對須要認證的接口要驗證token,驗證成功接收請求

這裏咱們採用jsonwebtoken來生成token,git

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

使用express-jwt驗證token(驗證成功會把token信息放在request.user中)github

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不提供方法來刷新tokenweb

思路:redis

  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, res, 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.jsexpress

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

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

router.get('/',(req,res,next)=>{})
router.post('/',(req,res,next)=>{})
router.put('/:movieId',(req,res,next)=>{})
相關文章
相關標籤/搜索