contexa-identity

Identity DSL

Identity DSL은 전체 인증 플랫폼을 설정하기 위한 플루언트, 타입 세이프 Java API입니다. 인증 방법, 상태 관리, Spring Security 설정을 단일 PlatformSecurityConfig 클래스에서 정의합니다.

빠른 시작

가장 간단한 설정 -- 세션 기반 상태의 폼 로그인:

Java
@Configuration
@EnableWebSecurity
public class PlatformSecurityConfig {

    @Bean
    public PlatformConfig platformDslConfig(
            IdentityDslRegistry<HttpSecurity> registry) throws Exception {
        return registry
            .form(form -> form.loginPage("/login").defaultSuccessUrl("/home"))
            .session(Customizer.withDefaults())
            .build();
    }
}

왜 Contexa DSL인가?

Spring Security는 모든 SecurityFilterChain에 대해 별도의 @Bean 메서드가 필요합니다. 3개의 로그인 페이지는 반복되는 보일러플레이트를 가진 3개의 메서드를 의미합니다. Contexa의 Identity DSL은 이를 크게 줄여 하나의 플루언트 체인과 하나의 메서드에서 여러 Filter Chain 구성을 조립할 수 있게 합니다.

Spring Security: 3개의 Filter Chain

Java
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean @Order(1)
    public SecurityFilterChain adminChain(HttpSecurity http) throws Exception {
        return http
            .securityMatcher("/admin/**")
            .csrf(AbstractHttpConfigurer::disable)
            .formLogin(form -> form.loginPage("/admin/login").defaultSuccessUrl("/admin"))
            .sessionManagement(session -> session.sessionFixation().changeSessionId())
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .build();
    }

    @Bean @Order(2)
    public SecurityFilterChain apiChain(HttpSecurity http) throws Exception {
        return http
            .securityMatcher("/api/**")
            .csrf(AbstractHttpConfigurer::disable)
            .formLogin(form -> form.loginPage("/api/login").defaultSuccessUrl("/api"))
            .sessionManagement(session -> session.sessionFixation().changeSessionId())
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .build();
    }

    @Bean @Order(3)
    public SecurityFilterChain userChain(HttpSecurity http) throws Exception {
        return http
            .csrf(AbstractHttpConfigurer::disable)
            .formLogin(form -> form.loginPage("/login").defaultSuccessUrl("/home"))
            .sessionManagement(session -> session.sessionFixation().changeSessionId())
            .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
            .build();
    }
}
// 3개의 @Bean 메서드, ~40줄, 체인마다 반복되는 보일러플레이트

Contexa Identity DSL: 동일한 결과

Java
@Bean
public PlatformConfig platformDslConfig(
        IdentityDslRegistry<HttpSecurity> registry) throws Exception {
    return registry
        .global(http -> {
            http.csrf(AbstractHttpConfigurer::disable)
                .sessionManagement(session -> session.sessionFixation().changeSessionId())
                .authorizeHttpRequests(auth -> auth.anyRequest().authenticated());
        })
        .form(f -> f.order(10).loginPage("/admin/login").defaultSuccessUrl("/admin")
            .rawHttp(http -> http.securityMatcher("/admin/**")))
        .session(Customizer.withDefaults())
        .form(f -> f.order(20).loginPage("/api/login").defaultSuccessUrl("/api")
            .rawHttp(http -> http.securityMatcher("/api/**")))
        .session(Customizer.withDefaults())
        .form(f -> f.order(30).loginPage("/login").defaultSuccessUrl("/home"))
        .session(Customizer.withDefaults())
        .build();
}
// 1개 메서드, ~15줄, 보일러플레이트를 크게 줄이고 런타임에 3개의 SecurityFilterChain 빈 등록
플루언트 체이닝
.form().session().form().session().build() -- 하나의 플루언트 체인이 자동으로 여러 Filter Chain을 생성
동적 빈 등록
SecurityFilterChainRegistrarBeanDefinitionRegistry를 통해 런타임에 SecurityFilterChain 빈을 등록
인증 + 상태 분리
모든 인증 방법이 모든 상태(.session() 또는 .oauth2())와 결합 가능. Spring Security는 세션 전용으로 제한됨.

