Я хочу добавить cognito authorizer ко всем функциям, объявленным в моем serverless.yml
файле. Для этого есть две основные причины:
1) Я хочу не повторять нижеприведенное для каждой отдельной функции
functions:
hello:
handler: handler.hello
events:
- http:
path: hello
method: get
integration: lambda
authorizer:
name: authorizer
arn: arn:aws:cognito-idp:us-east-1:0000:userpool/us-east-1_XXXXXX
2) Я хочу обеспечить безопасность всех конечных точек по умолчанию - важно!
Я создал ниже безсерверный плагин , но не уверен в A) какое событие жизненного цикла мне следует использовать и B) есть ли способ получить идентификатор авторизатора или ARN, не делая api-вызовы ?
class ServerlessCognitoAuthorizer {
constructor(serverless, options) {
this.serverless = serverless
this.options = options
this.hooks = {
'package:compileEvents': this.addAuhtorizer.bind(this)
}
const region = this.options.region || 'ap-southeast-2'
const credentials = this.serverless.providers.aws.getCredentials()
const myCredentials = Object.assign({}, credentials, { region })
this.apiGateway = new this.serverless.providers.aws.sdk.APIGateway(myCredentials)
}
async getApiId() {
try {
const result = await this.apiGateway.getRestApis({ limit: 1 }).promise()
const api = result.items.find(a => a.name === `my-${this.options.stage}-api`)
if (!api) {
this.serverless.cli.log('Cannot find REST API to add Cognito Authorizer. Skipping...')
return null
}
return api.id
} catch (e) {
this.serverless.cli.log('Error in ServerlessCognitoAuthorizer')
}
}
async getAuthorizer(restApiId) {
try {
const result = await this.apiGateway.getAuthorizers({ restApiId, limit: 1 }).promise()
const authorizerId = result.items[0].id
if (!authorizerId) {
this.serverless.cli.log(`Cannot find Cognito Authorizer ID for ${restApiId}`)
return null
}
return authorizerId
} catch (e) {
this.serverless.cli.log('Error in ServerlessCognitoAuthorizer')
throw e
}
}
async addAuhtorizer() {
const apiId = await this.getApiId()
let authorizerId
if (apiId) {
authorizerId = await this.getAuthorizer(apiId)
}
Object.values(this.serverless.service.functions).forEach(slsFunction => {
const { events, name } = slsFunction
for (const event of events) {
const httpEvent = event.http
if (httpEvent && authorizerId) {
this.serverless.cli.log(`Adding authorizer config to function ${name}`)
httpEvent.authorizer = {
type: 'COGNITO_USER_POOLS',
authorizerId
}
}
}
})
}
}
module.exports = ServerlessCognitoAuthorizer
Кстати, я создаю свой пул когнитивных систем с помощью ресурса формирования облаков ниже:
Resources:
CognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: ${self:service.name}-${self:provider.stage}-userpool
UsernameAttributes:
- email
AutoVerifiedAttributes:
- email
Schema:
- Name: given_name
AttributeDataType: String
Mutable: true
Required: true
- Name: family_name
AttributeDataType: String
Mutable: true
Required: true
- Name: email
AttributeDataType: String
Mutable: false
Required: true
Policies:
PasswordPolicy:
MinimumLength: 10
RequireLowercase: true
RequireNumbers: true
RequireSymbols: false
RequireUppercase: true
EmailConfiguration:
...
CognitoUserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
ClientName: ${self:provider.stage}-userpool-client
AllowedOAuthFlows:
- code
AllowedOAuthScopes:
- phone
- email
- openid
SupportedIdentityProviders:
- COGNITO
UserPoolId:
Ref: CognitoUserPool
ExplicitAuthFlows:
- ADMIN_NO_SRP_AUTH
GenerateSecret: false
...
# Print out the Id of the User Pool that is created
Outputs:
UserPoolId:
Value:
Ref: CognitoUserPool
UserPoolClientId:
Value:
Ref: CognitoUserPoolClient