且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Nodejs fastify 登录校验

更新时间:2022-08-13 10:37:26

在之前的文章过详细讲解了 在前端开发中如何在 React 中进行登录校验,下面我们来继续讲解在 Nodejs 后台开发 fastify 中如何进行登录校验。

在使用 fastify 开发后台接口的时候,很多时候,我们的接口是需要进行登录校验的,某些接口,如果没有登录则不允许访问,那如何在 fastify 中进行登录校验呢?

进行登录校验有一种最简单但同时也是最笨的方法就是,将校验函数封装为一个单独的函数,然后在每一个需要进行校验的地方都调用一次这个函数就行了。之所以说这个函数是最笨的方法就是因为需要自己每次都要手动调用校验函数。那有没有配置好了后,不需要自己手动调用的方法呢?答案是有的,那就是通过 fastify-plugin 插件来完成。

const fp = require('fastify-plugin');

function auth(fastify, opts, done) {
  fastify.addHook('onRequest', onRequest);

  done();

  function onRequest(req, reply, reqDone) {
    // 进行登录校验
  }
}

module.exports = fp(auth, { fastify: '3.x', name: 'fastify-auth' });

如果校验标记是通过 GET 传递的,则可以在 onRequest 中完成,如果是通过 POST 传递的,则需要在 preValidation 完成,详情参考:fastify钩子函数

接下来来看看完整的示例代码(token通过 GET 传递):

const fp = require('fastify-plugin');

function auth(fastify, opts, done) {
  if (typeof opts.verify !== 'function') {
    opts.verify = () => {
      return true;
    };
  }
  opts.ignore = opts.ignore || [];
  // 保存 token 对应的登录后的信息包含 open_id 和 access_token
  fastify.decorateRequest('loginUser', null);

  fastify.addHook('onRequest', onRequest);

  done();

  function onRequest(req, reply, reqDone) {
    // 这里可以进行忽略验证的 url,以便于在某些 url 中不进行校验
    let url = new URL(`http://${req.headers.host}${req.url}`);
    if (opts.ignore.includes(url.pathname)) {
      reqDone();
      return;
    }
    // 进行登录校验
    let token = req.query.token;
    if (token == null) {
      const err = new Error('Unauthorized');
      err.statusCode = 401;
      reqDone(err);
    } else {
      // 将校验函数弄为配置式
      let loginUser = opts.verify(token);
      if (loginUser === false) {
        const err = new Error('Unauthorized');
        err.statusCode = 401;
        token = null;
        reqDone(err);
      } else {
        // req.loginUser = { ...loginUser };
        loginUser = null;
        token = null;
        reqDone();
      }
    }
  }
}

module.exports = fp(auth, { fastify: '3.x', name: 'fastify-auth' });

然后在 app.js 也就是定义 fastify 启动的文件中的路由配置添加插件使用:

// 注册路由
app.register(
  async (Server) => {
    // 加入登录验证
    Server.register(require('./plugins/authorization'), {
      verify(token) {
        return tokenPools.has(token);
      }, // 校验函数
      ignore: ['/', '/api/login', '/api/shop_detail'], // 添加不进行接口校验的url地址
    });
    Server.register(require('./routes/root'));
    Server.register(require('./routes/api'), { prefix: '/api' });
  },
  { prefix: '/' },
);

在这里配置的校验会校验所有的函数,我们可以通过 fastify 上下文原理 来重新配置来避免某些校验。

// 注册路由
app.register(
  async (Server) => {
    // 加入登录验证
    Server.register(require('./plugins/authorization'), {
      verify(token) {
        return tokenPools.has(token);
      }, // 校验函数
      ignore: ['/', '/api/login', '/api/shop_detail'], // 添加不进行接口校验的url地址
    });
    Server.register(
      async (ChildServer) => {
        // 加入登录验证
        Server.register(require('./plugins/authorization'), {
          verify(token) {
            return tokenUtils.get(token);
          },
          ignore: [
            '/api/login'
          ],
        });
        ChildServer.register(require('./routes/api'));
      },
      { prefix: '/api' },
    );
    Server.register(require('./routes/root'));
  },
  { prefix: '/' },
);

通过这样配置凡是 routes/root 里面定义的路由接口则不会进行验证,而只有 routes/api 里面定义的路由才会进行验证。

其实我们如果将配置的 ignore 验证的地方改为正则匹配然后再加上上面的配置,就可以很多复杂的方式了。

fastifykoaExpressEggjs 一样的 Node.js Web 应用程序框架。