# Spring Boot 연동

### 개요

Spring Boot 애플리케이션에서 Keycloak을 사용하면 쉽고 안전하게 인증·인가를 처리할 수 있다. Spring Boot가 제공하는 자동 구성과 Keycloak이 제공하는 Spring Security 어댑터를 결합하여, 최소한의 설정만으로도 소셜 로그인이나 기업 인증 환경을 구성할 수 있다. 이 절에서는 Keycloak 서버와 Spring Boot 애플리케이션을 연동하기 위한 전반적인 절차와 예시 코드를 살펴본다.

### 사전 준비

* Keycloak 서버를 설치 및 구동한다. (기본 포트: 8080)
* Keycloak에서 Realm을 생성한다. 예: `MyRealm`
* Spring Boot 애플리케이션(Gradle 또는 Maven 기반)을 생성한다.

### Keycloak 설정

1. **Realm 생성** Keycloak 관리자 콘솔에서 `MyRealm`을 생성한다.
2. **Client 생성**
   * `Clients` 메뉴에서 새 Client를 생성한다. 예: `spring-boot-app`
   * ```
     Access Type

     ```

     을

     public

     또는

     confidential

     로 설정한다.

     * **confidential**을 사용하는 경우, `Credentials` 탭에서 생성되는 `Secret`을 Spring Boot 측 설정 파일에 함께 기입해야 한다.
   * `Valid Redirect URIs`에 Spring Boot 애플리케이션의 콜백 URL을 등록한다. 예: `http://localhost:8081/*`
3. **사용자·역할 설정**
   * `Users` 메뉴에서 테스트 사용자 계정을 생성한다.
   * `Roles` 메뉴에서 필요한 역할(예: `USER`, `ADMIN`)을 생성하고, 생성된 사용자에게 해당 역할을 부여한다.

### 프로젝트 설정

#### 의존성 추가

Maven을 사용하는 경우, `pom.xml`에 Keycloak Spring Boot 스타터를 추가한다.

```xml

<dependencies>
    <!-- ... 다른 의존성 ... -->
    <dependency>
        <groupId>org.keycloak</groupId>
        <artifactId>keycloak-spring-boot-starter</artifactId>
        <version>21.1.1</version> <!-- 실제 프로젝트에 맞춰 조정 -->
    </dependency>
</dependencies>

```

Gradle을 사용하는 경우, `build.gradle`에 다음을 추가한다.

```groovy

dependencies {
    // ... 다른 의존성 ...
    implementation 'org.keycloak:keycloak-spring-boot-starter:21.1.1'
}

```

#### 설정 파일

Spring Boot 2.0 이상 버전에서 Keycloak 연동 시, `application.yml` 또는 `application.properties`를 통해 인증 서버 URL, Realm, Client 정보 등을 설정할 수 있다.

**application.yml 예시**:

```yaml

server:
  port: 8081

keycloak:
  realm: MyRealm
  auth-server-url: http://localhost:8080/auth
  resource: spring-boot-app
  public-client: true
  bearer-only: false
  # confidential Client인 경우, secret 설정 필요
  # credentials:
  #   secret: <Client Secret>

```

* `realm`: Keycloak에서 생성한 Realm 이름
* `auth-server-url`: Keycloak 서버 주소(기본값: `http://localhost:8080/auth`)
* `resource`: Client ID (예: `spring-boot-app`)
* `public-client`: Client Access Type이 public인 경우 `true`, confidential인 경우 `false`로 설정
* `bearer-only`: 토큰 기반 API 서버로만 사용하려면 `true`, 일반 웹 애플리케이션처럼 동작하게 하려면 `false`

### Spring Security 구성

#### KeycloakSpringBootConfigResolver

Keycloak Spring Boot Starter를 사용할 때는 `KeycloakConfigResolver`를 직접 구현하거나, Keycloak이 제공하는 `KeycloakSpringBootConfigResolver`를 빈으로 등록할 수 있다. 대부분의 경우 제공되는 `KeycloakSpringBootConfigResolver`를 그대로 사용하면 된다.

```java

@Configuration
public class KeycloakConfig {
    @Bean
    public KeycloakSpringBootConfigResolver keycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }
}

```

#### Web Security 설정

