Một số lỗi thường gặp với authorize Serverless
Khi bạn build API thì bạn sẽ phải quan tâm đến việc authenticate và authorize, vậy làm sao để dùng authenticate và authorize trong serverless
Trong bài này mình đang dùng serverless để build API cho phía client
Lambda Authorizer Auth Workflow
1 : Client send request đến API Gateway, kèm theo token
hoặc các parameter
2: API Gateway check authenticate có được config hay chưa, nếu có thì API Gateway sẽ gọi đến Lambda functions
3: Lambda functions
check Authenticate. ( get token từ request, kiểm tra DB… )
4: Nếu Bước 3 thành công, lambda functions
sẽ cấp cho phép truy cập bằng cách trả về 1 object
có chứa ít nhất 1 IAM policy
và 1 định danh
( principal identifier
)
5: API Gateway sẽ nhận policy và đánh giá/xem xét nó:
- Nếu không được phép truy cập thì API Gateway sẽ trả về mã code HTTP phù hợp (401/403/500)
- Nếu được phép truy cập thì API sẽ thực thi phương thức. Nếu bạn bật caching trong
authorize caching
thì API Gateway cũng lưu cache lạipolicy
đó đểLambda authorizer function
không cần phải gọi lại
Example
Create a Token-Based Lambda Authorizer Function
Bài viết này mình sẽ dùng Nodejs 8.10 Dưới đây là đoạn code ví dụ về việc xác thực
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
const jwt = require('jsonwebtoken')
/*
* Check authorize User permission or role or another thing if you want
* @return boolean
* */
const authorizeUser = (userScopes, methodArn) => {
console.log(`authorizeUser ${JSON.stringify(userScopes)} ${methodArn}`)
// Tại đây bạn có thể kiểm tra permission/ role ...
return true
}
/*
* Build IAM Policy of user
* @return policy object
* */
const buildIAMPolicy = (userId, effect, resource, context = {}) => {
console.log(`buildIAMPolicy ${userId} ${effect} ${resource}`)
return {
principalId: userId,
policyDocument: {
Version: '2012-10-17',
Statement: [
{
Action: 'execute-api:Invoke',
Effect: effect,
Resource: resource,
},
],
},
context,
}
}
/*
* Handle authenticate function
* */
module.exports.handler = (event, {}, callback) => {
const { authorizationToken } = event
if (!authorizationToken) {
return callback('authorizationToken not parse from request')
}
const tokenParts = authorizationToken.split(' ')
const token = tokenParts[1]
if (!(tokenParts[0].toLowerCase() === 'bearer' && token)) {
return callback('Invalid format for authenticate or token empty')
}
try {
const decoded = jwt.verify(token, Buffer.from(process.env.JWT_SECRET, 'utf-8')) // Verify JWT
const { user } = decoded // Checks if the user's scopes allow her to call the current endpoint ARN
const effect = authorizeUser(user.id, event.methodArn) ? 'Allow' : 'Deny'
// Return an IAM policy document for the current endpoint
const userId = user.id
const authorizerContext = { user: JSON.stringify(user) }
const policyDocument = buildIAMPolicy(userId, effect, event.methodArn, authorizerContext)
return callback(null, policyDocument)
} catch (e) {
return callback('Unauthorized')
}
}
Trong ví dụ này, Khi API nhận được request thì API Gateway sẽ chuyển token
tới lambda functions
The Lambda authorizer function sẽ hoạt động như sau:
- Nếu
token
có giá trị làAllow
thìauthorize functions
sẽ trả về 200 OK HTTP vàIAM policy
sẽ giống như đoạn dưới
1
2
3
4
5
6
7
8
9
10
{
"Version": "2012-10-17",
"Statement": [
{
"Action": "execute-api:Invoke",
"Effect": "Allow",
"Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/"
}
]
}
- Nếu
token
có giá trị làDeny
thìauthorize functions
sẽ trả về 403 Forbidden HTTP vàIAM policy
sẽ giống như đoạn dưới1 2 3 4 5 6 7 8 9 10
{ "Version": "2012-10-17", "Statement": [ { "Action": "execute-api:Invoke", "Effect": "Deny", "Resource": "arn:aws:execute-api:us-east-1:123456789012:ivdtdhp7b5/ESTestInvoke-stage/GET/" } ] }
- Nếu
token
có giá trị làunauthorized
thìauthorize functions
sẽ trả về 401 Unauthorized HTTP - Còn lại nếu token có giá trị khác thì client sẽ nhận được mã lỗi 500
Tới đây là đã xong phần Custom Authorizer Serverless
, và có một số vấn đề xảy ra khi làm việc với nó như sau:
“message”: null
{ “Message”: “null” }
Problem
Khi debug với serverless-offline thì thấy ở màn hình console
1
2
Serverless: Running Authorization function for get /users (λ: authorize)
authorizationToken not parse from request: Authorization function returned an error response: (λ: authorize)
Nhưng khi deploy thì nó không hoạt động
Giải pháp
Bạn truy cập vào console của AWS và edit template mặc định của API Gateway
Bạn vào service Amazon API Gateway
–> Chọn API của bạn
–> Chọn mục Gateway Responses
và bạn cần sửa một số
thông tin để phù hợp với nhu cầu của bạn. Đối với mình thì mình sửa như hình dưới, thêm một số Response Header
( tránh CORS
) và mapping template
User is not authorized to access this resource
{ “Message”: “User is not authorized to access this resource” }
Problem
Nguyên nhân là tất cả các API của bạn đề gửi methodArn
trong event
và nó có dạng arn:aws:execute-api:us-1:text:123/prod/POST/v1/hello
Giải pháp
Thay vì bạn gửi event.methodArn
thì bạn nên gửi ký tự *
1
const policyDocument = buildIAMPolicy(userId, effect, '*', authorizerContext)
hoặc
1
2
3
4
5
6
const methodArn = [
arn:aws:execute-api:us-1:text:123/prod/POST/v1/hello,
arn:aws:execute-api:us-1:text:123/prod/GET/v1/hello,
...
]
const policyDocument = buildIAMPolicy(userId, effect, methodArn, authorizerContext)
Ngoài ra còn một số lỗi về việc deploy, mình sẽ cố gắng chia sẻ lại các lỗi đó trong bài khác, Cảm ơn đã đọc bài