我已经建立了一个小的web应用程序,它使用了Cognito, Lambda和API Gateway,用户通过Cognito从UI进行身份验证。我还为我的ApiGateway端点设置了一个Cognito Authorizer,我从UI测试了它,我复制并粘贴我的令牌,它返回200。但是,当我的用户请求一个服务时,我需要识别他,所以我想解码并验证我在lambda的事件对象中获得的JSON web令牌,以获得有效负载和用户属性但是我现在需要验证和解码JSON web令牌,就像库https://github.com/awslabs/aws-jwt-verify的文档一样要访问事件对象,我使用aws-serverless-express/中间件库,如下所示:
app.use(awsServerlessExpressMiddleware.eventContext())
,现在可以访问像这样的事件对象
const event = req.apiGateway.event;
以下是我在lambda处理程序
中的代码const event = req.apiGateway.event;
const authToken = event.headers['Authorization'];
const verifier = CognitoJwtVerifier.create({
userPoolId: 'us-east-1_cDd9TR9a5',
tokenUse: "access",
clientId: '1irae6vkl1v4f8so6o09h787ev',
scope: "read"
});
try {
const payload = await verifier.verify(authToken);
console.log('Token is valid. Payload:', payload);
} catch (err) {
console.log(err);
console.log('Token not valid!');
}
但是我得到这个错误
JwtInvalidScopeError: Missing Scope。预期:读
我也试图删除像文档的第一个例子的属性范围,但我也得到另一个错误
CognitoJwtInvalidTokenUseError: Token使用不允许:id。预期:访问
使用以下代码:
在node js中为Cognito提供认证中间件
const AmazonCognitoIdentity = require("amazon-cognito-identity-js")
const { JwtRsaVerifier } = require("aws-jwt-verify")
const request = require("request")
const jwkToPem = require("jwk-to-pem")
const jwt = require("jsonwebtoken")
const poolData = {
UserPoolId: process.env.COGNITO_USER_POOL_ID,
ClientId: process.env.COGNITO_CLIENT_ID
}
const pool_region = process.env.AWS_REGION
const idTokenVerifier = JwtRsaVerifier.create({
issuer: `https://cognito-idp.${pool_region}.amazonaws.com/${poolData.UserPoolId}`,
jwksUri: `https://cognito-idp.${pool_region}.amazonaws.com/${poolData.UserPoolId}/.well-known/jwks.json`,
audience: process.env.COGNITO_CLIENT_ID
})
const renewToken = async (refreshToken, next, req, res) => {
const RefreshToken = new AmazonCognitoIdentity.CognitoRefreshToken({
RefreshToken: refreshToken
})
const userPool = new AmazonCognitoIdentity.CognitoUserPool(poolData)
const userData = {
Username: "",
Pool: userPool
}
const cognitoUser = new AmazonCognitoIdentity.CognitoUser(userData)
await cognitoUser.refreshSession(RefreshToken, async (err, session) => {
if (err) {
console.log(err)
res.status(401).send({
success: false,
message: err.message
})
return
} else {
const tokenObj = {
access_token: session.accessToken.jwtToken,
id_token: session.idToken.jwtToken,
refresh_token: session.refreshToken.token
}
const userPayload = await idTokenVerifier.verify(tokenObj.id_token)
req.user = userPayload
next()
}
})
}
const auth = async (req, res, next) => {
if (
req.headers.authorization &&
req.headers.authorization.split(" ")[0] === "Bearer"
) {
const token = req.headers.authorization.split(" ")[1]
const idToken = req.headers.authorization.split(" ")[2]
const refreshToken = req.headers.authorization.split(" ")[3]
try {
await new Promise((_, reject) => {
request(
{
url: `https://cognito-idp.${pool_region}.amazonaws.com/${poolData.UserPoolId}/.well-known/jwks.json`,
json: true
},
function (error, response, body) {
if (!error && response.statusCode === 200) {
var pems = {}
var keys = body["keys"]
for (var i = 0; i < keys.length; i++) {
//Convert each key to PEM
var key_id = keys[i].kid
var modulus = keys[i].n
var exponent = keys[i].e
var key_type = keys[i].kty
var jwk = { kty: key_type, n: modulus, e: exponent }
var pem = jwkToPem(jwk)
pems[key_id] = pem
}
//validate the token
var decodedJwt = jwt.decode(token, { complete: true })
if (!decodedJwt) {
reject({
success: false,
message: "Not a valid JWT token"
})
}
var kid = decodedJwt.header.kid
var pem = pems[kid]
if (!pem) {
reject({
success: false,
message: "Invalid token"
})
}
jwt.verify(token, pem, async (err, payload) => {
if (err) {
// console.log("Invalid Token or JWT Token expired")
if (err.message === "jwt expired") {
await renewToken(refreshToken, next, req, res)
} else {
reject({
success: false,
message: "Token Expired"
})
}
} else {
if (payload.username) {
const userPayload = await idTokenVerifier.verify(idToken)
req.user = userPayload
next()
} else {
reject({
success: false,
message: "Invalid token"
})
}
}
})
} else {
console.log("Error! Unable to get JWKs")
return {
success: false,
message: "Error! Unable to get JWKs"
}
}
}
)
})
} catch (err) {
console.log(err)
res.status(401).send({
success: false,
message: "Unauthorized"
})
}
} else {
res.status(401).send({
success: false,
message: "No token provided"
})
}
}
module.exports = auth
使用示例:
const express = require("express")
const router = express.Router()
// ** import middleware **
const auth = require("../middleware/auth")
// ** import controllers **
const user = require("../controller/user")
// ** user routes
router.get("/user/get-profile", [auth], user.getProfile)
我希望这将帮助你!
通过添加所需字段tokenUse: "id"到cognitojwtverify对象
https://github.com/awslabs/aws-jwt-verify cognitojwtverifier-verify-parameters
下面是来自github的示例。
import { CognitoJwtVerifier } from "aws-jwt-verify";
const verifier = CognitoJwtVerifier.create({
userPoolId: "<user_pool_id>", // mandatory, can't be overridden upon calling verify
tokenUse: "id", // needs to be specified here or upon calling verify
clientId: "<client_id>", // needs to be specified here or upon calling verify
groups: "admins", // optional
graceSeconds: 0, // optional
scope: "my-api/read", // optional
customJwtCheck: (payload, header, jwk) => {}, // optional
});
try {
const payload = await verifier.verify("eyJraWQeyJhdF9oYXNoIjoidk...", {
groups: "users", // Cognito groups overridden: should be users (not admins)
});
console.log("Token is valid. Payload:", payload);
} catch {
console.log("Token not valid!");
}