在使用AWS进行开发的时候,APIGateway的使用频率非常高。在开发API的时候,必须要考虑其安全性。下面就介绍一下如何使用AWS Lambda Authorizer为APIGateway增加安全性。

基本原理
在用户对API发出请求之前,需要先进行登录验证,本文不涉及登录部分,只涉及登陆后,如果通过token访问API。在登录成功后用户获得一个authorizationToken。之后每次发出API请求的时候,都要携带这个token。其发出的请求参数可能是这样的:
{
"studentId": "9901",
"authorizationToken": "xxxxxxxx"
}
用户发出API调用请求 => APIGateway => 对Lambda Authorizer发出授权请求 => Lambda Authorizer进行认证 => 通过后调用Lambda Handler
Lambda Authorizer会返回一个Policy Document,陈述是否对本次请求授权:
{
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action":"execute-api:Invoke",
"Resource": [
"arn:aws:execute-api:eu-west-1:AWS_ACCOUNT_ID:API_ID/STAGE/MEHTOD/RESOURCE"
],
"Effect": "Allow"
}
]
}
}
上面Resource众的API_ID指的是在APIGateway中创建的API对应的ID,而不是相应Resource/Mehthod对应的ID。
实现步骤
创建Lambda
首先选择”Author from Scratch”,创建一个Node.js 14.x Lambda:
exports.handler = async (event) => {
const response = {
statusCode: 200,
body: JSON.stringify('Hello from Lambda!'),
};
return response;
};
通过APIGateway暴露Lambda
在APIGateway中,选择创建一个REST API。
创建一个Resource,比如叫做students
创建一个GET方法,并连接到上一步创建的Lambda:

然后选择Deploy API,部署完毕后就可以通过网址访问这个API了: https://xxxxxx.execute-api.eu-west-1.amazonaws.com/dev/students
其返回结果类似这样:
{"statusCode":200,"body":"\"Hello from Lambda!\""}
创建Authorizer Lambda
首先再创建一个Lambda (TestLambaAuthorizer),来实现验证逻辑。这里就不再和后台数据库连接了,只通过一个简单的逻辑来演示。其代码为:
exports.handler = async (event) => {
let auth = 'Deny';
if (event['authorizationToken'] == 'your_token') {
auth = 'Allow';
}
return {
"principalId": "test_principal",
"policyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Resource": ["arn:aws:execute-api:eu-west-1:AWS_ACCOUNT_ID:API_ID/*/*/*"],
"Effect": auth
}
]
}
}
};
注意:上面Resource的格式为:arn:aws:execute-api:REGION:AWS_ACCOUNT_ID:API_ID/STAGE/METHOD/RESOURCE
为API增加Authorizer
创建Authorizer
首先需要创建一个Authorizer,并使用第二个Lambda来处理请求。

将Authorizer和对应的方法关联
接下来将刚创建的Authorizer和待保护的资源/方法相关联:

记得重新发布API
测试
接下来使用Postman进行测试,如果直接发送GET请求到APIGateway,会看到未授权访问信息:
{
"message": "Unauthorized"
}
然后再Postman中添加Header,再进行测试,通过。

注意事项
- 可以使用mock来做到快速迭代
- 可以使用request/response mapping模板来更好的兼容历史遗留应用
- 需要使用Lambda异步调用来支持耗时较长的请求(>30s)