如何从API网关自定义授权程序中抛出自定义错误消息

时间:2017-12-21 09:27:09

标签: aws-api-gateway

蓝图中的

Here表示,API网关将以401响应:未经授权。

我在lambda中编写了相同的raise Exception('Unauthorized'),并能够从Lambda控制台进行测试。但是在POSTMAN中,我收到了状态500 身体:

{
  message: null`
} 

我想添加自定义错误消息,例如"无效签名"," TokenExpired"等,任​​何文档或指南都将不胜感激。

5 个答案:

答案 0 :(得分:8)

这是完全可能的,但文档是如此糟糕和令人困惑。

这是你如何做到的:

您可以在网关响应模板中访问一个名为$context.authorizer的对象。您可以在此处详细了解:https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html

以下是从您的授权人lambda中填充此authorizer对象的例子:

// A simple TOKEN authorizer example to demonstrate how to use an authorization token 
// to allow or deny a request. In this example, the caller named 'user' is allowed to invoke 
// a request if the client-supplied token value is 'allow'. The caller is not allowed to invoke 
// the request if the token value is 'deny'. If the token value is 'Unauthorized', the function 
// returns the 'Unauthorized' error with an HTTP status code of 401. For any other token value, 
// the authorizer returns an 'Invalid token' error. 

exports.handler =  function(event, context, callback) {
    var token = event.authorizationToken;
    switch (token.toLowerCase()) {
        case 'allow':
            callback(null, generatePolicy('user', 'Allow', event.methodArn));
            break;
        case 'deny':
            
            callback(null, generatePolicy('user', 'Deny', event.methodArn));
            break;
        case 'unauthorized':
            callback("Unauthorized");   // Return a 401 Unauthorized response
            break;
        default:
            callback("Error: Invalid token"); 
    }
};

       var generatePolicy = function(principalId, effect, resource) {
            var authResponse = {};
            
            authResponse.principalId = principalId;
            if (effect && resource) {
                var policyDocument = {};
                policyDocument.Version = '2012-10-17'; 
                policyDocument.Statement = [];
                var statementOne = {};
                statementOne.Action = 'execute-api:Invoke'; 
                statementOne.Effect = effect;
                statementOne.Resource = resource;
                policyDocument.Statement[0] = statementOne;
                authResponse.policyDocument = policyDocument;
            }
            
            // Optional output with custom properties of the String, Number or Boolean type.
            authResponse.context = {
                "stringKey": "stringval custom anything can go here",
                "numberKey": 123,
                "booleanKey": true,
            };
            return authResponse;
        }

这里关键是添加这部分:

// Optional output with custom properties of the String, Number or Boolean type.

        authResponse.context = {
            "stringKey": "stringval custom anything can go here",
            "numberKey": 123,
            "booleanKey": true,
        };

这将在$ context.authorizer

上提供

然后我在网关响应选项卡中设置了身体映射模板,如下所示:

{"message":"$context.authorizer.stringKey"}

注意:必须引用它!

最后 - 在邮递员发送Authorization令牌设置为拒绝的请求之后,我现在从邮递员那里取回一个看起来像这样的有效载荷:

{
    "message": "stringval custom anything can go here"
}

答案 1 :(得分:1)

我使用@maxwell解决方案,并使用自定义资源ResponseTemplates。像下面这样拒绝显示响应。

{
  "success":false,
  "message":"Custom Deny Message"
}

您可以检查此,https://github.com/SeptiyanAndika/serverless-custom-authorizer

答案 2 :(得分:1)

这可以通过使用context.fail()函数轻松实现。

示例:

const customAuthorizer: Handler = (event, context: Context, callback: Callback) => {        
    authenticate(event)
        .then((res) => {
            // result should be as described in AWS docs
            callback(null, res);
        })
        .catch((err) => {
            context.fail("Unauthorized");
        });
}

这将返回带有以下正文的401响应。

{
    "message": "Unauthorized"
}

这也可以通过抛出错误来实现:

throw new Error('Unauthorized');

答案 3 :(得分:0)

我不确定导致500 message: null响应的原因。可能是Lambda函数权限配置错误。

要自定义未授权的错误响应,您需要为UNAUTHORIZED错误类型设置网关响应。您可以在此处配置响应标头和负载。

答案 4 :(得分:0)

麦克斯韦大部分是正确的。我尝试了他的实现并注意到他的消息应该来自:

{"message":"$context.authorizer.stringKey"}

{"message":"$context.authorizer.context.stringKey"}