繁体   English   中英

从 Lambda - Node Js 验证和解码 Cognito json 网络令牌

[英]Verify and decode Cognito json web token from Lambda - Node Js

我已经设置了一个使用 Cognito、Lambda 和 API 网关的小型 Web 应用程序,用户通过 UI 中的 Cognito 进行身份验证。 我还为我的 ApiGateway 端点设置了一个 Cognito Authorizer,我从 UI 中测试了它,我复制并粘贴了我的令牌,它返回了 200。但是我需要在他请求一项服务时识别我的用户,所以我想解码和验证我在 lambda 的事件对象中获得的 JSON Web 令牌以获取有效负载和用户属性但我现在需要验证和解码 JSON Web 令牌,如库https://github.com/awslabs/aws的文档-jwt-verify要访问事件对象,我正在使用 aws-serverless-express/middleware 库,如下所示:

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:缺少范围。 预期:阅读

我也尝试像文档的第一个示例一样删除属性范围,但我也遇到了另一个错误

CognitoJwtInvalidTokenUseError:不允许使用令牌:id。 预期:访问

使用此代码:

节点 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)

我希望这能帮到您!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM