1. 소개

이 빠른 사용방법(예제)에서는 비동기 요청에 대한 Servlet 3 지원과 Spring MVC 및 Spring Security가 이러한 .

웹 애플리케이션에서 비동기성에 대한 가장 기본적인 동기는 장기 실행 요청을 처리하는 것입니다. 대부분의 사용 사례에서 Spring Security 주체가 이러한 스레드로 전파되는지 확인해야 합니다.

물론 Spring Security 는 MVC 범위 밖에서 @Async 와 통합되고 HTTP 요청도 처리합니다.

2. 메이븐 의존성

Spring MVC에서 비동기 통합을 사용하려면 pom.xml 에 다음 의존성을 포함해야 합니다 .

<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.7.3</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.7.3</version>
</dependency>

최신 버전의 Spring Security 의존성은 여기 에서 찾을 수 있습니다 .

3. 스프링 MVC와 @Async

공식 문서 에 따르면 Spring Security는 WebAsyncManager 와 통합됩니다 .

첫 번째 단계는 springSecurityFilterChain 이 비동기 요청을 처리하도록 설정되었는지 확인하는 것입니다. Servlet 구성 클래스 에 다음 줄을 추가하여 Java 구성에서 수행할 수 있습니다 .

dispatcher.setAsyncSupported(true);

또는 XML 구성에서:

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <async-supported>true</async-supported>
</filter>
<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>ASYNC</dispatcher>
</filter-mapping>

또한 서블릿 구성에서 async-supported 매개변수 를 활성화해야 합니다.

<servlet>
    ...
    <async-supported>true</async-supported>
    ...
</servlet>

이제 우리는 전파된 SecurityContext 와 함께 비동기 요청을 보낼 준비가 되었습니다 .

Spring Security 내의 내부 메커니즘 은 다른 스레드 에서 응답이 커밋되어 사용자 로그아웃 이 발생할 때 SecurityContext 가 더 이상 지워지지 않도록 합니다.

4. 사용 사례

간단한 예를 통해 이를 실제로 살펴보겠습니다.

@Override
public Callable<Boolean> checkIfPrincipalPropagated() {
    Object before 
      = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    log.info("Before new thread: " + before);

    return new Callable<Boolean>() {
        public Boolean call() throws Exception {
            Object after 
              = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            log.info("New thread: " + after);
            return before == after;
        }
    };
}

Spring SecurityContext 가 새 스레드로 전파 되는지 확인하고 싶습니다 .

위에 제시된 메소드는 로그에서 볼 수 있듯이 SecurityContext 가 포함된 Callable 을 자동으로 실행합니다 .

web - 2017-01-02 10:42:19,011 [http-nio-8081-exec-3] INFO
  o.baeldung.web.service.AsyncService - Before new thread:
  org.springframework.security.core.userdetails.User@76507e51:
  Username: temporary; Password: [PROTECTED]; Enabled: true;
  AccountNonExpired: true; credentialsNonExpired: true;
  AccountNonLocked: true; Granted Authorities: ROLE_ADMIN

web - 2017-01-02 10:42:19,020 [MvcAsync1] INFO
  o.baeldung.web.service.AsyncService - New thread:
  org.springframework.security.core.userdetails.User@76507e51:
  Username: temporary; Password: [PROTECTED]; Enabled: true;
  AccountNonExpired: true; credentialsNonExpired: true;
  AccountNonLocked: true; Granted Authorities: ROLE_ADMIN

전파할 SecurityContext 를 설정하지 않으면 두 번째 요청은 null 값으로 끝납니다.

전파된 SecurityContext 와 함께 비동기 요청을 사용하는 다른 중요한 사용 사례도 있습니다 .

  • 병렬로 실행할 수 있고 실행하는 데 상당한 시간이 걸릴 수 있는 여러 외부 요청을 만들고 싶습니다.
  • 우리는 로컬에서 수행해야 할 몇 가지 중요한 처리가 있으며 외부 요청을 병렬로 실행할 수 있습니다.
  • 다른 것들은 예를 들어 이메일 보내기와 같은 실행 후 잊어버리는 시나리오를 나타냅니다.

여러 메서드 호출이 이전에 동기 방식으로 함께 연결된 경우 이를 비동기 방식으로 변환하려면 결과를 동기화해야 할 수 있습니다.

5. 결론

이 짧은 예제에서는 인증된 컨텍스트에서 비동기 요청을 처리하기 위한 Spring 지원을 설명했습니다 .

프로그래밍 모델의 관점에서 보면 새 기능은 믿을 수 없을 정도로 단순해 보입니다. 그러나 더 깊이 있는 이해가 필요한 측면도 분명히 있습니다.

이 예제는 Github 에서 Maven 프로젝트로도 제공됩니다 .

Security footer banner