Keycloak이 제공하는 `KeycloakWebSecurityConfigurerAdapter`(Spring Boot 2.x 기준)를 상속받아 Spring Security를 구성한다. Spring Boot 3.x에서는 Spring Security 6를 사용하면서 API가 변경되었으므로, 버전에 따라 구성이 달라질 수 있다. 아래 예시 코드는 Spring Boot 2.x를 기준으로 한다.

```java

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    /**
     * Keycloak 인증 프로바이더를 등록한다.
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) {
        KeycloakAuthenticationProvider keycloakAuthenticationProvider =
            keycloakAuthenticationProvider();
        // 권한 맵핑 전략 설정(ROLE_ 접두어 사용)
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(
            new SimpleAuthorityMapper());
        auth.authenticationProvider(keycloakAuthenticationProvider);
    }

    /**
     * 세션 관리를 위해 KeycloakSecurityContext를 사용하도록 설정한다.
     */
    @Bean
    @Override
    protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
        return new RegisterSessionAuthenticationStrategy(
            new SessionRegistryImpl());
    }

    /**
     * Keycloak 필터 체인을 Spring Security 필터 체인에 등록한다.
     */
    @Bean
    @Override
    protected KeycloakSecurityContextRepository keycloakSecurityContextRepository() {
        return new KeycloakSecurityContextRepository();
    }

    /**
     * Security 정책 정의
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http); // Keycloak 필터 등록
        http
            .authorizeRequests()
            .antMatchers("/public/**").permitAll()
            .anyRequest().authenticated();
    }
}

```

#### Spring Boot 3.x 및 Spring Security 6 환경

Spring Boot 3.x 이상에서는 `KeycloakWebSecurityConfigurerAdapter` 지원이 종료되었으므로, Security 설정을 Java Config로 직접 구성해야 한다. 예를 들어 다음과 같이 `SecurityFilterChain`을 Bean으로 등록하여 Keycloak 필터와 인증 매니저를 설정한다.

```java

@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {

    @Bean
    KeycloakSpringBootConfigResolver keycloakConfigResolver() {
        return new KeycloakSpringBootConfigResolver();
    }

    @Bean
    KeycloakSecurityContextRepository keycloakSecurityContextRepository() {
        return new KeycloakSecurityContextRepository();
    }

    @Bean
    SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // Keycloak 필터 등록
        KeycloakAuthenticationProvider keycloakAuthenticationProvider = new KeycloakAuthenticationProvider();
        keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());

        http
            .csrf().disable()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .securityContext()
            .securityContextRepository(keycloakSecurityContextRepository())
            .and()
            .authorizeHttpRequests()
            .requestMatchers("/public/**").permitAll()
            .anyRequest().authenticated()
            .and()
            .oauth2ResourceServer()
            .jwt(); // Access Token 검사

        return http.build();
    }

    @Bean
    AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) 
        throws Exception {
        return authenticationConfiguration.getAuthenticationManager();
    }
}

```

Keycloak에서 발급한 JWT를 직접 검증하기 위해 Spring Security의 `oauth2ResourceServer().jwt()` 구성을 사용할 수 있다. 이때, Keycloak 서버의 OpenID Connect Discovery 문서를 통해 JWK 세팅을 자동으로 처리할 수도 있다.

### 동작 확인

1. Spring Boot 애플리케이션을 구동한다. (`http://localhost:8081`)
2. 브라우저에서 인증이 필요한 URL에 접근한다. (예: `/secured`)
3. 로그인 페이지가 표시되면 Keycloak 로그인 페이지로 리디렉션된다.
4. 앞서 생성했던 사용자의 아이디와 비밀번호로 로그인하면, Spring Boot 애플리케이션에서 인증된 상태로 페이지를 확인할 수 있다.

***

Keycloak과 Spring Boot를 연동하면, 비교적 적은 설정으로도 OAuth2/OIDC 기반 인증·인가 기능을 구현할 수 있다. 버전에 따라 Spring Security 설정 방식이 달라지므로, 사용하는 Spring Boot와 Keycloak 버전에 맞게 WebSecurity 설정 클래스를 작성하고, Keycloak 서버의 Realm·Client 정보를 정확히 일치시키는 것이 중요하다. 이를 통해 기업 내부 시스템, 웹 서비스, 또는 마이크로서비스 환경에서 안전하고 일관성 있는 인증·인가 전략을 수립할 수 있다.
