Tích Hợp Keycloak Bảo Mật Ứng Dụng Java Spring Boot

Trong kiến trúc Microservices hiện đại, việc quản trị định danh và truy cập (IAM) tập trung là yêu cầu bắt buộc để đảm bảo tính bảo mật và khả năng mở rộng. Thay vì tự xây dựng hệ thống Auth phức tạp, chúng ta sẽ sử dụng Keycloak — một giải pháp mã nguồn mở mạnh mẽ dựa trên các tiêu chuẩn OIDC và OAuth 2.0.
1. Chuẩn Bị Hạ Tầng Với Docker Compose
Để đảm bảo tính bền vững (Persistence) và nhất quán dữ liệu (ACID), chúng ta sẽ chạy Keycloak cùng với PostgreSQL thay vì sử dụng cơ sở dữ liệu in-memory mặc định.
Tệp tin docker-compose.yml:
YAML
version: '3.8'
services:
postgres_db:
image: postgres:15
environment:
POSTGRES_DB: keycloak_db
POSTGRES_USER: admin
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
keycloak:
image: quay.io/keycloak/keycloak:latest
command: start-dev
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres_db:5432/keycloak_db
KC_DB_USERNAME: admin
KC_DB_PASSWORD: password
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
ports:
- "8080:8080"
depends_on:
- postgres_db
volumes:
postgres_data:
2. Cấu Hình Keycloak Admin Console
Sau khi khởi chạy bằng lệnh docker-compose up -d, hãy truy cập http://localhost:8080/admin:
Tạo Realm: Tạo một Realm mới (ví dụ:
phucbui2it-realm) để cô lập môi trường ứng dụng.Tạo Client: * Client ID:
springboot-app.Capability Config: Bật
Client authenticationnếu ứng dụng là Backend (Confidential).
Tạo Roles & Users:
Tạo Role:
ROLE_USER,ROLE_ADMIN.Tạo User và gán Role tương ứng trong tab Role Mappings.
3. Tích Hợp Vào Ứng Dụng Spring Boot
Chúng ta sẽ biến Spring Boot API thành một OAuth2 Resource Server. Điều này có nghĩa là ứng dụng sẽ không trực tiếp yêu cầu username/password mà chỉ kiểm tra tính hợp lệ của JWT (JSON Web Token) do Keycloak cấp phát.
A. Dependencies (Maven)
Sử dụng thư viện chuẩn của Spring Security để đảm bảo tính hiện đại và ổn định:
XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
B. Cấu Hình application.yml
Ứng dụng cần biết địa chỉ của Keycloak để tự động tải Public Key nhằm xác thực chữ ký số ($Digital Signature$) của Token.
YAML
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8080/realms/phucbui2it-realm
4. Xử Lý Phân Quyền (Custom Role Converter)
Keycloak lưu trữ vai trò người dùng trong claim realm_access. Chúng ta cần một Converter để Spring Security có thể đọc được các vai trò này.
Java
public class KeycloakRoleConverter implements Converter<Jwt, Collection<GrantedAuthority>> {
@Override
public Collection<GrantedAuthority> convert(Jwt jwt) {
Map<String, Object> realmAccess = (Map<String, Object>) jwt.getClaims().get("realm_access");
if (realmAccess == null || realmAccess.isEmpty()) return List.of();
return ((List<String>) realmAccess.get("roles")).stream()
.map(roleName -> new SimpleGrantedAuthority("ROLE_" + roleName))
.collect(Collectors.toList());
}
}
5. Security Configuration & Controller
Thiết lập bộ lọc bảo mật để áp dụng Converter và kiểm soát các endpoint.
SecurityConfig.java:
Java
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/public/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter()))
);
return http.build();
}
private JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(new KeycloakRoleConverter());
return converter;
}
}
Controller Kiểm Thử:
Java
@RestController
@RequestMapping("/api")
public class TestController {
@GetMapping("/admin")
@PreAuthorize("hasRole('ADMIN')")
public String adminAccess() { return "Chào Admin của ndthuy!"; }
}
Tổng Kết
Bằng cách tích hợp Keycloak, ứng dụng Java của bạn giờ đây đã đạt được trạng thái Stateless hoàn toàn. Mọi gánh nặng về quản lý mật khẩu, mã hóa, và phiên đăng nhập đều được chuyển giao cho Keycloak xử lý, giúp mã nguồn ứng dụng trở nên sạch sẽ và an toàn hơn theo đúng chuẩn System Architecture hiện đại.