DSL 아키텍처

DSL은 2단계 체인 빌더 패턴을 따릅니다. 각 .auth().state() 쌍이 독립적인 SecurityFilterChain을 생성하며, 우선순위에 따라 정렬됩니다.

2단계 빌더 패턴

IdentityDslRegistry
진입점
.global()
공유 HttpSecurity 설정
인증 단계
form / rest / ott / passkey / mfa
상태 단계
session / oauth2
.build()
PlatformConfig

하나의 Registry에서 다중 Chain

.auth().state() 쌍이 별도의 SecurityFilterChain을 생성합니다. Registry가 모든 쌍을 수집하고 SecurityFilterChainRegistrar가 런타임에 Spring 빈으로 등록합니다.

IdentityDslRegistry
.global(http -> { /* 공유 CSRF, 인가, 컨텍스트 */ })
Chain 1 (order: 20)
.form()
loginPage("/admin/login")
.oauth2()
SecurityFilterChain
/admin/**
Chain 2 (order: 50)
.rest()
loginProcessingUrl("/api/auth")
.oauth2()
SecurityFilterChain
/api/**
Chain 3 (order: 100)
.mfa()
formLogin + passkey
.session()
SecurityFilterChain
/** (catch-all)

각 체인은 자체 필터, 인증 전략 및 상태 관리로 격리됩니다. 요청은 order()securityMatcher에 의해 라우팅됩니다 -- 첫 번째 매칭 체인이 요청을 처리합니다.

동작 원리: 동적 빈 등록

PlatformConfig를 반환하는 하나의 @Bean 메서드를 작성합니다. Contexa의 부트스트랩 파이프라인이 이를 읽고 자동으로 여러 SecurityFilterChain 빈을 등록합니다 -- 추가 @Bean 어노테이션이 필요 없습니다.

작성하는 것 vs. Spring이 보는 것

작성하는 것
1개의 @Bean 메서드
PlatformConfig 반환
부트스트랩 파이프라인
Contexa가 생성
N개의 SecurityFilterChain
런타임에 등록
Spring이 보는 것
Spring Context
formSecurityFilterChain1
restSecurityFilterChain2
ottSecurityFilterChain3

부트스트랩 파이프라인

1
PlatformConfig 빌드
FlowConfig #1
form + session
order=10, matcher=/admin/**
FlowConfig #2
rest + oauth2
order=20, matcher=/api/**
FlowConfig #3
ott + session
order=30, matcher=/**
2
Flow별 HttpSecurity 생성
HttpSecurity #1
격리된 컨텍스트
독립 필터
HttpSecurity #2
격리된 컨텍스트
독립 필터
HttpSecurity #3
격리된 컨텍스트
독립 필터
3
설정 적용
global() + form()
CSRF, 세션 고정,
로그인 페이지, 필터
global() + rest()
CSRF, 토큰 검증,
bearer 필터
global() + ott()
CSRF, OTT 생성,
매직 링크 필터
4
Spring 빈으로 등록
formSecurityFilterChain1
OrderedSecurityFilterChain
order=10
restSecurityFilterChain2
OrderedSecurityFilterChain
order=20
ottSecurityFilterChain3
OrderedSecurityFilterChain
order=30
핵심 인사이트: SecurityFilterChainRegistrar는 Spring의 BeanDefinitionRegistry에 직접 접근합니다. PlatformConfig를 반환하는 하나의 @Bean 메서드를 작성하면, Spring은 각각에 대해 별도의 @Bean 메서드를 작성한 것과 정확히 동일하게 여러 SecurityFilterChain 빈을 인식합니다.

글로벌 설정

global()은 공유 HTTP 보안 설정을 모든 Filter Chain에 적용합니다. 개별 인증 방법 설정은 충돌 시 글로벌 설정을 오버라이드합니다 (SecurityConfigurerOrchestrator가 글로벌을 먼저 적용한 후 플로우별 설정을 적용).

Java
registry
    .global(http -> {
        http
            .csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(authReq -> authReq
                .requestMatchers("/css/**", "/js/**", "/images/**").permitAll()
                .anyRequest().access(customAuthorizationManager))
            .securityContext(sc ->
                sc.securityContextRepository(customRepository));
    })
    // ... 인증 방법이 이어짐

오버라이드 규칙: 글로벌 설정기가 먼저 실행되고, 각 플로우의 자체 설정기가 실행됩니다. 플로우가 disableCsrf() 또는 rawHttp()를 설정하면, 해당 특정 체인에 대해서만 글로벌 CSRF 설정이 오버라이드됩니다.

Filter Chain 순서 & 요청 라우팅

각 인증 방법에는 기본 order() 값이 있습니다. 낮은 order = 높은 우선순위 = 먼저 요청을 가로챕니다. 여러 Filter Chain이 등록되면 Spring Security는 순서대로 평가하고 securityMatcher가 요청과 매칭되는 첫 번째 체인을 사용합니다.

인증 방법기본 Order설명
Form Login100기존 폼 기반 로그인
MFA200다중 인증
REST API200JSON 자격 증명 제출
One-Time Token300매직 링크 / OTT
Passkey400WebAuthn / FIDO2

order()rawHttp(http -> http.securityMatcher(...))를 사용하여 어떤 체인이 어떤 요청을 처리할지 제어합니다:

Java
registry
    .global(http -> { /* 공유 설정 */ })
    // 관리자 페이지: Form 로그인, order 20 (최고 우선순위)
    .form(f -> f.order(20).loginPage("/admin/login")
        .rawHttp(http -> http.securityMatcher("/admin/**")))
    .session(Customizer.withDefaults())
    // API 엔드포인트: REST 로그인, order 50
    .rest(r -> r.order(50).loginProcessingUrl("/api/auth")
        .rawHttp(http -> http.securityMatcher("/api/**")))
    .oauth2(Customizer.withDefaults())
    // 일반 사용자: MFA, order 100
    .mfa(m -> m.order(100)
        .primaryAuthentication(p -> p.formLogin(form -> form.loginPage("/login")))
        .passkey(Customizer.withDefaults()))
    .session(Customizer.withDefaults())
    .build();

