복붙노트

[SPRING] 스프링 보안 및 @Async (인증 된 사용자가 섞여 있음)

SPRING

스프링 보안 및 @Async (인증 된 사용자가 섞여 있음)

@ Async.This 메소드를 사용하여 Spring에서 메소드를 비동기 적으로 호출하면 @PreAuthorize, Spring Security Annotation으로 주석 된 다른 메소드가 호출된다. 인증 작업을 수행하려면 SecurityContextHolder 모드를 MODE_INHERITABLETHREADLOCAL로 설정해야 인증 정보가 비동기 호출로 전달됩니다. 지금까지 모든 것이 잘 작동합니다.

그러나 로그 아웃하고 다른 사용자로 로그인 할 때 비동기 메서드 인 SecurityContextHolder는 벌 로그 아웃 된 이전 사용자의 인증 정보를 저장합니다. 물론 원치 않는 AccessDenied 예외가 발생합니다. 동기 호출에는 이러한 문제가 없습니다.

나는 를 정의 했으므로 일단 executor pool의 thread가 초기화되면 인증 정보를 오버라이드하지 않을 수도있다.

해결법

  1. ==============================

    1.MODE_INHERITABLETHREADLOCAL이 스레드 풀에서 올바르게 작동하지 않는 것 같습니다.

    MODE_INHERITABLETHREADLOCAL이 스레드 풀에서 올바르게 작동하지 않는 것 같습니다.

    가능한 해결책으로 ThreadPoolTaskExecutor를 서브 클래스 화하고 그 메소드를 오버라이드하여 SecurityContext를 수동으로 전달한 다음 대신 executor를 선언 할 수 있습니다.

    public void execute(final Runnable r) {
        final Authentication a = SecurityContextHolder.getContext().getAuthentication();
    
        super.execute(new Runnable() {
            public void run() {
                try {
                    SecurityContext ctx = SecurityContextHolder.createEmptyContext();
                    ctx.setAuthentication(a);
                    SecurityContextHolder.setContext(ctx);
                    r.run();
                } finally {
                    SecurityContextHolder.clearContext();
                }
            }
        });
    }
    
  2. ==============================

    2.이는 미래의 조사가 필요한 힌트 일뿐입니다. (너무 피곤하지만 나중에 조사 할 때 유용 할 수 있습니다.)

    이는 미래의 조사가 필요한 힌트 일뿐입니다. (너무 피곤하지만 나중에 조사 할 때 유용 할 수 있습니다.)

    오늘 나는 GitHub을보고 org.springframework.security.task.DelegatingSecurityContextAsyncTaskExecutor를 발견했다.

    @Async 호출을 통해 "통과"되도록 보안 컨텍스트를 위임하도록 설계된 것 같습니다.

    또한이 게시물을 살펴보십시오 : Spring Security 3.2 M1 주요 내용, Servlet 3 API 지원은 강력하게 관련되어있는 소리입니다.

  3. ==============================

    3.Ralph와 Oak의 정보를 사용하여 -

    Ralph와 Oak의 정보를 사용하여 -

    @Async가 표준 태스크 실행기 태그와 함께 작동하게하려면 다음과 같이 Spring XML 구성을 설정해야한다.

    <task:annotation-driven executor="_importPool"/>
    <task:executor id="_importPool" pool-size="5"/>
    
    <bean id="importPool"
              class="org.springframework.security.task.DelegatingSecurityContextAsyncTaskExecutor">
         <constructor-arg ref="_importPool"/>
    </bean>
    

    그런 다음 @Async 메서드에서 사용할 풀을 지정합니다.

    @Async("importPool")
    public void run(ImportJob import) {
       ...
    }
    

    그렇게하면 @Async 메서드를 호출 할 때마다 스레드 풀 스레드가 호출 스레드와 동일한 보안 컨텍스트를 사용하게됩니다.

  4. ==============================

    4.@Ralph를 기반으로 대답은 스프링으로 스레드 풀링을 사용하여 Aync 이벤트를 달성하고 http://docs.spring.io/autorepo/docs/spring-security/4.0.0.M1/apidocs/org/springframework/security를 ​​사용하여 보안을 위임 할 수 있습니다. /task/DelegatingSecurityContextAsyncTaskExecutor.html

    @Ralph를 기반으로 대답은 스프링으로 스레드 풀링을 사용하여 Aync 이벤트를 달성하고 http://docs.spring.io/autorepo/docs/spring-security/4.0.0.M1/apidocs/org/springframework/security를 ​​사용하여 보안을 위임 할 수 있습니다. /task/DelegatingSecurityContextAsyncTaskExecutor.html

    <bean id="applicationEventMulticaster"
        class="org.springframework.context.event.SimpleApplicationEventMulticaster">
        <property name="taskExecutor">
            <ref bean="delegateSecurityAsyncThreadPool"/>
        </property>
    </bean>
    
    <bean id="threadsPool"
        class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    </bean>
    
    
    <bean id="delegateSecurityAsyncThreadPool"
        class="org.springframework.security.task.DelegatingSecurityContextTaskExecutor">
        <constructor-arg ref="threadsPool"/>
    </bean>
    
  5. ==============================

    5.Jus가 @axtavt의 답을 추가하려면 다른 방법을 재정의해야합니다.

    Jus가 @axtavt의 답을 추가하려면 다른 방법을 재정의해야합니다.

    @Override
        public <T> Future<T> submit(Callable<T> task) {
            ExecutorService executor = getThreadPoolExecutor();
            final Authentication a = SecurityContextHolder.getContext().getAuthentication();
            try {
                return executor.submit(new Callable<T>() {
                    @Override
                    public T call() throws Exception {
                        try {
                            SecurityContext ctx = SecurityContextHolder.createEmptyContext();
                            ctx.setAuthentication(a);
                            SecurityContextHolder.setContext(ctx);
                            return task.call();
                        } catch (Exception e) {
                            slf4jLogger.error("error invoking async thread. error details : {}", e);
                            return null;
                        } finally {
                            SecurityContextHolder.clearContext();
                        }
                    }
                });
            } catch (RejectedExecutionException ex) {
                throw new TaskRejectedException("Executor [" + executor + "] did not accept task: " + task, ex);
            }
        }
    
  6. from https://stackoverflow.com/questions/5246428/spring-security-and-async-authenticated-users-mixed-up by cc-by-sa and MIT license