AWS 用户无权通过显式拒绝访问此资源

Nda*_*ena 6 amazon-web-services node.js reactjs auth0 serverless

我正在 AWS 上部署无服务器应用程序,在尝试从前端访问我的无服务器应用程序时遇到一些问题。我的印象是问题出在后端,更具体地说是 serverless.yml 配置文件(请参见下面的第一行代码),或者更确切地说是我的 auth0Authorizer.ts 文件(请参见下面的第二行代码)。当我登录前端应用程序时,我收到一条 403 错误消息,内容为User is not authorized to access this resource with an explicit deny. 我真的怀疑这是否与 AWS 上的配置有关。

    org: name
app: serverless-todo-app-app
service:
  name: serverless-todo-app
package:
  individually: true

plugins:
  - serverless-webpack
  - serverless-iam-roles-per-function
  - serverless-reqvalidator-plugin
  - serverless-aws-documentation

provider:
  name: aws
  runtime: nodejs8.10
  stage: ${opt:stage, 'dev'}
  region: ${opt:region, 'us-west-1'}

  tracing: true

  environment:
    TODOS_TABLE: Todos-v4-${self:provider.stage}
    USER_ID_INDEX: UserIdIndex
    SIGNED_URL_EXPIRATION: 300 
    IMAGES_S3_BUCKET: 'severless-todo-app-bucket-v1-${self:provider.stage}'
    DYNAMODB_TABLE: TableName 
    TableName: ${self:provider.environment.TODOS_TABLE}
    AUTH_0_SECRET: ***********************************
  iamRoleStatements:
    - Effect: Allow
      Action:
        - dynamodb:Scan
        - dynamodb:PutItem
        - dynamodb:GetItem
        - codedeploy:*
        - xray:PutTelemetryRecords
        - xray:PutTraceSegments
      Resource:
        - '*'
    - Effect: Allow
      Action:
        - s3:GetObject
        - xray:PutTelemetryRecords
        - xray:PutTraceSegments     
      Resource: arn:aws:s3:::${self:provider.environment.IMAGES_S3_BUCKET}/*

custom:
  documentation:
    api:
      info:
        version: v1.0.0
        title: Udagram API
        description: Serverless application
    models:
      - name: TodoRequest
        contentType: application/json
        schema: ${file(models/create-todo-request.json)}


functions:

  Auth:
    handler: src/lambda/auth/auth0Authorizer.handler

  # TODO: Configure this function
  GetTodos:
    iamRoleStatements:
      - Effect: Allow
        Action:
          - dynamodb:Query
          - dynamodb:GetItem
        Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.TODOS_TABLE}

    handler: src/lambda/http/getTodos.handler
    events:
      - http:
          authorizer: Auth
          method: get
          path: todos
          cors: true


  # TODO: Configure this function
  CreateTodo:
    handler: src/lambda/http/createTodo.handler
    iamRoleStatements:
      - Effect: Allow
        Action:
          - dynamodb:PutItem
          - xray:PutTelemetryRecords
          - xray:PutTraceSegments
        Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.TODOS_TABLE}
    events:
      - http:
          authorizer: Auth
          method: post
          path: todos
          cors: true
          reqValidatorName: RequestBodyValidator
          documentation:
            summary: Create a new todo
            description: Create a new todo
            requestModels:
              'application/json': TodoRequest
  # TODO: Configure this function
  UpdateTodo:
    handler: src/lambda/http/updateTodo.handler
    iamRoleStatements:
      - Effect: Allow
        Action:
          - dynamodb:UpdateItem
          - xray:PutTelemetryRecords
          - xray:PutTraceSegments
        Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.TODOS_TABLE}

    events:
      - http:
          authorizer: Auth
          method: patch
          path: todos/{todoId}
          cors: true
  # TODO: Configure this function
  DeleteTodo:
    handler: src/lambda/http/deleteTodo.handler
    iamRoleStatements:
      - Effect: Allow
        Action:
          - dynamodb:DeleteItem
        Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.TODOS_TABLE}

    events:
      - http:
          authorizer: Auth
          method: delete
          path: todos/{todoId}
          cors: true

  # TODO: Configure this function
  GenerateUploadUrl:
    handler: src/lambda/http/generateUploadUrl.handler
    iamRoleStatements:
      - Effect: Allow
        Action:
          - s3:PutObject
          - s3:GetObject
          - xray:PutTelemetryRecords
          - xray:PutTraceSegments
        Resource: arn:aws:s3:::${self:provider.environment.IMAGES_S3_BUCKET}/*
      - Effect: Allow
        Action:
          - dynamodb:PutItem
          - dynamodb:GetItem
          - dynamodb:UpdateItem
        Resource: arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.TODOS_TABLE}

    events:
      - http:
          authorizer: Auth
          method: post
          path: todos/{todoId}/attachment
          cors: true

resources:
  Resources:
    # TODO: Add any necessary AWS resources
    AttachmentsBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:provider.environment.IMAGES_S3_BUCKET}
        CorsConfiguration:
          CorsRules:
            -
              AllowedOrigins:
                - '*'
              AllowedHeaders:
                - '*'
              AllowedMethods:
                - GET
                - PUT
                - POST
                - DELETE
                - HEAD
              MaxAge: 0

    BucketPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        PolicyDocument:
          Id: MyPolicy
          Version: "2012-10-17"
          Statement:
            - Sid: PublicReadForGetBucketObjects
              Effect: Allow
              Principal: '*'
              Action: 's3:GetObject'
              Resource: 'arn:aws:s3:::${self:provider.environment.IMAGES_S3_BUCKET}/*'
        Bucket: !Ref AttachmentsBucket


    GatewayResponseDefault4XX:
      Type: AWS::ApiGateway::GatewayResponse
      Properties:
        ResponseParameters:
          gatewayresponse.header.Access-Control-Allow-Origin: "'*'"
          gatewayresponse.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
          gatewayresponse.header.Access-Control-Allow-Methods: "'GET,OPTIONS,POST'"
        ResponseType: DEFAULT_4XX
        RestApiId:
          Ref: ApiGatewayRestApi

    RequestBodyValidator:
      Type: AWS::ApiGateway::RequestValidator
      Properties:
        Name: 'request-body-validator'
        RestApiId:
          Ref: ApiGatewayRestApi
        ValidateRequestBody: true
        ValidateRequestParameters: false

    TodosDynamoDBTable:
      Type: AWS::DynamoDB::Table
      Properties:
        AttributeDefinitions:
          - AttributeName: todoId
            AttributeType: S
          - AttributeName: userId
            AttributeType: S
        KeySchema:
          - AttributeName: userId
            KeyType: HASH
          - AttributeName: todoId
            KeyType: RANGE
        BillingMode: PAY_PER_REQUEST
        TableName: ${self:provider.environment.TODOS_TABLE}
        GlobalSecondaryIndexes:
          - IndexName: ${self:provider.environment.USER_ID_INDEX}
            KeySchema:
            - AttributeName: userId
              KeyType: HASH

            Projection:
              ProjectionType: ALL
Run Code Online (Sandbox Code Playgroud)
import { CustomAuthorizerEvent, CustomAuthorizerResult, CustomAuthorizerHandler } from 'aws-lambda'
import 'source-map-support/register'
import { verify } from 'jsonwebtoken'
import { JwtToken } from '../../auth/JwtToken'

const auth0Secret = process.env.AUTH_0_SECRET
export const handler: CustomAuthorizerHandler = async (event: CustomAuthorizerEvent): Promise<CustomAuthorizerResult> => {
  try {
    const decodedToken = verifyToken(event.authorizationToken)
    console.log('User was authorized')

    return {
      principalId: decodedToken.sub,
      policyDocument: {
        Version: '2012-10-17',
        Statement: [
          {
            Action: 'execute-api:Invoke',
            Effect: 'Allow',
            Resource: '*'
          }
        ]
      }
    }
  } catch (e) {
    console.log('User was not authorized', e.message)

    return {
      principalId: 'user',
      policyDocument: {
        Version: '2012-10-17',
        Statement: [
          {
            Action: 'execute-api:Invoke',
            Effect: 'Deny',
            Resource: '*'
          }
        ]
      }
    }
  }
}

function verifyToken(authHeader: string): JwtToken {
  if (!authHeader)
    throw new Error('No authentication header')

  if (!authHeader.toLowerCase().startsWith('bearer '))
    throw new Error('Invalid authentication header')

  const split = authHeader.split(' ')
  const token = split[1]

  return verify(token, auth0Secret) as JwtToken
}
Run Code Online (Sandbox Code Playgroud)

Far*_*hat 5

当 AWS 表示显式拒绝时,这意味着 IAM 策略链中的某个位置存在针对该操作的拒绝。在这种情况下,唯一的策略是您的授权者 Lambda 提供的会话策略。正如 @hephalump 在评论中提到的,根据您的代码,当出现错误时就会发生这种情况,因此请检查日志以了解需要做什么。