securityMatcher 없이는 체인이 모든 요청에 매칭됩니다. 여러 체인을 사용할 때는 겹침을 방지하기 위해 항상 rawHttp()를 통해 securityMatcher를 설정하세요.

인증 + 상태 조합

모든 인증 방법은 세션 또는 OAuth2 상태와 결합할 수 있습니다. 서로 다른 체인에 걸쳐 다른 상태 전략을 혼합할 수 있습니다.

인증 방법+ Session+ OAuth2
Form Login.form(...).session(...).form(...).oauth2(...)
REST API.rest(...).session(...).rest(...).oauth2(...)
One-Time Token.ott(...).session(...).ott(...).oauth2(...)
Passkey.passkey(...).session(...).passkey(...).oauth2(...)
MFA.mfa(...).session(...).mfa(...).oauth2(...)

플로우별 상태: .state() 호출은 가장 최근에 등록된 인증 방법에 적용됩니다. 이를 통해 체인별로 다른 상태 전략을 사용할 수 있습니다:

Java
registry
    .form(f -> f.loginPage("/login"))
    .session(Customizer.withDefaults())      // form -> Session
    .rest(r -> r.loginProcessingUrl("/api/auth"))
    .oauth2(Customizer.withDefaults())       // rest -> OAuth2
    .mfa(m -> m.primaryAuthentication(...).passkey(...))
    .session(Customizer.withDefaults())      // mfa -> Session
    .build();

