1. 소개

이 사용방법(예제)에서는 AuthenticationManagerResolver 를 소개 한 다음 기본 및 OAuth2 인증 흐름에 사용하는 방법을 보여줍니다.

2. AuthenticationManager 란 무엇입니까 ?

간단히 말해 AuthenticationManager인증 을위한 주요 전략 인터페이스입니다.

입력 인증의 주체가 유효하고 확인 된 경우 AuthenticationManager # authenticate인증 된 플래그가 true로 설정된 Authentication 인스턴스를 반환 합니다 . 그렇지 않으면 주체가 유효하지 않으면 AuthenticationException이 발생 합니다. 마지막 경우에 결정할 수 없으면 null 을 반환합니다 .

ProviderManagerAuthenticationManager 의 기본 구현입니다 . 인증 프로세스를 AuthenticationProvider 인스턴스 List에 위임합니다 .

WebSecurityConfigurerAdapter 를 확장하면 전역 또는 로컬 AuthenticationManager를 설정할 수 있습니다 . 로컬 AuthenticationManager의 경우 configure (AuthenticationManagerBuilder)를 재정의 할 수 있습니다 .

AuthenticationManagerBuilder UserDetailService , AuthenticationProvider 및 기타 의존성을쉽게 설정하여 AuthenticationManager 를 빌드하는도우미 클래스입니다.

전역 AuthenticationManager의 경우 AuthenticationManager 를 빈으로 정의해야합니다 .

3. 왜 AuthenticationManagerResolver 인가?

AuthenticationManagerResolver를 사용하면 Spring이 컨텍스트별로 AuthenticationManager를 선택할 수 있습니다 . 버전 5.2.0의 Spring Security에 추가 새로운 기능입니다 .

public interface AuthenticationManagerResolver<C> {
    AuthenticationManager resolve(C context);
}

AuthenticationManagerResolver # resolve일반 컨텍스트를 기반으로 AuthenticationManager 의 인스턴스를 반환 할 수 있습니다 . , 이에 따라 AuthenticationManager 를 해결하려면 클래스를 컨텍스트로 설정할 수 있습니다 .

Spring Security는 HttpServletRequestServerWebExchange 를 컨텍스트로 사용 하여 AuthenticationManagerResolver 를 인증 흐름에 통합했습니다 .

4. 사용 시나리오

실제로 AuthenticationManagerResolver 를 사용하는 방법을 살펴 보겠습니다 .

예를 들어, 직원과 고객이라는 두 그룹의 사용자가있는 시스템을 가정 해보십시오. 이 두 그룹에는 특정 인증 논리가 있으며 별도의 데이터 저장소가 있습니다. 또한 이러한 그룹 중 하나의 사용자는 관련 URL 만 호출 할 수 있습니다.

5. AuthenticationManagerResolver 는 어떻게 작동합니까?

AuthenticationManager를 동적으로 선택해야하는 모든 곳에서 AuthenticationManagerResolver 를 사용할 수 있지만이 사용방법(예제)에서는 기본 제공 인증 흐름에서 사용하는 데 관심이 있습니다.

먼저 AuthenticationManagerResolver를 설정 한 다음 기본 및 OAuth2 인증에 사용합니다.

5.1. AuthenticationManagerResolver 설정

Security 구성을위한 클래스를 생성하는 것으로 시작하겠습니다. WebSecurityConfigurerAdapter 를 확장해야합니다 .

@Configuration
public class CustomWebSecurityConfigurer extends WebSecurityConfigurerAdapter {
    // ...
}

그런 다음 고객에 대한 AuthenticationManager반환하는 메서드를 추가해 보겠습니다 .

AuthenticationManager customersAuthenticationManager() {
    return authentication -> {
        if (isCustomer(authentication)) {
            return new UsernamePasswordAuthenticationToken(/*credentials*/);
        }
        throw new UsernameNotFoundException(/*principal name*/);
    };
}

의 AuthenticationManager 직원은 우리가 대체, 논리적으로 동일 isCustomer을 함께 isEmployee :

public AuthenticationManager employeesAuthenticationManager() {
    return authentication -> {
        if (isEmployee(authentication)) {
            return new UsernamePasswordAuthenticationToken(/*credentials*/);
        }
        throw new UsernameNotFoundException(/*principal name*/);
    };
}

마지막으로 요청 URL에 따라 확인 되는 AuthenticationManagerResolver추가해 보겠습니다 .

AuthenticationManagerResolver<HttpServletRequest> resolver() {
    return request -> {
        if (request.getPathInfo().startsWith("/employee")) {
            return employeesAuthenticationManager();
        }
        return customersAuthenticationManager();
    };
}

5.2. 기본 인증의 경우

우리는 사용할 수 AuthenticationFilter를 동적으로 해결하기 위해 AuthenticationManager에 요청 당합니다. AuthenticationFilter 는 버전 5.2에서 Spring Security에 추가되었습니다.

Security 필터 체인에 추가하면 일치하는 모든 요청에 ​​대해 먼저 인증 개체를 추출 할 수 있는지 여부를 확인합니다. 그렇다면 AuthenticationManagerResolver 에 적합한 AuthenticationManager요청 하고 흐름을 계속합니다.

먼저 CustomWebSecurityConfigurerAuthenticationFilter 를 생성하는 메서드를 추가해 보겠습니다 .

private AuthenticationFilter authenticationFilter() {
    AuthenticationFilter filter = new AuthenticationFilter(
      resolver(), authenticationConverter());
    filter.setSuccessHandler((request, response, auth) -> {});
    return filter;
}

