用egg.js来写一个api管理系统(一)

Egg.js是一个基于Node.js的企业级开发框架,非常适合构建API服务。

安装egg.js

首先,您需要安装Node.js和npm(Node Package Manager)。然后,您可以通过运行以下命令来安装Egg.js:

npm i egg --save

然后,您可以使用以下命令创建一个新的Egg.js项目:

npx egg-init <project-name>

接下来,您可以通过修改config/config.default.js文件来配置您的应用程序。

最后,您可以在您的Egg.js项目中编写控制器和路由,以实现您的API管理系统。

给系统加一个token验证

您可以使用JWT(JSON Web Token)来为您的API管理系统添加令牌验证。

首先,您可以在您的Egg.js项目中安装jsonwebtoken库:

npm install jsonwebtoken --save

然后,您可以在您的控制器中编写代码来生成和验证JWT令牌:

const jwt = require('jsonwebtoken');

// 生成JWT令牌
const token = jwt.sign({ data: 'foobar' }, 'secret', { expiresIn: '1h' });

// 验证JWT令牌
jwt.verify(token, 'secret', (err, decoded) => {
  if (err) {
    console.error(err);
  } else {
    console.log(decoded);
  }
});

您可以在请求头中包含JWT令牌,并在您的路由中检查令牌是否有效。如果令牌无效,则可以向用户返回401错误代码。

此外,您还可以使用Egg.js中间件来自动验证令牌,以简化代码:

// 创建令牌验证中间件
const jwtMiddleware = (req, res, next) => {
  const token = req.headers.authorization;
  if (!token) {
    return res.status(401).send({ error: '令牌丢失' });
  }
  try {
    const decoded = jwt.verify(token, 'secret');
    req.user = decoded;
    next();
  } catch (err) {
    return res.status(401).send({ error: '令牌无效' });
  }
};

// 应用令牌验证中间件
app.use(jwtMiddleware);

请注意,以上代码仅作为示例,请不要在生产环境中使用硬编码的密钥。请使用随机生成的密钥或通过其他方式(如环境变量)安全存储密钥。

除此之外,您可以使用其他方法,如比对令牌中的用户ID与数据库中的用户记录,来进一步验证令牌的有效性。

您还可以使用Egg.js的插件机制,来简化令牌验证的流程。例如,您可以安装egg-jwt插件,它提供了一个简单的方法来处理JWT令牌验证。

最后,请注意,令牌验证是安全的关键组成部分,请确保您的代码遵循最佳安全实践,以防止令牌被滥用或窃取。

使用OAuth2.0进行令牌验证

以下是一个简单的示例,展示了如何使用Egg.js和OAuth2.0进行令牌验证:

npm install egg-oauth2-server

在config.default.js文件中,配置OAuth2.0服务器:

exports.oauth2server = {
  grantType: ['password', 'refresh_token'],
};

创建一个中间件,用于检查请求中是否包含令牌,并验证令牌的有效性:

// app/middleware/oauth.js
const OAuth = require('egg-oauth2-server');

module.exports = (options, app) => {
  const oauth = new OAuth(options, app);
  return async function oauthMiddleware(ctx, next) {
    try {
      await oauth.authenticate();
      await next();
    } catch (err) {
      ctx.status = 401;
      ctx.body = {
        error: err.message,
      };
    }
  };
};

在所有需要认证的路由上使用该中间件:

// app/router.js
module.exports = app => {
  const { router, controller } = app;
  const oauthMiddleware = app.middleware.oauth();

  router.get('/api/user', oauthMiddleware, controller.user.info);
};

这是一个简单的实现,您可以根据您的需求进行调整。如果您想了解更多关于OAuth2.0的信息,请参阅OAuth2.0规范。

使用JWT进行令牌验证

使用JWT进行令牌验证的具体代码也可能因您所使用的实现而异。然而,以下是一个简单的示例,展示了如何使用Egg.js和JWT进行令牌验证:

npm install jsonwebtoken

创建一个秘密,用于加密和解密令牌:

// app/config/config.default.js
exports.jwt = {
  secret: 'your_secret_key',
};

创建一个中间件,用于检查请求中是否包含令牌,并验证令牌的有效性:

