You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 09:15:28