No-op SuccessHandlerAuthenticationFilter # successHandler 를 설정하는 이유는 성공적인 인증 후 리디렉션의 기본 동작을 방지하기위한 것입니다.

그런 다음 CustomWebSecurityConfigurer 에서 WebSecurityConfigurerAdapter # configure (HttpSecurity)재정 의하여이 필터를 Security 필터 체인에 추가 할 수 있습니다 .

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.addFilterBefore(
      authenticationFilter(),
      BasicAuthenticationFilter.class);
}

5.3. OAuth2 인증의 경우

BearerTokenAuthenticationFilter 는 OAuth2 인증을 담당합니다. BearerTokenAuthenticationFilter # doFilterInternal의 방법 A에 대한 체크 BearerTokenAuthenticationToken 요청에서, 그리고 가능한 경우, 그것은 적절한 해결 AuthenticationManager에이 토큰을 인증한다.

OAuth2ResourceServerConfigurerBearerTokenAuthenticationFilter 를 설정하는 데 사용됩니다 .

따라서 WebSecurityConfigurerAdapter # configure (HttpSecurity)를 재정 의하여 CustomWebSecurityConfigurer 에서 리소스 서버에 대한 AuthenticationManagerResolver설정할 수 있습니다 .

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
      .oauth2ResourceServer()
      .authenticationManagerResolver(resolver());
}

6. 반응 형 애플리케이션에서 AuthenticationManager 해결

반응 형 웹 애플리케이션의 경우 컨텍스트에 따라 AuthenticationManager 를 해결하는 개념의 이점을 계속 누릴 수 있습니다 . 하지만 여기에 ReactiveAuthenticationManagerResolver가 대신 있습니다.

@FunctionalInterface
public interface ReactiveAuthenticationManagerResolver<C> {
    Mono<ReactiveAuthenticationManager> resolve(C context);
}

ReactiveAuthenticationManagerMono반환합니다 . ReactiveAuthenticationManagerAuthenticationManager 와 반응 형 이므로 해당 인증 메서드는 Mono를 반환합니다 .

6.1. ReactiveAuthenticationManagerResolver 설정

Security 구성을위한 클래스를 생성하여 시작하겠습니다.

@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class CustomWebSecurityConfig {
    // ...
}

다음 으로이 클래스의 고객에 대해 ReactiveAuthenticationManager정의 해 보겠습니다 .

ReactiveAuthenticationManager customersAuthenticationManager() {
    return authentication -> customer(authentication)
      .switchIfEmpty(Mono.error(new UsernameNotFoundException(/*principal name*/)))
      .map(b -> new UsernamePasswordAuthenticationToken(/*credentials*/));
}

그런 다음 직원을위한 ReactiveAuthenticationManager정의합니다 .

public ReactiveAuthenticationManager employeesAuthenticationManager() {
    return authentication -> employee(authentication)
      .switchIfEmpty(Mono.error(new UsernameNotFoundException(/*principal name*/)))
      .map(b -> new UsernamePasswordAuthenticationToken(/*credentials*/));
}

마지막으로 시나리오를 기반으로 ReactiveAuthenticationManagerResolver설정합니다 .

ReactiveAuthenticationManagerResolver<ServerWebExchange> resolver() {
    return exchange -> {
        if (match(exchange.getRequest(), "/employee")) {
            return Mono.just(employeesAuthenticationManager());
        }
        return Mono.just(customersAuthenticationManager());
    };
}

6.2. 기본 인증의 경우

반응 형 웹 애플리케이션에서 인증위해 AuthenticationWebFilter사용할 수 있습니다 . 요청을 인증하고 Security 컨텍스트를 채 웁니다.

AuthenticationWebFilter는 먼저 요청이 일치하는지 확인합니다. 그 후 요청에 인증 개체가 있으면 ReactiveAuthenticationManagerResolver 의 요청에 적합한 ReactiveAuthenticationManager가져와 인증 흐름을 계속합니다.

따라서 Security 구성에서 사용자 정의 된 AuthenticationWebFilter설정할 수 있습니다.

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
    return http
      .authorizeExchange()
      .pathMatchers("/**")
      .authenticated()
      .and()
      .httpBasic()
      .disable()
      .addFilterAfter(
        new AuthenticationWebFilter(resolver()), 
        SecurityWebFiltersOrder.REACTOR_CONTEXT
      )
      .build();
}

먼저 ServerHttpSecurity # httpBasic비활성화 하여 정상적인 인증 흐름을 방지 한 다음 수동으로이를 AuthenticationWebFilter로 바꾸고 사용자 지정 확인자를 전달합니다.

6.3. OAuth2 인증의 경우

ServerHttpSecurity # oauth2ResourceServer로 ReactiveAuthenticationManagerResolver구성 할 수 있습니다 . ServerHttpSecurity # buildSecurity 필터 체인에 리졸버와 함께 AuthenticationWebFilter 의 인스턴스를 추가합니다 .

따라서 Security 구성에서 OAuth2 인증 필터에 대한 AuthenticationManagerResolver설정해 보겠습니다 .

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
    return http
      // ...
      .and()
      .oauth2ResourceServer()
      .authenticationManagerResolver(resolver())
      .and()
      // ...;
}

7. 결론

이 기사에서는 간단한 시나리오 내에서 기본 및 OAuth2 인증에 AuthenticationManagerResolver사용했습니다 .

그리고, 승 e've 도의 사용 탐구 ReactiveAuthenticationManagerResolver을 모두 기본 및 OAuth2를 인증에 대한 반응 Spring 웹 응용 프로그램에서.

항상 그렇듯이 소스 코드는 GitHub에서 사용할 수 있습니다 . 우리의 반응 예제는 GitHub 에서도 사용할 수 있습니다 .