동일한 인증 방법을 여러 번 등록할 수 있습니다 (자동 명명: form_flow, form_flow_2 등).

Spring Security: 세션 전용

Spring Security의 formLogin()은 세션 기반 상태 관리에 고정되어 있습니다. 토큰 기반 인증을 위해서는 oauth2ResourceServer()로 완전히 별도의 SecurityFilterChain을 수동으로 설정해야 합니다.

Java
// Spring Security: 세션 상태가 암묵적, 체인별 전환 불가
http.formLogin(form -> form.loginPage("/login"));
// 항상 세션 기반. 변경 불가.

// 토큰 기반 인증을 위해서는 완전히 별도의 체인이 필요:
@Bean
public SecurityFilterChain resourceServerChain(HttpSecurity http) throws Exception {
    return http
        .securityMatcher("/api/**")
        .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
        .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .build();
}
// 두 가지 다른 패러다임, 두 가지 다른 설정, 통합 없음

Contexa DSL: 모든 인증 x 모든 상태

Contexa는 인증과 상태 관리를 분리합니다. 동일한 .form()이 한 체인에서는 .session()을, 다른 체인에서는 .oauth2()를 사용할 수 있습니다 -- 단일 메서드에서.

Java
registry
    // 관리자: OAuth2 토큰 상태의 폼 로그인
    .form(f -> f.order(20).loginPage("/admin/login")
        .rawHttp(http -> http.securityMatcher("/admin/**")))
    .oauth2(Customizer.withDefaults())

    // API: OAuth2 토큰 상태의 REST 로그인 (Stateless)
    .rest(r -> r.order(50).loginProcessingUrl("/api/auth")
        .rawHttp(http -> http.securityMatcher("/api/**")))
    .oauth2(Customizer.withDefaults())

    // 사용자: 세션 상태의 MFA
    .mfa(m -> m.order(100)
        .primaryAuthentication(auth -> auth.formLogin(form -> form.loginPage("/login")))
        .passkey(Customizer.withDefaults()))
    .session(Customizer.withDefaults())
    .build();
// 5가지 인증 방법 x 2가지 상태 유형 = 10가지 조합, 모두 하나의 메서드에서
모든 인증 x 모든 상태: Contexa는 인증과 상태를 직교적 관심사로 취급합니다. 세션이 있는 폼 로그인, OAuth2가 있는 폼 로그인, 세션이 있는 REST, OAuth2가 있는 MFA -- 모든 조합이 가능합니다. 이는 전체 설정 클래스를 복제하지 않고는 바닐라 Spring Security에서 아키텍처적으로 불가능합니다.

rawHttp() -- 전체 Spring Security 접근

rawHttp()전체 Spring Security HttpSecurity API를 노출하는 SafeHttpCustomizer<HttpSecurity> 훅을 제공합니다. 체크 예외를 지원하며 여러 번 호출할 수 있습니다 (각 호출이 누적됨).

Java
.form(f -> f.order(20)
    .rawHttp(http -> http
        .securityMatcher("/admin/**")
        .sessionManagement(session ->
            session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
        .addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class))
    .rawHttp(http -> http
        .headers(headers -> headers.frameOptions(fo -> fo.deny())))
)

모든 인증 방법과 global()에서 사용 가능합니다. 폼 로그인의 경우 HttpSecurity.formLogin() 내부를 직접 커스터마이즈하는 rawFormLogin()도 있습니다.

SecurityFilterChain 커스터마이제이션

globalHttpCustomizer 람다는 HttpSecurity 빌더를 수신하여 Spring Security의 설정 API에 대한 완전한 접근을 제공합니다. 아래는 일반적인 커스터마이제이션 포인트입니다.

CSRF 설정

기본 설정은 CSRF를 비활성화합니다. HTML 폼을 서빙하는 애플리케이션의 경우 쿠키 기반 토큰 리포지토리와 함께 CSRF를 활성화하는 것을 고려하세요:

