2013-04-23 4 views
1

작업이 비동기 적으로 작동하므로 사용자의 세션에 액세스 할 수 없습니다. 작업이 사용자 세션에 액세스 할 수 있도록 솔루션을 찾아야합니다 (사용자가 아직 그 순간 로그인 한 경우).스프링 보안 : 비동기 작업에서 인증 된 사용자에게 액세스하는 방법

사용자 세션

import org.springframework.security.core.GrantedAuthority; 
import org.springframework.security.core.authority.SimpleGrantedAuthority; 
import org.springframework.security.core.userdetails.UserDetails; 

public class UserPrincipal implements UserDetails { 

private User user; 

private Collection<SimpleGrantedAuthority> grantedAuthorities; 

public UserPrincipal(User user) { 
    Assert.notNull(user); 
    this.user = user; 

    Set<SimpleGrantedAuthority> authorities = new LinkedHashSet<>(); 
    for (Role role : user.getRoles()) { 
     authorities.add(new SimpleGrantedAuthority(role.getName().toUpperCase(Locale.ENGLISH))); 
    } 
    grantedAuthorities = Collections.unmodifiableCollection(authorities); 
} 

}

추상 작업 클래스

public abstract class Job implements Runnable { 

protected Logger logger = LoggerFactory.getLogger(getClass()); 

protected Job() { 
} 

@Override 
public final void run() { 
    logger.debug("starting work"); 
    /* code goes here */ 
    logger.debug("work is done"); 
} 
} 

작업 클래스

@Component 
@Scope(value = "prototype") 
public class ProcessLoggingJob extends Job { 

@Override 
protected void work(Map<String, Object> context) throws Exception { 
    // need to access user session here 
} 
+0

, 당신은 acheive하려고하는 어떤 세션 – BlackJoker

+0

에서 기록 로그인 정보] 어떤 HTTP 세션의 생성을 추적하고 파괴하는 HttpSessionListener을 구현을? – Akshay

+1

정답은 여기에있다 : http://stackoverflow.com/questions/5246428/spring-security-and-async – Ritesh

답변

2

비동기 작업은 다른 스레드에서 (예상대로) 실행됩니다. 세션은 응용 프로그램 서버에 의해 관리되고 요청에 의해 제공됩니다. 스프링 보안은 추가 요청없이 로컬 스레드의 컨텍스트를 관리합니다 (@Michael이 답변에 표시 한대로).

(세션에서 가져온) 보안 컨텍스트로

지역 하나 개의 스레드 (일반 응용 프로그램 서버의 HTTP 스레드)에서 개최되어, 비동기 작업이 와 다른 스레드에서의 지역 스레드에 액세스 할 기회를 실행하지 요구 thread

내가 볼 수있는 유일한 기회가 큐에 전달, 사용자 데이터를 포함하여 요청 스레드에서 새로운 작업 데이터를 생성하는 큐 메커니즘을 사용하는 것입니다, 작업의 대기열에서 데이터를 처리. 이 (널 (null) 처리 누락)처럼 보일 수있는 요청 처리 스레드에서

는 :

private BlockingQueue<UserDetails> usersToProceedAsync; 

public void doSomethingInRequestThread() throws InterruptedException { 
    UserDetails principal = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal() 
    ... 
    usersToProceedAsync.put(principal); 
} 

작업 구현 될 수있다 : 당신은 단지를 주입하여 두 클래스를 연결해야

private BlockingQueue<UserDetails> usersToProceedAsync; 

protected void work(Map<String, Object> context) throws Exception { 
    UserDetails principal = usersToProceedAsync.poll(); 
    if (principal != null) { 
    ... 
    } 
} 

두 큐에 동일한 대기열 (예 : LinkedBlockingQueue). 작업 인스턴스가 작업 실행마다 작성되면 큐를 주입 할 팩토리가 필요합니다.

요청 당 하나의 작업 데이터를 만들 때주의하십시오! 비동기 작업이 모든 작업을 처리 할 수있을만큼 빠름을 보장하는 방법은 무엇입니까? BlockingQueue에서 데이터를 추가하거나 제거하기 위해 다른 메소드를 사용하거나 바운드 된 ArrayBlockingQueue과 같은 다른 구현을 사용하여 동작을 조정할 수있는 많은 옵션이 있습니다.

다른 아이디어는 예약 된 작업 실행 대신 executor 프레임 워크를 사용할 수 있습니다. 그냥 요청 처리기에서 실행기를 만들고 당신을위한 작업 실행하자 :

private final Executor asyncJobs = Executors.newCachedThreadPool() 

public void doSomethingInRequestThread() throws InterruptedException { 
    UserDetails principal = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal() 
    ... 
    asyncJobs.execute(new AsyncJob(principal)); 
} 

private class AsyncJob implements Runnable { 
    private final UserDetails principal; 

    public AsyncJob(UserDetails principal) { 
    this.principal = principal; 
    } 

    public void run() { 
    ... 
    } 
} 
+0

그 큐 메커니즘에 대한 코딩 샘플을 줄 수 있습니까 – Kushan

+0

ok, 일부 코드를 찾아 내려고했습니다. –

관련 문제