如何使用 aws-amplify 验证 node/express 中的 accessToken?

Posted

技术标签:

【中文标题】如何使用 aws-amplify 验证 node/express 中的 accessToken?【英文标题】:How to verify accessToken in node/express using aws-amplify? 【发布时间】:2020-07-12 12:00:06 【问题描述】:

我正在使用 AWS amplify 在我的前端 React 应用程序上进行用户身份验证。 我的 React 应用直接与 amplify 通信,无需任何后端(节点服务器)交互。

我有一个用 node/express 编写的 REST API。我想使用放大来保护该 API。

目前,我正计划将访问令牌从我的反应应用程序传递到我的节点服务器。但我无法找到一种方法可以在后端使用放大验证此令牌。

aws-amplify 包是否提供任何我可以传递访问令牌来验证它的功能?

类似Auth.verifyToken(<access_token>)

【问题讨论】:

【参考方案1】:

很遗憾,官方的 aws-amplify SDK 中没有这样的方法。 经过大量研究后,我不得不为此编写自己的中间件。这并不像看起来那么困难,但唯一困难的部分是从庞大的 AWS 文档中收集正确的信息。

我已经编写了这个中间件来实现同样的效果,希望这会有所帮助

import axios from 'axios'
import awsconfig from '../../aws-exports';

const COGNITO_URL = `https://cognito-idp.$awsconfig.aws_project_region.amazonaws.com/`;

const authentication = async (req, res, next) => 
    try 
        const accessToken = req.headers.authorization.split(" ")[1];

        const  data  = await axios.post(
            COGNITO_URL,
            
                AccessToken: accessToken
            ,
            
                headers: 
                    "Content-Type": "application/x-amz-json-1.1",
                    "X-Amz-Target": "AWSCognitoIdentityProviderService.GetUser"
                
            
        )

        req.user = data;
        next();
     catch (error) 
        return res.status(401).json(
            message: 'Auth failed'
        );
    
;

export default authentication;

此中间件采用授权标头并使用 AWS Cognito REST API 验证传入的 accessToken。

为了在您的前端获取 accessToken,您可以执行以下操作:

const  accessToken:  jwtToken   = await Auth.currentSession();

这个jwtToken 是你的accessToken,你可以在你的Authorization 标头中发送它,然后使用我编写的中间件在后端验证它。

【讨论】:

【参考方案2】:

AWS 实际上已经很好地记录了这一点。我写了一个关于我编写的中间件的要点,用于在我的 express.js 服务器中验证 AWS Cognito 令牌。

本质上,当您在 Amazon 中创建用户池时,AWS 会创建一个 JSON Web 密钥 (JWK)。 JWT 包含一个公钥,您可以使用它来验证 JWT 的签名。

javascript 中的高级:

import jwt from "jsonwebtoken";

const authToken = getJwtFromHeader(request);

// please remember to verify the "iss" claim and "exp" claim!
validateAuthToken(authToken);

// convert a jwk to a PEM for use by OpenSSL or crypto
const jwk = getJwkFromAWS();
const pem = jwkToPem(jwk);

// verify the signature of the token using the public key from AWS
await jwt.verify(authToken, pem, algorithms: ['RS256'], (err, decoded) =>
  console.log('decoded', decoded);
  // TODO -- verify claims from decoded token
); 

完整 express.js 实现的我的 GIST: https://gist.github.com/fourgates/92dc769468497863168417c3524e24dd

AWS 资源:

https://github.com/awslabs/aws-support-tools/tree/master/Cognito/decode-verify-jwt https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-verifying-a-jwt.html

【讨论】:

重要提示:对于阅读本文的任何人,记得验证“iss”声明和“exp”声明!如果您不检查“iss”声明,任何拥有 AWS 账户的人都可以创建一个用户池并发出 JWT,这些 JWT 将通过您的应用程序进行身份验证。听起来很明显,但万一你忘记了!【参考方案3】:

很遗憾,aws-amplify SDK 不提供该功能。为此,我创建了一个npm package 来处理它。

工作原理

包暴露:

authenticate:一个 Express 中间件,可以添加到任何需要针对 Cognito 用户池进行身份验证的路由。 authenticationError:一个 Express 错误处理程序,负责处理由 authenticate 中间件生成的任何身份验证错误。 JWTValidator:可以实例化以验证 Cognito 发布的 JWT 的类。如果您需要自定义身份验证和错误处理逻辑,这很有用。 authenticate 中间件在内部使用它。

包含的功能

JWT 签名验证。 JWT 声明验证。 验证令牌未过期。 验证受众 (aud) 声明是否与有效声明之一匹配 配置中提供的受众群体。 验证颁发者 (iss) 声明对配置的用户是否有效 游泳池。 验证 token_use 声明与有效令牌用途之一匹配 在配置中提供。 支持 JWK 轮换,如 JWT signing key rotation thread 中所述。 能够为本地测试设置自定义 pem,而无需 创建用户池。

基本用法

// app.js
'use strict';

const express = require('express');
const  authenticate, authenticationError  = require('aws-cognito-express');

const app = express();

// Add the authentication middleware.
app.use(authenticate(
  region: 'us-east-2',
  userPoolId: 'us-east-2_6IfDT7ZUq',
  tokenUse: ['id', 'access'],
  audience: ['55plsi2cl0o267lfusmgaf67pf']
));

// Protected route.
app.get('/articles', (req, res, next) => 
  console.log('JWT payload: ', req.cognito);
);

// Add the authentication error handler.
app.use(authenticationError());

module.exports = app;

有关更高级的用例,请查看文档here。

【讨论】:

请不要只发布一些工具/包或库作为答案。至少在答案本身中展示how it solves the problem。 @Shree 我刚刚更新了它。谢谢你让我知道:) 这没有提供问题的答案。一旦你有足够的reputation,你就可以comment on any post;相反,provide answers that don't require clarification from the asker. @StevenSiebert 我刚刚编辑了我的答案,以明确 aws-amplify SDK 目前不提供此功能。感谢您的建议。

以上是关于如何使用 aws-amplify 验证 node/express 中的 accessToken?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 aws-amplify 处理 api 错误?

无法解析模块“@aws-amplify/ui-react/styles.css”的路径

如何在我的 Vuejs 项目中迁移 aws-amplify 以使用 Typescript?

如何按日期(createdAt)对aws-amplify中列表查询中的字段进行排序?

AWS-amplify 在请求中包含 cognito Authorization 标头

无法使用 aws-amplify 从 cognito 获取更新的属性及其值