未经明确授权,AWS用户无权访问此资源

时间:2019-08-31 22:03:04

标签: node.js reactjs amazon-web-services 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
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
}

0 个答案:

没有答案