如何使用Spring Cloud Function创建AWS Lambda自定义API Gateway授权器并正确返回策略文档
解决Spring Cloud Function Lambda授权器返回结构被包装的问题
这个问题我之前也碰到过——Spring Cloud Function的AWS适配器默认会把函数返回值包装成APIGatewayProxyResponseEvent格式(就是你看到的带isBase64Encoded、headers、body的外层结构),这是为了适配常规的API Gateway Lambda集成场景,但Lambda授权器要求直接返回策略文档JSON,不需要这层额外包装。
下面是两种可行的解决方法:
方法1:禁用代理模式包装(最快解决)
在你的Spring Boot应用配置文件(application.properties或application.yml)中添加以下配置,让AWS适配器直接返回函数的输出结果,不进行外层包装:
spring.cloud.function.adapter.aws.proxy.mode=false
配置后,你当前返回的Map<String, Object>会被直接序列化为JSON,不再被包裹到body字段里,正好符合API Gateway授权器的要求。
方法2:使用类型安全的POJO(更健壮)
如果想让代码更清晰、避免Map序列化的潜在问题,可以创建对应授权策略结构的POJO类,替换当前的Map返回:
第一步:定义AuthPolicy相关POJO
import java.util.List; import java.util.Map; public class AuthPolicy { private String principalId; private PolicyDocument policyDocument; private Map<String, Object> context; // Getters, Setters & Constructor public AuthPolicy() {} public AuthPolicy(String principalId, PolicyDocument policyDocument, Map<String, Object> context) { this.principalId = principalId; this.policyDocument = policyDocument; this.context = context; } // Getters and Setters omitted for brevity public static class PolicyDocument { private String Version = "2012-10-17"; private List<Statement> Statement; // Getters, Setters & Constructor public PolicyDocument() {} public PolicyDocument(List<Statement> statement) { Statement = statement; } // Getters and Setters omitted for brevity } public static class Statement { private String Action = "execute-api:Invoke"; private String Effect; private String Resource; // Getters, Setters & Constructor public Statement() {} public Statement(String effect, String resource) { Effect = effect; Resource = resource; } // Getters and Setters omitted for brevity } }
第二步:修改Function Bean返回POJO
import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.HashMap; import java.util.List; import java.util.UUID; import java.util.function.Function; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @Configuration public class AuthFunctionConfig { private static final Logger logger = LoggerFactory.getLogger(AuthFunctionConfig.class); @Bean public Function<APIGatewayProxyRequestEvent, AuthPolicy> authorise() { return request -> { String token = request.getHeaders().get("Authorization"); String arn = String.format("arn:aws:execute-api:%s:%s:%s/%s/%s/", System.getenv("AWS_REGION"), request.getRequestContext().getAccountId(), request.getRequestContext().getApiId(), request.getRequestContext().getStage(), request.getRequestContext().getHttpMethod()); try { String effect = request.getHttpMethod().equalsIgnoreCase("GET") ? "Allow" : "Deny"; // 构建Statement AuthPolicy.Statement statement = new AuthPolicy.Statement(effect, arn); // 构建PolicyDocument AuthPolicy.PolicyDocument policyDoc = new AuthPolicy.PolicyDocument(List.of(statement)); // 构建上下文 Map<String, Object> context = new HashMap<>(); context.put("name", "test"); return new AuthPolicy(UUID.randomUUID().toString(), policyDoc, context); } catch (Exception e) { logger.error("Failed to generate authorization policy", e); // 这里可以返回默认拒绝策略或抛出异常,根据业务需求处理 return null; } }; } }
第三步:同样禁用代理模式
别忘了添加和方法1一样的配置:
spring.cloud.function.adapter.aws.proxy.mode=false
验证效果
配置完成后,你的Lambda函数返回的JSON就会是API Gateway授权器期望的结构,直接返回策略文档本身,不再有外层的包装字段。
内容的提问来源于stack exchange,提问作者user2681304
相关产品推荐
相关产品推荐