Java
// CSRF 비활성화 (기본값 - Stateless API에 적합)
http.csrf(AbstractHttpConfigurer::disable);

// 쿠키 리포지토리로 CSRF 활성화 (HTML 폼 애플리케이션용)
http.csrf(csrf -> csrf
    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
);

AISessionSecurityContextRepository를 사용한 세션 관리

AISessionSecurityContextRepository는 Spring의 HttpSessionSecurityContextRepository를 AI 강화 세션 추적으로 확장합니다. 행동 데이터(세션 패턴, 접근 빈도, 이상 점수)를 인가 파이프라인에 제공합니다.

Java
// AI 세션 컨텍스트를 보안 Filter Chain에 연결
http.securityContext(sc ->
    sc.securityContextRepository(aiSessionSecurityContextRepository)
);

// Stateless REST API의 경우, form/rest 체인 설정에서
// Stateless 세션 관리를 사용:
registry.form(form -> form
    .order(20)
    .loginPage("/admin/login")
    .defaultSuccessUrl("/admin")
    .rawHttp(http -> http.sessionManagement(session ->
        session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)))
);

CORS 설정

Java
SafeHttpCustomizer<HttpSecurity> globalHttpCustomizer = http -> {
    http
        .cors(cors -> cors.configurationSource(request -> {
            CorsConfiguration config = new CorsConfiguration();
            config.setAllowedOrigins(List.of("https://app.example.com"));
            config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
            config.setAllowCredentials(true);
            return config;
        }))
        .csrf(AbstractHttpConfigurer::disable)
        .authorizeHttpRequests(authReq -> authReq
            .requestMatchers("/css/**", "/js/**", "/images/**").permitAll()
            .anyRequest().access(customDynamicAuthorizationManager)
        )
        .securityContext(sc ->
            sc.securityContextRepository(aiSessionSecurityContextRepository));
};

커스텀 필터

개별 체인 설정의 rawHttp 메서드를 사용하여 커스텀 필터를 추가하거나, 크로스 체인 적용을 위해 글로벌 커스터마이저에 포함합니다:

Java
// 인가 필터 앞에 커스텀 필터 추가
SafeHttpCustomizer<HttpSecurity> globalHttpCustomizer = http -> {
    http
        .addFilterBefore(new TenantContextFilter(),
            AuthorizationFilter.class)
        .authorizeHttpRequests(authReq -> authReq
            .anyRequest().access(customDynamicAuthorizationManager)
        );
};

공통 옵션

모든 인증 방법이 공유하는 옵션입니다 (AbstractOptions에서 제공):

옵션설명
order(int)Filter Chain 우선순위 (낮을수록 우선순위 높음)
loginProcessingUrl(String)로그인 요청을 처리하는 URL
defaultSuccessUrl(String)로그인 성공 후 리다이렉트
failureUrl(String)로그인 실패 후 리다이렉트
successHandler(PlatformAuthenticationSuccessHandler)커스텀 성공 핸들러
failureHandler(PlatformAuthenticationFailureHandler)커스텀 실패 핸들러
securityContextRepository(SecurityContextRepository)보안 컨텍스트 저장소 오버라이드
disableCsrf()이 체인의 CSRF 비활성화
cors(Customizer)CORS 설정
headers(Customizer)HTTP 헤더 설정
sessionManagement(Customizer)세션 관리 설정
logout(Customizer)로그아웃 설정
rawHttp(SafeHttpCustomizer)전체 Spring Security API 접근 (누적됨)
authorizeStaticPermitAll(String...)인증 없이 정적 리소스 허용
asep(Customizer)이 플로우의 ASEP 어노테이션 속성

완전한 예제

관리자 폼 로그인(OAuth2), 사용자 MFA(Session), API REST 엔드포인트(OAuth2)를 포함한 프로덕션 레디 설정:

Java
@Configuration
@RequiredArgsConstructor
@EnableWebSecurity
public class PlatformSecurityConfig {