// app/middleware/authentication.js
const jwt = require('jsonwebtoken');

module.exports = (options, app) => {
  return async function authenticationMiddleware(ctx, next) {
    const token = ctx.header.authorization;
    if (!token) {
      ctx.status = 401;
      ctx.body = {
        error: 'No token provided in request headers',
      };
      return;
    }

    try {
      const decoded = jwt.verify(token, app.config.jwt.secret);
      ctx.state.user = decoded;
      await next();
    } catch (err) {
      ctx.status = 401;
      ctx.body = {
        error: 'Invalid token',
      };
    }
  };
};

在所有需要认证的路由上使用该中间件:

// app/router.js
module.exports = app => {
  const { router, controller } = app;
  const authenticationMiddleware = app.middleware.authentication();

  router.get('/api/user', authenticationMiddleware, controller.user.info);
};

给每个用户一个唯一的API密钥

// app/middleware/authenticate.js
module.exports = () => {
  return async function authenticate(ctx, next) {
    const apiKey = ctx.header.apikey;

    // 在数据库中查找用户
    const user = await ctx.model.User.findOne({ apiKey });
    if (!user) {
      ctx.status = 401;
      ctx.body = { message: 'Unauthorized' };
      return;
    }

    // 将用户信息存储在上下文中,以便在其他地方使用
    ctx.state.user = user;
    await next();
  };
};

// app/router.js
module.exports = app => {
  const { router, middleware } = app;
  const authenticate = middleware.authenticate();

  router.get('/api/v1/resources', authenticate, ctx => {
    // 访问 API 资源
  });
};

这个代码示例使用一个中间件函数来验证请求中的API密钥。如果密钥是有效的,则该中间件函数将用户信息存储在上下文中,并将控制传递给下一个中间件函数或路由处理程序。如果密钥是无效的,则中间件函数将返回401 Unauthorized响应。

限制用户的访问次数

您可以通过记录并限制每个用户的API请求数来限制用户的访问次数。

可以在存储用户数据的数据库中添加一个字段,用于记录每个用户在特定时间段内对API的访问次数。每当用户对API进行请求时,您可以将其请求数加1。如果用户的请求数超过了限制,则拒绝其请求并向其返回适当的错误消息。

代码实现的示例如下:

// app/middleware/api_key_auth.js
const jwt = require('jsonwebtoken');
const { secret } = require('config').security;

module.exports = (options, app) => {
  return async function apiKeyAuth(ctx, next) {
    // 获取请求头中的 API Key
    const apiKey = ctx.headers['x-api-key'];

    // 验证 API Key 是否存在
    if (!apiKey) {
      ctx.status = 401;
      ctx.body = { error: 'Unauthorized' };
      return;
    }

    // 验证 API Key 是否正确
    try {
      const decoded = jwt.verify(apiKey, secret);
      const user = await app.models.User.findOne({ apiKey: decoded.apiKey });

      // 验证 API Key 对应的用户是否存在
      if (!user) {
        ctx.status = 401;
        ctx.body = { error: 'Unauthorized' };
        return;
      }

      // 验证用户访问次数是否超限
      if (user.requestCount >= user.requestLimit) {
        ctx.status = 429;
        ctx.body = { error: 'Too Many Requests' };
        return;
      }

      // 将用户的信息挂载到 ctx 上,方便在后续的处理中使用
      ctx.user = user;

      // 将用户的访问次数加 1
      await app.models.User.updateOne({ apiKey: decoded.apiKey }, { $inc: { requestCount: 1 } });

      // 继续执行后续的请求处理
      await next();
    } catch (err) {
      ctx.status = 401;
      ctx.body = { error: 'Unauthorized' };
    }
  };
};

// config/config.default.js
module.exports = {
  security: {
    secret: 'your secret'
  }
};

// app/router.js
module.exports = app => {
  const { router, controller } = app;

  router.get('/', controller.home.index);
  router.get('/secret', app.middleware.apiKeyAuth(), controller.home.secret);
};

请注意,在这个示例中,用户数据是写死在代码中的,在生产环境中,您应该将用户数据存储在数据库中以便更好地管理。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

袁代码

如果帮助了你,不妨也帮助我一下

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值