簡體   English   中英

AWS CDK 用戶池授權者

[英]AWS CDK user pool authorizer

我正在嘗試使用 AWS-CDK 創建一個 API 網關,並使用 Cognito 用戶池授權方保護 REST 端點。

我找不到任何示例如何做到這一點。 我認為它應該看起來像這樣,但也許我需要的方法不存在?

const cdk       = require('@aws-cdk/cdk');
const lambda    = require('@aws-cdk/aws-lambda');
const apigw     = require('@aws-cdk/aws-apigateway');

const path  = require('path');

// 
// Define the stack:
class MyStack extends cdk.Stack {
    constructor (parent, id, props) {
        super(parent, id, props);    

        var tmethodHandler = new lambda.Function(this, 'test-lambda', {
            runtime: lambda.Runtime.NodeJS810,
            handler: 'index.handler',
            code: lambda.Code.directory( path.join( __dirname, 'lambda')),
        });

        var api         = new apigw.RestApi(this, 'test-api');

        const tmethod   = api.root.addResource('testmethod');

        const tmethodIntegration    = new apigw.LambdaIntegration(tmethodHandler);

        tmethod.addMethod('GET', getSessionIntegration, {
            authorizationType: apigw.AuthorizationType.Cognito,
            authorizerId : 'crap!!!?'
        });

    }
}

class MyApp extends cdk.App {
    constructor (argv) {
        super(argv);

        new MyStack(this, 'test-apigw');
    }
}

console.log(new MyApp(process.argv).run());

截至September 2019 @bgdnip答案犯規准確翻譯為typescript 我得到它與以下工作:

const api = new RestApi(this, 'RestAPI', {
    restApiName: 'Rest-Name',
    description: 'API for journey services.',
});

const putIntegration = new LambdaIntegration(handler);

const auth = new CfnAuthorizer(this, 'APIGatewayAuthorizer', {
    name: 'customer-authorizer',
    identitySource: 'method.request.header.Authorization',
    providerArns: [providerArn.valueAsString],
    restApiId: api.restApiId,
    type: AuthorizationType.COGNITO,
});

const post = api.root.addMethod('PUT', putIntegration, { authorizationType: AuthorizationType.COGNITO });
const postMethod = post.node.defaultChild as CfnMethod;
postMethod.addOverride('Properties.AuthorizerId', { Ref: auth.logicalId });

這是來自https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html#cfn_layer_resource_props

十月更新

以上已經過時且不必要,可以通過以下使用aws-cdk 1.12.0來實現

const api = new RestApi(this, 'RestAPI', {
    restApiName: 'Rest-Name',
    description: 'API for journey services.',
});

const putIntegration = new LambdaIntegration(handler);

const auth = new CfnAuthorizer(this, 'APIGatewayAuthorizer', {
    name: 'customer-authorizer',
    identitySource: 'method.request.header.Authorization',
    providerArns: [providerArn.valueAsString],
    restApiId: api.restApiId,
    type: AuthorizationType.COGNITO,
});

const post = api.root.addMethod('PUT', putIntegration, {
    authorizationType: AuthorizationType.COGNITO,
    authorizer: { authorizerId: auth.ref }
});

這是我在 TypeScript 中的解決方案(有點基於 bgdnlp 的響應)

import { App, Stack, Aws } from '@aws-cdk/core';
import { Code, Function, Runtime } from '@aws-cdk/aws-lambda';
import { LambdaIntegration, RestApi, CfnAuthorizer, CfnMethod } from '@aws-cdk/aws-apigateway';

const app = new App();
const stack = new Stack(app, `mystack`);
const api = new RestApi(stack, `myapi`);

const region = Aws.REGION;
const account = Aws.ACCOUNT_ID;
const cognitoArn = `arn:aws:cognito-idp:${region}:${account}:userpool/${USER_POOL_ID}`;

const authorizer = new CfnAuthorizer(stack, 'Authorizer', {
  name: `myauthorizer`,
  restApiId: api.restApiId,
  type: 'COGNITO_USER_POOLS',
  identitySource: 'method.request.header.Authorization',
  providerArns: [cognitoArn],
});

const lambda = new Function(stack, 'mylambda', {
  runtime: Runtime.NODEJS_10_X,
  code: Code.asset('dist'),
  handler: `index.handler`,
});

const integration = new LambdaIntegration(lambda);

const res = api.root.addResource('hello');

const method = res.addMethod('GET', integration);

const child = method.node.findChild('Resource') as CfnMethod;

child.addPropertyOverride('AuthorizationType', 'COGNITO_USER_POOLS');

child.addPropertyOverride('AuthorizerId', { Ref: authorizer.logicalId });

以前的答案不再有效,因為authorizerId屬性已替換為authorizer ,目前尚未完全實現。

相反,它可以通過使用底層 CfnResource 對象來完成,如官方指南中所述

下面以 Python 代碼為例:

from aws_cdk import cdk
from aws_cdk import aws_apigateway


