🧭 はじめに
マイクロサービス構成では、各サービスに個別で認証を実装するのは非効率です。そこで登場するのが API Gatewayでの認証集中管理。Spring Cloud Gatewayは、OAuth2 や JWT を使った認証を統合することでセキュアなAPIアクセスを実現する方法を解説します。
🧩 システム構成図
⚙️ Keycloakの設定
1. RealmとClientの作成
- Realm:
demo-realm
- Client:
spring-gateway-client
- Access Type:
confidential
- Valid Redirect URIs:
http://localhost:8080/login/oauth2/code/keycloak
- Web Origins:
*
- Access Type:
2. ユーザー作成
- ユーザー名:
demo-user
- パスワード:
password
- ロール:
USER
🛠️ Spring Cloud GatewayのOAuth2設定
application.yml
spring:
security:
oauth2:
client:
registration:
keycloak:
client-id: spring-gateway-client
client-secret: <your-client-secret>
authorization-grant-type: authorization_code
redirect-uri: "{baseUrl}/login/oauth2/code/keycloak"
scope: openid
provider:
keycloak:
issuer-uri: http://localhost:8080/realms/demo-realm
cloud:
gateway:
routes:
- id: secured-route
uri: http://localhost:8081
predicates:
- Path=/api/**
filters:
- JwtAuthenticationFilter
🧪 JWT認証フィルターの作成
JwtAuthenticationFilter.java
public class JwtAuthenticationFilter extends AbstractGatewayFilterFactory<JwtAuthenticationFilter.Config> {
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String authHeader = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
String token = authHeader.substring(7);
try {
Claims claims = Jwts.parser()
.setSigningKey(Keys.hmacShaKeyFor("your-signing-key".getBytes()))
.parseClaimsJws(token)
.getBody();
exchange.getRequest().mutate()
.header("X-User-Id", claims.getSubject())
.header("X-User-Roles", claims.get("roles", String.class))
.build();
return chain.filter(exchange);
} catch (JwtException e) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
};
}
public static class Config {}
}
👤 認証後のユーザー情報取得
バックエンドサービスでは、Gatewayが付加したヘッダーからユーザー情報を取得できます。
例:Spring Boot Controller
@GetMapping("/api/userinfo")
public ResponseEntity<Map<String, String>> getUserInfo(@RequestHeader("X-User-Id") String userId,
@RequestHeader("X-User-Roles") String roles) {
Map<String, String> userInfo = new HashMap<>();
userInfo.put("userId", userId);
userInfo.put("roles", roles);
return ResponseEntity.ok(userInfo);
}
✅ まとめ
Spring Cloud GatewayとKeycloakを組み合わせることで、OAuth2 + JWTによる堅牢な認証機構を構築できます。次回は、Rate Limitingの実装について紹介予定です。