    private final CustomDynamicAuthorizationManager authorizationManager;
    private final AISessionSecurityContextRepository securityContextRepository;

    @Bean
    public PlatformConfig platformDslConfig(
            IdentityDslRegistry<HttpSecurity> registry) throws Exception {

        return registry
            // 글로벌: 모든 체인에 공유
            .global(http -> {
                http
                    .csrf(AbstractHttpConfigurer::disable)
                    .authorizeHttpRequests(authReq -> authReq
                        .requestMatchers("/css/**", "/js/**", "/images/**").permitAll()
                        .anyRequest().access(authorizationManager))
                    .securityContext(sc ->
                        sc.securityContextRepository(securityContextRepository));
            })
            // 관리자: OAuth2를 사용하는 폼 로그인, 최고 우선순위
            .form(f -> f.order(20).loginPage("/admin/login")
                .defaultSuccessUrl("/admin/dashboard")
                .rawHttp(http -> http.securityMatcher("/admin/**")))
            .oauth2(Customizer.withDefaults())
            // API: OAuth2를 사용하는 REST 로그인
            .rest(r -> r.order(50).loginProcessingUrl("/api/auth")
                .rawHttp(http -> http
                    .securityMatcher("/api/**")
                    .sessionManagement(s ->
                        s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))))
            .oauth2(Customizer.withDefaults())
            // 사용자: 세션을 사용하는 MFA
            .mfa(m -> m.order(100)
                .primaryAuthentication(auth ->
                    auth.formLogin(form -> form
                        .loginPage("/login")
                        .defaultSuccessUrl("/home")))
                .passkey(Customizer.withDefaults()))
            .session(Customizer.withDefaults())
            .build();
    }
}

마이그레이션 가이드

기존 Spring Security 설정에서 Contexa의 PlatformSecurityConfig로 마이그레이션하려면 SecurityFilterChain 빈을 DSL 레지스트리 패턴으로 교체하고 동적 인가 매니저를 연결해야 합니다.

변경 전: 기존 Spring Security

Java
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(
            HttpSecurity http) throws Exception {
        return http
            .csrf(AbstractHttpConfigurer::disable)
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .requestMatchers("/api/**").hasRole("USER")
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .defaultSuccessUrl("/admin")
            )
            .build();
    }
}

변경 후: Contexa PlatformSecurityConfig

Java
@EnableWebSecurity
@RequiredArgsConstructor
public class PlatformSecurityConfig {

    private final CustomDynamicAuthorizationManager customDynamicAuthorizationManager;
    private final AISessionSecurityContextRepository aiSessionSecurityContextRepository;

    @Bean
    public PlatformConfig platformDslConfig(
            IdentityDslRegistry<HttpSecurity> registry) throws Exception {

        SafeHttpCustomizer<HttpSecurity> globalHttpCustomizer = http -> {
            http
                .csrf(AbstractHttpConfigurer::disable)
                .authorizeHttpRequests(auth -> auth
                    .requestMatchers("/css/**", "/js/**", "/images/**", "/favicon.ico")
                        .permitAll()
                    .anyRequest()
                        .access(customDynamicAuthorizationManager)
                )
                .securityContext(sc -> sc
                    .securityContextRepository(aiSessionSecurityContextRepository));
        };

        return registry
            .global(globalHttpCustomizer)
            .form(form -> form.order(20)
                .loginPage("/admin/login")
                .defaultSuccessUrl("/admin"))
            .oauth2(Customizer.withDefaults())
            .build();
    }
}

마이그레이션 단계

