簡體   English   中英

如何使用 aws-amplify 驗證 node/express 中的 accessToken?

[英]How to verify accessToken in node/express using aws-amplify?

我在我的前端 React 應用程序上使用 AWS amplify 進行用戶身份驗證。 我的 React 應用程序直接與 amplify 通信,無需任何后端(節點服務器)交互。

我有一個用 node/express 編寫的 REST API。 我想使用放大來保護該 API。

目前,我計划將訪問令牌從我的反應應用程序傳遞到我的節點服務器。 但是我無法找到一種方法來使用放大在后端驗證此令牌。

aws-amplify 包是否提供任何我可以傳遞訪問令牌來驗證它的功能?

Auth.verifyToken(<access_token>)

不幸的是,官方的 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標頭中發送它,然后使用我編寫的中間件在后端驗證它。

AWS 實際上已經很好地記錄了這一點。 我寫了一個關於我編寫的中間件的要點,用於在我的 express.js 服務器中驗證 AWS Cognito 令牌。

本質上,當您在 Amazon 中創建用戶池時,AWS 會創建一個 JSON Web Key (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

不幸的是,aws-amplify SDK 不提供該功能。 出於這個原因,我創建了一個npm 包來處理它。

這個怎么運作

認證流程

該包公開:

  • authenticate :一個 Express 中間件,可以添加到任何需要根據 Cognito 用戶池進行身份驗證的路由中。
  • authenticationError :一個 Express 錯誤處理程序,負責處理由authenticate中間件生成的任何身份驗證錯誤。
  • JWTValidator :可以實例化以驗證 Cognito 發布的JWTValidator的類。 如果您需要自定義身份驗證和錯誤處理邏輯,這將非常有用。 authenticate中間件在內部使用它。

包括的功能

  • JWT 簽名驗證。
  • JWT 聲明驗證。
  • 驗證令牌未過期。
  • 驗證受眾 (aud) 聲明是否與配置中提供的有效受眾之一匹配。
  • 驗證頒發者 (iss) 聲明對於配置的用戶池是否有效。
  • 驗證 token_use 聲明是否與配置中提供的有效令牌用途之一匹配。
  • 根據JWT 簽名密鑰輪換線程中的描述支持 JWK 輪換。
  • 能夠為本地測試設置自定義 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;

有關更高級的用例,請在此處查看文檔。

自 2021 年 9 月 17 日起,我們現在有了這個存儲庫(以及相關的 npm 包):

這允許我們(外部節點應用程序,通常是服務器端面向 Web 的應用程序)驗證由 AWS 簽名的 JWT,例如從 AWS cognito 發出的 JWT。

具體來說,由於令牌是非對稱簽名的,因此節點包的這個經過驗證的 AWS 帳戶發布者指的是 AWS 發布的 JSON Web 密鑰集 (JWKS),從而提高了對我們用來驗證 JWT 中包含的聲明的代碼的信任度,因為它們可以作為不記名令牌提供給我們的應用程序。

取自https://github.com/awslabs/aws-jwt-verify#express的示例代碼(在這種情況下它使用express )似乎也非常用戶友好:

import express, { Request } from 'express';
import { CognitoJwtVerifier } from 'aws-jwt-verify';


const cognitoJWTVerifier = CognitoJwtVerifier.create({
  userPoolId: 'your-user-pool-id', // mandatory, can't be overridden upon calling verify
  tokenUse: 'access',
  clientId: 'your-client-id',
});


app.get('/authenticated/route', async (req: Request & { verifiedCognitoJWT?: any }, res, next) => {
  try {
    const verifiedCognitoJWT = await cognitoJWTVerifier.verify(`${req.header('authorization')}`);
    req.verifiedCognitoJWT = verifiedCognitoJWT;

    next();
  } catch (e) {
    return res.status(401).json({ statusCode: 401, message: 'Unauthorized' });
  }
}, getAuthenticatedRoute);

請注意,您可以選擇在您的應用程序開始偵聽 HTTP 連接之前調用hydrate()來預取 JWKS,但省略此調用只會延遲對verify()的第一次調用,該調用會延遲獲取它們。

當然,這個例子可以通過適當的類型進行擴展,或者根據需要內置到中間件等中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM