玩转Express(二)登录态&中间件

简介: 玩转Express(二)登录态&中间件

前言

上一节咱们实现了一个登录接口,但仅仅是“登录”而已。登录完成之后,服务器应该保存好登录态,以认识下一个访问的“人”。那么本节就以主流的保存登录态方案为例,给咱们的登录接口加上登录态。同时,中间件是 Express 中一个十分重要的概念,咱们今天也来一起盘一盘它。

登录态

首先 http 是无状态的,它无法识别用户。但就现在的网站而言,大部分接口都需要知道当前操作的用户是谁,每次发送接口都需要区分出每个人。所以登录态就是用来区分用户的,让服务器知道这次请求会话是谁发送的,谁需要处理的。

本文将讲述两种保存登录态的方式一是服务端有状态,一是服务端无状态。

服务端有状态

当登录成功后,服务器会根据当前登录的用户生成一个 id ,并把它分别保留在客户端的 cookie 以及服务端中。则客户端每次请求的时候都会带上这个 id ,其实服务端就可以拿这个 id 来做对比,从而知道当前请求的用户是谁。服务端的状态存储可以利用 session ,也可以利用别的方式,我们本着折腾的心态,用一个单例的缓存来存储状态。

Cache类实现

我们现在自己简单实现一个缓存的类,这个类暂定有以下功能:

  • 键值对形式存储
  • 支持过期时间

好的,现在我们已经列出来了这些功能。接下来慢慢实现即可。现在根目录下新建一个 cache.js 文件。具体代码如下:

class Cache {
    constructor(maxAge = 1000 * 60 * 30) {
        this.maxAge = maxAge
        //保存缓存的object
        this.cache = {}
        //过期时间object
        this.ttl = {}
    }
    getCache(key) {
        let ttl = this.ttl[key]
        if ((+new Date()) - ttl >= this.maxAge) {
            //过期了则删除
            this.deleteCache(key)
            return undefined
        } else {
            return this.cache[key]
        }
    }
    setCache(key, value) {
        this.cache[key] = value
        this.ttl[key] = +new Date()
    }
    deleteCache(key) {
        delete this.cache[key]
        delete this.ttl[key]
    }
}

module.exports = Cache

app.js中引入使用如下:

const Cache = require('./cache')
global.cache = new Cache()

登录态保存

那么我们就可以愉快的将用户信息存储在服务端了,改造登录接口如下

res.cookie('n_session_id', md5(account), {
    httpOnly: true,//客户端不可修改cookie
    maxAge: 1000 * 60 * 30
})
cache.setCache(md5(account), account)

接下来咱们加上一个接口,验证一下登录态:

router.get('/getList', (req, res) => {
  let account = req.cookies.n_session_id
  let serverAccount = cache.getCache(account)
  if (!account || !serverAccount) {
    res.json('请先登录')
  } else {
    let mock = [{
      id: 1,
      name: 'abc'
    }, {
      id: 2,
      name: 'efg'
    }]
    res.json(mock)
  }
})

服务端无状态

上述服务器有状态的方法有一个明显的缺点,当系统变大服务器数量变多时,有可能用户当前访问的服务器并不是用户之前保存登录态的服务器,当然也可以用 Redis 或其他方案来解决这个问题。下面我们用一种名为 JWT 的方案,让登录态完全保存在客户端。具体 JWT 的讲解可参考文章什么是 JWT -- JSON WEB TOKEN

接入JWT

首先先安装 jsonwebtoken

npm install jsonwebtoken

再简单封装一个加密算法,如下:

const jwt = require('jsonwebtoken');
const Token = {
  //data为加密数据
  encrypt:function(data){
    return jwt.sign(data, 'token')
  },
  decrypt:function(token){
    try {
      let data = jwt.verify(token, 'token');
      return {
        token:true,
        id:data.id
      };
    } catch (e) {
      return {
        token:false,
        data:e
      }
    }
  }
}

接下来就可以在路由中愉快的使用了。 token 的客户端存储一般有两种,一种存放在 cookie 中,另一种 json 返回 token 后,客户端每一次请求都把 token 放在请求头里。这里采用第一种,改造登录请求如下

const token = Token.encrypt({
    user: account
})
res.cookie('token', token, {
    httpOnly: true,
    maxAge: 1000 * 60 * 30
})

验证 token 时如下操作即可:

//解密
let data = Token.decrypt(req.cookies.token);
if (data.token) {
    //有效token
}else{
    //无效token
}

中间件

从本质上说,一个 Express 应用是在调用各种中间件。中间件( middleware )是一个函数,他可以访问请求对象( request object(req) ),响应对象( response object(res) )和 web 应用中处于请求-响应循环