class Stk(cdk.Stack):
    def __init__(self, app, id):
        super().__init__(app, id)

        api_gw = aws_apigateway.RestApi(self, 'MyApp')
        post_method = api_gw.root.add_method(http_method='POST')

        # Create authorizer using low level CfnResource
        api_gw_authorizer = aws_apigateway.CfnAuthorizer(
            scope=self,
            id='my_authorizer',
            rest_api_id=api_gw.rest_api_id,
            name='MyAuth',
            type='COGNITO_USER_POOLS',
            identity_source='method.request.header.name.Authorization',
            provider_arns=[
                'arn:aws:cognito-idp:eu-west-1:123456789012:userpool/'
                'eu-west-1_MyCognito'])

        # Get underlying post_method Resource object. Returns CfnMethod
        post_method_resource = post_method.node.find_child('Resource')
        # Add properties to low level resource
        post_method_resource.add_property_override('AuthorizationType',
                                                   'COGNITO_USER_POOLS')
        # AuthorizedId uses Ref, simulate with a dictionaty
        post_method_resource.add_property_override(
                'AuthorizerId',
                {"Ref": api_gw_authorizer.logical_id})


app = cdk.App()
stk = Stk(app, "myStack")

app.synth()

我想出了一個機制......我能夠讓它像這樣工作:

var auth = new apigw.cloudformation.AuthorizerResource(this, 'myAuthorizer', {
    restApiId: api.restApiId,
    authorizerName: 'mypoolauth',
    authorizerResultTtlInSeconds: 300,
    identitySource: 'method.request.header.Authorization',
    providerArns: [ 'arn:aws:cognito-idp:us-west-2:redacted:userpool/redacted' ],
    type: "COGNITO_USER_POOLS"
});

tmethod.addMethod('GET', getSessionIntegration, {
    authorizationType: apigw.AuthorizationType.Cognito,
    authorizerId : auth.authorizerId
});

現在要弄清楚如何在 API 網關上啟用 CORS 標頭...

的確。 沒有通過復制和粘貼來執行此操作的示例;)。 這是我使用基於 Java 版本 0.24.1 的 AWS CDK 創建 AWS Cognito 用戶池並將用戶 pol 授權方與 API 網關和 lambda 函數連接起來的示例。

此示例只是為名為“Foo”的函數提供受保護 API 的示例。

  • Cognito 用戶池
  • API網關
  • 拉姆達
  • 動態數據庫

    // ----------------------------------------------------------------------- // Cognito User Pool // ----------------------------------------------------------------------- CfnUserPool userPool = new CfnUserPool(this, "cognito", CfnUserPoolProps.builder() .withAdminCreateUserConfig( AdminCreateUserConfigProperty.builder() .withAllowAdminCreateUserOnly(false) .build()) .withPolicies( PoliciesProperty.builder() .withPasswordPolicy( PasswordPolicyProperty.builder() .withMinimumLength(6) .withRequireLowercase(false) .withRequireNumbers(false) .withRequireSymbols(false) .withRequireUppercase(false) .build() ) .build() ) .withAutoVerifiedAttributes(Arrays.asList("email")) .withSchema(Arrays.asList( CfnUserPool.SchemaAttributeProperty.builder() .withAttributeDataType("String") .withName("email") .withRequired(true) .build())) .build()); // ----------------------------------------------------------------------- // Cognito User Pool Client // ----------------------------------------------------------------------- new CfnUserPoolClient(this, "cognitoClient", CfnUserPoolClientProps.builder() .withClientName("UserPool") .withExplicitAuthFlows(Arrays.asList("ADMIN_NO_SRP_AUTH")) .withRefreshTokenValidity(90) .withUserPoolId(userPool.getRef()) .build()); // ----------------------------------------------------------------------- // Lambda function // ----------------------------------------------------------------------- Function function = new Function(this, "function.foo", FunctionProps.builder() // lamda code located in /functions/foo .withCode(Code.asset("functions/foo")) .withHandler("index.handler") .withRuntime(Runtime.NODE_J_S810) .build()); // ----------------------------------------------------------------------- // DynamoDB Table // ----------------------------------------------------------------------- Table table = new Table(this, "dynamodb.foo", TableProps.builder() .withTableName("foo") .withPartitionKey(Attribute.builder() .withName("id") .withType(AttributeType.String) .build()) .build()); // GRANTS function -> table table.grantReadWriteData(function.getRole()); // ----------------------------------------------------------------------- // API Gateway // ----------------------------------------------------------------------- // API Gateway REST API with lambda integration LambdaIntegration lambdaIntegration = new LambdaIntegration(function); RestApi restApi = new RestApi(this, "foo"); // Authorizer configured with cognito user pool CfnAuthorizer authorizer = new CfnAuthorizer(this, "authorizer", CfnAuthorizerProps.builder() .withName("cognitoAuthorizer") .withRestApiId(restApi.getRestApiId()) .withIdentitySource("method.request.header.Authorization") .withProviderArns(Arrays.asList(userPool.getUserPoolArn())) .withType("COGNITO_USER_POOLS") .build()); // Bind authorizer to API ressource restApi.getRoot().addMethod("ANY", lambdaIntegration, MethodOptions .builder() .withAuthorizationType(AuthorizationType.Cognito) .withAuthorizerId(authorizer.getAuthorizerId()) .build());

