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);
};
请注意,在这个示例中,用户数据是写死在代码中的,在生产环境中,您应该将用户数据存储在数据库中以便更好地管理。