Express中有如下几种中间件

  • 应用级中间件
  • 路由级中间件
  • 错误处理中间件
  • 内置中间件
  • 第三方中间件

一个请求发送到服务器后,它的生命周期是先收到 request(请求),然后服务端处理,处理完了以后发送 response(响应)回去而这个服务端处理的过护,需要把处理的事情分一下,分配成几个部分来做。简单实例可以看笔者的一篇博文Express中间件,这里就不再赘述。


中间件鉴权

我们之前开发了登录的接口以及保存了登录态,也开发了一个测试的接口需要验证等登录态。而在一个系统中,需要验证登录态的接口肯定比不需要验证的多,而每一个接口都写一份验证登录态的逻辑未免太过冗余。所以用中间件来统一处理。

根目录新建一个 middleware 文件夹,新建一个 login.js 文件。

  • 新建一个可以绕过登录态的数组,匹配到里面的元素则直接跳过
  • 获取登录态,若无则跳登录,若有则把 account 加入 req 对象中,下面的路由就可以直接 req.account 拿到用户的信息 -中间件的 use 顺序十分重要
const whileList = ['/users/login'];

function login(req, res, next) {
    let account = req.cookies.n_session_id
    let serverAccount = cache.getCache(account)
    let url = req.url
    if (whileList.includes(url)) {
        next()
    } else {
        if (!account || !serverAccount) {
            res.json('请先登录')
        } else {
            req.account = serverAccount
            next()
        }
    }
}

module.exports = login

然后在 app.js 中引入使用:

const loginMiddleware = require('./middleware/login')
app.use(loginMiddleware)

app.use('/', indexRouter)
app.use('/users', usersRouter)

像我们之前封装的 ORM 类和 Cache 类也可以同样利用中间件的方式放入 req 参数中,这里就不再做多赘述。

相关文章
|
JSON 前端开发 中间件
axios基本使用,express中间件
axios基本使用,express中间件
|
21天前
|
Web App开发 JSON JavaScript
Node.js 中的中间件机制与 Express 应用
Node.js 中的中间件机制与 Express 应用
|
4月前
|
JavaScript 安全 Linux
【Azure 应用服务】NodeJS Express + MSAL 应用实现AAD登录并获取AccessToken -- cca.acquireTokenByCode(tokenRequest)
【Azure 应用服务】NodeJS Express + MSAL 应用实现AAD登录并获取AccessToken -- cca.acquireTokenByCode(tokenRequest)
|
4月前
|
JavaScript Linux API
【Azure 应用服务】NodeJS Express + MSAL 应用实现AAD集成登录并部署在App Service Linux环境中的实现步骤
【Azure 应用服务】NodeJS Express + MSAL 应用实现AAD集成登录并部署在App Service Linux环境中的实现步骤
|
6月前
|
JSON 中间件 API
中间件API示例(以Express.js为例)
【6月更文挑战第14天】
50 8
|
7月前
|
JavaScript 中间件 API
中间件应用Express.js(Node.js)
【5月更文挑战第3天】我们定义了一个名为 `logger` 的中间件函数。它接受请求对象、响应对象以及下一个中间件函数作为参数。当接收到请求时,它会打印出请求的 HTTP 方法和 URL,然后调用 `next()` 函数来将控制权传递给下一个中间件或路由处理器。我们使用 `app.use()` 方法将 `logger` 中间件添加到了应用级别的中间件堆栈中,这意味着它将对所有请求生效。
50 3
中间件应用Express.js(Node.js)
|
中间件
93 # 实现 express 错误处理中间件
93 # 实现 express 错误处理中间件
62 0
|
7月前
|
开发框架 JavaScript 中间件
深入探索Node.js的Express框架:使用与中间件详解
【4月更文挑战第30天】本文深入探讨了Node.js的Express框架,介绍了其作为Web开发的强大工具,主要聚焦于基本使用和中间件。Express是基于Node.js的Web应用框架,用于构建高效的应用和API。文章详细讲解了如何安装Express,创建简单应用,以及中间件的工作原理和应用,包括中间件的顺序、错误处理和挂载位置。此外,还提到了使用第三方中间件扩展功能。理解Express基础和中间件对于开发高质量Web应用至关重要。
|
7月前
|
Web App开发 JavaScript 前端开发
Express 框架的特点、使用方法以及相关的常用功能和中间件
Express 框架的特点、使用方法以及相关的常用功能和中间件
367 1
|
7月前
|
JavaScript 前端开发 中间件
Node.js—Express使用、Express 路由 、Express 中间件、托管静态资源、使用 Express 写接口、node.js链接sqlite数据库
Node.js—Express使用、Express 路由 、Express 中间件、托管静态资源、使用 Express 写接口、node.js链接sqlite数据库
243 0