EC2上Node.js Express后端如何通过Cognito实现移动端用户认证访问控制
实现已认证用户访问EC2上Express接口的方案
这个问题问得好!既然你已经用Cognito搞定了客户端认证,那咱们可以在Express里加一个JWT验证中间件,实现类似Lambda IAM认证的效果——核心就是校验客户端传来的Cognito令牌合法性,只有通过校验的请求才能访问你的CRUD接口。下面是针对你的EC2架构的具体实现步骤:
核心思路
用户通过Cognito客户端SDK获取到ID Token(推荐用于身份校验)或Access Token(多用于API授权)后,在请求Express接口时将令牌放在Authorization请求头中(格式为Bearer <token>)。Express的自定义中间件会负责:
- 提取请求头中的令牌
- 验证令牌的签名、过期时间、受众(Audience)和颁发者(Issuer)
- 校验通过后,将解析后的用户信息挂载到请求对象上,放行到后续的CRUD接口;校验失败则返回401未授权。
具体实现步骤
1. 准备Cognito配置信息
先确认你的Cognito用户池和客户端配置正确,并且客户端能正常获取令牌。记录下以下信息(后续会用到):
- AWS区域(比如
us-east-1) - 用户池ID(格式类似
us-east-1_XXXXXXXXX) - 应用客户端ID(一串随机字符串)
2. 安装依赖包
在你的Express项目中,安装用于JWT解析和公钥获取的依赖:
npm install jsonwebtoken jwks-rsa
jsonwebtoken:负责解析和验证JWT令牌jwks-rsa:从Cognito的公钥端点获取用于验证签名的公钥(避免硬编码公钥,适配Cognito自动轮换密钥的机制)
3. 编写JWT验证中间件
创建一个中间件文件(比如middleware/authenticate.js),实现令牌校验逻辑:
const jwt = require('jsonwebtoken'); const jwksClient = require('jwks-rsa'); // 初始化JWKS客户端,指向Cognito的公钥端点 const client = jwksClient({ jwksUri: `https://cognito-idp.${process.env.AWS_REGION}.amazonaws.com/${process.env.COGNITO_USER_POOL_ID}/.well-known/jwks.json` }); // 根据令牌头中的kid获取对应的公钥 function getSigningKey(header, callback) { client.getSigningKey(header.kid, (err, key) => { const signingKey = key.publicKey || key.rsaPublicKey; callback(null, signingKey); }); } // 核心认证中间件 const authenticate = (req, res, next) => { // 从请求头提取令牌 const authHeader = req.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { return res.status(401).json({ message: '请提供有效的身份令牌' }); } const token = authHeader.split(' ')[1]; // 验证JWT的合法性 jwt.verify(token, getSigningKey, { audience: process.env.COGNITO_APP_CLIENT_ID, // 必须匹配你的Cognito客户端ID issuer: `https://cognito-idp.${process.env.AWS_REGION}.amazonaws.com/${process.env.COGNITO_USER_POOL_ID}`, // 必须匹配用户池的颁发者地址 algorithms: ['RS256'] // Cognito用RS256算法签名JWT }, (err, decodedToken) => { if (err) { return res.status(401).json({ message: '令牌无效或已过期' }); } // 将解析后的用户信息挂载到req对象,后续接口可直接使用 req.user = decodedToken; next(); }); }; module.exports = authenticate;
4. 在受保护的路由上使用中间件
把上面的中间件添加到需要保护的CRUD路由前,只有通过认证的请求才能访问这些接口:
const express = require('express'); const router = express.Router(); const authenticate = require('./middleware/authenticate'); // 假设你有一个操作RDS的控制器 const rdsController = require('./controllers/rdsController'); // 受保护的查询接口 router.get('/api/items', authenticate, rdsController.getItems); // 受保护的创建接口 router.post('/api/items', authenticate, rdsController.createItem); // 受保护的更新接口 router.put('/api/items/:id', authenticate, rdsController.updateItem); // 受保护的删除接口 router.delete('/api/items/:id', authenticate, rdsController.deleteItem); module.exports = router;
5. 配置环境变量
为了避免硬编码敏感信息,把Cognito相关配置放在环境变量中:
- 你可以在EC2实例上直接设置环境变量,或者用
dotenv包加载.env文件:
如果用AWS_REGION=us-east-1 COGNITO_USER_POOL_ID=us-east-1_XXXXXXXXX COGNITO_APP_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxxxxdotenv,记得在项目入口文件(比如app.js)顶部添加:require('dotenv').config();
6. 额外安全建议
- 强制HTTPS:确保你的Express后端只通过HTTPS提供服务,防止令牌在传输过程中被窃取
- 权限细化:可以通过Cognito令牌中的
cognito:groups字段实现角色权限控制(比如区分管理员和普通用户) - 令牌刷新:实现Cognito令牌的刷新机制,避免用户因令牌过期频繁重新登录
- 日志监控:添加认证失败的日志记录,方便排查身份验证相关问题
内容的提问来源于stack exchange,提问作者Steve Freed
相关产品推荐
相关产品推荐

