如何使用Midway Auth实现Spring Boot与API Gateway的认证集成?
Spring Boot + AWS API Gateway + Midway Auth 集成分步指南
注:由于Midway Auth公开资料较少,以下示例基于OAuth2标准流程及常见的Midway Auth集成逻辑编写,若实际API有差异,需根据官方文档调整。
一、基础依赖与配置
首先在Spring Boot项目的pom.xml中添加Midway Auth的核心依赖(若为官方Maven仓库可获取的包):
<dependency> <groupId>com.midway</groupId> <artifactId>midway-auth-spring-boot-starter</artifactId> <version>最新版本号</version> </dependency>
在application.yml中配置Midway Auth核心参数:
midway: auth: client-id: your-client-id client-secret: your-client-secret token-endpoint: https://your-midway-auth-server/oauth2/token user-info-endpoint: https://your-midway-auth-server/oauth2/userinfo scope: openid profile email
二、Spring Boot 中实现Midway Auth认证流程
1. 自定义认证过滤器
编写过滤器处理用户登录请求,调用Midway Auth获取访问令牌:
@Component public class MidwayAuthFilter extends OncePerRequestFilter { @Autowired private RestTemplate restTemplate; @Value("${midway.auth.client-id}") private String clientId; @Value("${midway.auth.client-secret}") private String clientSecret; @Value("${midway.auth.token-endpoint}") private String tokenEndpoint; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 从请求中获取用户名密码(示例为表单登录,可根据实际场景调整) String username = request.getParameter("username"); String password = request.getParameter("password"); if (username != null && password != null) { // 构建令牌请求参数 MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); params.add("grant_type", "password"); params.add("username", username); params.add("password", password); params.add("client_id", clientId); params.add("client_secret", clientSecret); // 调用Midway Auth获取令牌 ResponseEntity<MidwayTokenResponse> tokenResponse = restTemplate.postForEntity( tokenEndpoint, params, MidwayTokenResponse.class ); if (tokenResponse.getStatusCode().is2xxSuccessful()) { MidwayTokenResponse token = tokenResponse.getBody(); // 将令牌存入请求属性,供后续请求使用 request.setAttribute("midway_access_token", token.getAccessToken()); // 解析用户信息并注入SecurityContext UserDetails userDetails = fetchUserInfo(token.getAccessToken()); SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities())); } else { response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "认证失败"); return; } } filterChain.doFilter(request, response); } private UserDetails fetchUserInfo(String accessToken) { // 调用Midway Auth用户信息端点获取详情 HttpHeaders headers = new HttpHeaders(); headers.setBearerAuth(accessToken); HttpEntity<Void> entity = new HttpEntity<>(headers); ResponseEntity<MidwayUserInfo> userInfoResponse = restTemplate.exchange( "${midway.auth.user-info-endpoint}", HttpMethod.GET, entity, MidwayUserInfo.class ); MidwayUserInfo userInfo = userInfoResponse.getBody(); // 转换为Spring Security标准UserDetails对象 return User.withUsername(userInfo.getUsername()) .password("") // 密码由Midway Auth管理,本地无需存储 .authorities(Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))) .build(); } } // 令牌响应实体类 class MidwayTokenResponse { private String accessToken; private String refreshToken; private Long expiresIn; private String tokenType; // Getters & Setters } // 用户信息实体类 class MidwayUserInfo { private String username; private String email; private String[] roles; // Getters & Setters }
2. 配置Spring Security
将自定义过滤器加入Spring Security过滤链:
@Configuration @EnableWebSecurity public class SecurityConfig { @Autowired private MidwayAuthFilter midwayAuthFilter; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .csrf().disable() .authorizeHttpRequests(auth -> auth .requestMatchers("/login").permitAll() .anyRequest().authenticated() ) .addFilterBefore(midwayAuthFilter, UsernamePasswordAuthenticationFilter.class); return http.build(); } @Bean public RestTemplate restTemplate() { return new RestTemplate(); } }
三、传递令牌到AWS API Gateway与Lambda
1. Spring Boot中携带令牌调用API Gateway
在请求中把Midway Auth生成的令牌放入Authorization请求头:
@Service public class ApiGatewayClient { @Autowired private RestTemplate restTemplate; public String callLambdaThroughApiGateway(String accessToken, String apiGatewayUrl) { HttpHeaders headers = new HttpHeaders(); headers.setBearerAuth(accessToken); HttpEntity<Void> entity = new HttpEntity<>(headers); ResponseEntity<String> response = restTemplate.exchange( apiGatewayUrl, HttpMethod.GET, entity, String.class ); return response.getBody(); } }
2. AWS API Gateway配置
- 创建自定义令牌授权器,类型选择
Token,授权器端点指向Midway Auth的令牌校验接口(或自定义校验Lambda) - 配置授权器缓存,减少重复校验请求
- 将授权器绑定到需要保护的API资源上
3. Lambda端令牌校验(Java示例)
若选择在Lambda中直接校验令牌,可编写如下逻辑:
public class TokenValidationHandler implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> { private static final String MIDWAY_AUTH_VALIDATE_ENDPOINT = "https://your-midway-auth-server/oauth2/introspect"; private static final String CLIENT_ID = "your-client-id"; private static final String CLIENT_SECRET = "your-client-secret"; @Override public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent input, Context context) { APIGatewayProxyResponseEvent response = new APIGatewayProxyResponseEvent(); String authHeader = input.getHeaders().get("Authorization"); if (authHeader == null || !authHeader.startsWith("Bearer ")) { response.setStatusCode(401); response.setBody("Missing or invalid Authorization header"); return response; } String accessToken = authHeader.substring(7); boolean isValid = validateToken(accessToken); if (!isValid) { response.setStatusCode(403); response.setBody("Invalid access token"); return response; } // 令牌有效,执行业务逻辑 response.setStatusCode(200); response.setBody("Success"); return response; } private boolean validateToken(String accessToken) { RestTemplate restTemplate = new RestTemplate(); MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); params.add("token", accessToken); params.add("client_id", CLIENT_ID); params.add("client_secret", CLIENT_SECRET); ResponseEntity<Map> validationResponse = restTemplate.postForEntity( MIDWAY_AUTH_VALIDATE_ENDPOINT, params, Map.class ); return validationResponse.getStatusCode().is2xxSuccessful() && (boolean) validationResponse.getBody().get("active"); } }
四、常见问题处理
- 令牌过期:在Spring Boot中实现令牌刷新逻辑,使用
refresh_token调用Midway Auth获取新的access_token - 跨域问题:配置Spring Boot的CorsFilter,允许API Gateway域名访问
- 权限校验:结合Midway Auth返回的用户角色,在Spring Security和Lambda中实现细粒度权限控制
内容的提问来源于stack exchange,提问作者tushar khot
相关产品推荐
相关产品推荐

