Post

Spring MVC 및 Spring Security를 ​​통한 Servlet 3 비동기

1. 메이븐 의존성

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

1
2
3
4
5
6
7
8
9
10
<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>

2. 스프링 MVC와 @Async

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

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

1
dispatcher.setAsyncSupported(true);

또는 XML 구성이다.

1
2
3
4
5
6
7
8
9
10
11
<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>

또한 서블릿 구성에서 비동기 지원 매개변수를 활성화해야 한다.

1
2
3
4
5
<servlet>
    ...
    <async-supported>true</async-supported>
    ...
</servlet>

이제 SecurityContext가 전파된 비동기 요청을 보낼 준비가 되었다.

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

3. 사용 사례

간단한 예를 통해 이를 실제로 확인한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@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을 자동으로 실행 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
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와 함께 비동기 요청을 사용하는 다른 중요한 사용 사례도 있다.

  • 병렬로 실행될 수 있고 실행하는데 상당한 시간이 걸릴 수 있는 여러 외부 요청을 만들고 싶다.

  • 로컬에서 수행해야 할 중요한 처리가 있고 외부 요청이 해당 처리와 동시에 실행될 수 있다.

  • 다른 것들은 예를 들어 이메일 보내기와 같은 실행 후 잊어버리는 시나리오를 나타낸다.

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

[출처 및 참고]

This post is licensed under CC BY 4.0 by the author.