1
Contexa 의존성 추가
프로젝트에 spring-boot-starter-contexa를 추가합니다. 이는 contexa-iam, contexa-core, contexa-identity 모듈을 전이적으로 포함합니다.
2
리소스 스캐너 실행
리소스 스캐너를 사용하여 기존 엔드포인트를 모두 검색하고 현재의 hasRole() / hasAuthority() 규칙과 일치하는 초기 XACML 정책을 생성합니다.
3
Shadow Mode 활성화
security.zerotrust.mode=SHADOW를 설정하여 동적 인가를 감사 전용 모드로 실행합니다. 결정은 로그에 기록되지만 적용되지 않아 정책이 예상 동작과 일치하는지 확인할 수 있습니다.
4
SecurityFilterChain 교체
기존 SecurityFilterChain 빈을 PlatformConfig 패턴으로 교체합니다. 정적 permitAll() 규칙을 requestMatchers로 이동하고 모든 hasRole() / hasAuthority().anyRequest().access(customDynamicAuthorizationManager)로 교체합니다.
5
Shadow Mode에서 검증
애플리케이션을 실행하고 감사 로그를 검토하여 동적 정책이 이전 정적 규칙과 동일한 결정을 생성하는지 확인합니다. 정책 격차를 수정합니다.
6
Enforce Mode로 전환
security.zerotrust.mode=ENFORCE를 설정하여 실시간 정책 적용을 활성화합니다. 전환 기간 동안 인가 감사 로그를 면밀히 모니터링합니다.

마이그레이션 체크리스트

단계액션검증
1spring-boot-starter-contexa 의존성 추가오류 없이 애플리케이션 시작
2리소스 스캐너를 실행하여 엔드포인트 검색Policy Center의 리소스 화면에서 스캔된 리소스 확인 가능
3각 엔드포인트에 대한 XACML 정책 생성Policy Center와 관련 정책 상세 흐름에서 정책 확인 가능
4Shadow Mode 활성화 (security.zerotrust.mode=SHADOW)감사 로그에 인가 결정 표시
5SecurityFilterChainPlatformConfig로 교체모든 Filter Chain이 성공적으로 빌드
6정적 hasRole() / hasAuthority() 규칙 제거SecurityFilterChain 설정에 기존 hasRole() / hasAuthority() 요청 규칙이 남아 있지 않음
7Shadow Mode 감사 로그가 예상 동작과 일치하는지 확인예상치 못한 거부/허용 결정 없음
8Enforce Mode로 전환 (security.zerotrust.mode=ENFORCE)애플리케이션이 Shadow Mode와 동일하게 동작

DSL API 레퍼런스

IdentityAuthDsl

인증 단계 인터페이스입니다. 각 메서드는 상태 선택을 위한 IdentityStateDsl을 반환합니다.

메서드반환 타입설명
global(SafeHttpCustomizer<HttpSecurity>)IdentityAuthDsl모든 체인에 대한 공유 HTTP 보안 설정
form(Customizer<FormConfigurerConfigurer>)IdentityStateDsl폼 로그인 등록 (기본 order: 100)
rest(Customizer<RestConfigurerConfigurer>)IdentityStateDslREST API 로그인 등록 (기본 order: 200)
ott(Customizer<OttConfigurerConfigurer>)IdentityStateDslOne-Time Token 등록 (기본 order: 300)
passkey(Customizer<PasskeyConfigurerConfigurer>)IdentityStateDslPasskey/WebAuthn 등록 (기본 order: 400)
mfa(Customizer<MfaDslConfigurer>)IdentityStateDsl다중 인증 등록 (기본 order: 200)
build()PlatformConfig확정하고 불변 설정 생성

IdentityStateDsl

상태 관리 단계입니다. 인증 방법 등록 후 반환됩니다.

메서드반환 타입설명
session(Customizer<SessionStateConfigurer>)IdentityAuthDsl세션 기반 상태 (자동: sessionFixation.changeSessionId)
oauth2(Customizer<OAuth2StateConfigurer>)IdentityAuthDslOAuth2/JWT 상태 (자동: Resource Server + Auth Server)
설정 레퍼런스
application.yml 프로퍼티(로그인/로그아웃 URI, OAuth2 클라이언트 설정, 토큰 엔드포인트, MFA 설정)에 대해서는 상태 관리Identity 설정을 참조하세요.