我有一个使用 NestJS 和 MongoDB 构建的 API。该应用程序使用 Elastic Beanstalk 和 Render 部署到 AWS。我想使用 API 密钥保护我的 API,因此我创建了一个 api-key 和 api-host 字符串,客户端必须将其包含在请求标头中。我有一个中间件,它将检查请求标头中的 api-key="........" 和 api-host="........" ,如果找不到或没有找到它们不匹配,API 将抛出错误“ACCESS DENIED”。我在 Render 和 AWS 上正确设置了环境变量。在 Postman 和 Render 上,一切都运行良好。但是,AWS 应用程序抛出“访问被拒绝”错误。
import {Injectable, NestMiddleware, UnauthorizedException} from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class HeaderVerificationMiddleware implements NestMiddleware {
constructor(private configService: ConfigService) {}
async use(req: Request, res: Response, next: NextFunction) {
try {
const { api_key, api_host } = req.headers;
if (!(api_key && api_host)) {
throw new UnauthorizedException('ACCESS DENIED!');
}
if (
api_key === this.configService.get<string>('APP_API_KEY') &&
api_host === this.configService.get<string>('APP_API_HOST')
) {
next(); // Proceed with the request
} else {
throw new UnauthorizedException('ACCESS DENIED!!'); // Reject the request
}
} catch (error) {
throw new UnauthorizedException(error.message);
}
}
}
您的代码在根据环境变量验证
api_key
和 api_host
方面似乎是正确的。根据您提供的信息,让我们考虑以下事项:
标头区分大小写:HTTP 标头不区分大小写。您的代码假设标头始终为小写(
api_key
,api_host
)。情况可能并非如此,特别是如果它们是由客户设置的。您应该将标头规范化为不区分大小写。
const api_key = req.headers['api_key'] || req.headers['API_KEY'];
const api_host = req.headers['api_host'] || req.headers['API_HOST'];
环境变量:仔细检查环境变量
APP_API_KEY
和 APP_API_HOST
在 AWS Elastic Beanstalk 上是否设置正确。有时可能会有隐藏的字符或空格。
日志记录:添加日志记录语句以查看请求中出现的确切值以及预期值可能很有用。这可以让您了解可能出现问题的地方。
console.log('Received api_key:', api_key);
console.log('Expected api_key:', this.configService.get<string>('APP_API_KEY'));
console.log('Received api_host:', api_host);
console.log('Expected api_host:', this.configService.get<string>('APP_API_HOST'));
部署设置:确保 AWS Elastic Beanstalk 具有读取环境变量的必要权限。有时某些权限或策略可能会阻止应用程序访问它们。
缓存:确保没有缓存机制可能会因先前失败的请求而出现“访问被拒绝”错误。
环境内的差异:与 Render 或本地环境相比,AWS Elastic Beanstalk 处理标头的方式可能略有不同。
客户端注意事项:确保向 AWS 部署的应用程序发出请求的客户端确实发送了正确的标头。有时,客户端上可能存在网络策略、代理或其他基础设施部分,这些部分可能会剥离或修改标头。
替代方法:作为附加的安全层,请考虑定期轮换 API 密钥,并在可行的情况下使用更复杂的身份验证机制,例如 JWT 或 OAuth。
反向代理配置:如果您将反向代理与 Elastic Beanstalk(例如 Nginx)一起使用,请确保它不会在标头到达您的应用程序之前剥离或更改标头。
最后,作为快速健全性检查,请尝试暂时对预期的
api_key
和 api_host
进行硬编码,看看它是否有效。这将排除 ConfigService
或环境变量的任何问题。
if (
api_key === 'your_hardcoded_api_key' &&
api_host === 'your_hardcoded_api_host'
) {
next();
} else {
throw new UnauthorizedException('ACCESS DENIED!!');
}