你必須:

  • 創建api網關
  • 在 api 網關中將 Cognito 設置為授權方
  • 在您的方法中設置授權
  • 將您與 lambda 的集成設置為“使用 Lambda 代理集成”。 默認情況下,LambdaIntegration 屬性將此值設為 true,因此不必擔心

最后,發出請求,在 Header 中添加令牌。 API 網關將使用 Cognito 對其進行驗證。 如果此通過,您的 lambda 將被觸發,如果您可以找到聲明event.requestContext.authorizer.claims


const lambda = require("@aws-cdk/aws-lambda");
const apiGateway = require('@aws-cdk/aws-apigateway'); 

 const api = new apiGateway.RestApi(
      this,
      '<id-ApiGateway>',
      {
        restApiName: '<ApiGateway-name>',
      },
    );

    const auth = new apiGateway.CfnAuthorizer(this, '<id>', {
      name: "<authorizer-name>",
      type: apiGateway.AuthorizationType.COGNITO,
      authorizerResultTtlInSeconds: 300,
      identitySource: "method.request.header.Authorization",
      restApiId: api.restApiId,
      providerArns: ['<userPool.userPoolArn>'],
    });

    const myLambda= new lambda.Function(this, "<id>", {
      functionName: '<lambda-name>',
      runtime: lambda.Runtime.NODEJS_10_X,
      handler: "<your-handler>",
      code: lambda.Code.fromAsset("<path>"), // TODO: modify the way to get the path
    });

      const lambdaIntegration = new apiGateway.LambdaIntegration(myLambda);

      const resource = api.root.resourceForPath('<your-api-path>');
      // When the API will be deployed, the URL will look like this
      // https://xxxxxx.execute-api.us-east-2.amazonaws.com/dev/<your-api-path>

      const authorizationOptions = {
        apiKeyRequired: false,
        authorizer: {authorizerId: auth.ref},
        authorizationType: 'COGNITO_USER_POOLS'
      };

      resource.addMethod(
        GET, // your method
        lambdaIntegration,
        authorizationOptions
      );

對於使用 CDK 的 Java 版本的怪人(像我一樣),您可以使用 Cfn 構造上的 setter:

final UserPool userPool = ...
final RestApi restApi = ...
final LambdaIntegration integration = ...
final Method method = restApi.getRoot().addMethod("GET", integration);

final CfnAuthorizer cognitoAuthorizer = new CfnAuthorizer(this, "CfnCognitoAuthorizer",
        CfnAuthorizerProps.builder()
                .name("CognitoAuthorizer")
                .restApiId(restApi.getRestApiId())
                .type("COGNITO_USER_POOLS")
                .providerArns(Arrays.asList(userPool.getUserPoolArn()))
                .identitySource("method.request.header.Authorization")
                .build());

final CfnMethod cfnMethod = (CfnMethod) method.getNode().getDefaultChild();
cfnMethod.setAuthorizationType("COGNITO_USER_POOLS");
cfnMethod.setAuthorizerId(cognitoAuthorizer.getRef());

從 v1.88 開始,現在 CDK 直接支持

const userPool = new cognito.UserPool(this, 'UserPool');

const auth = new apigateway.CognitoUserPoolsAuthorizer(this, 'booksAuthorizer', {
  cognitoUserPools: [userPool]
});

declare const books: apigateway.Resource;
books.addMethod('GET', new apigateway.HttpIntegration('http://amazon.com'), {
  authorizer: auth,
  authorizationType: apigateway.AuthorizationType.COGNITO,
});

AWS CDK API V1 參考

AWS CDK API V2 參考

如果您當前使用的是CDK v2CDK v1(latest) 這很容易:

// Your cognito userpool
const userPool = new cognito.UserPool(this, "MyUserPool")

// Authorizer for your userpool
const cognitoAuthorizer = new apigw.CognitoUserPoolsAuthorizer(
  this,
  "CognitoAuthorierOnLambda",
  {
    cognitoUserPools: [userPool],
  }
);

// Rest Api
const api = new apigw.RestApi(this, 'myApi', {
  defaultCorsPreflightOptions: {
    allowOrigins: apigw.Cors.ALL_ORIGINS,
    allowMethods: apigw.Cors.ALL_METHODS, // this is also the default
  },
  deploy: true
});

// add /getItems endpoint
const getItems = api.root.addResource('getItems');

// attach lambda to this endpoint 
const getItemsIntegration = new apigw.LambdaIntegration(getItemsLambdaFunction);    

// make the endpoint secure with cognito userpool           
getItems.addMethod('GET', getAllItemsIntegration, {
  authorizer:cognitoAuthorizer
});

暫無
暫無

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

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