2014-09-30 5 views
8

Recentemente ho iniziato a conoscere Spring Security e oggi ho posto questa domanda fondamentale (credo): Perché non posso accedere al Principal corrente all'interno di un filtro Servlet come dimostrato nella classe di seguito:Spring Security: accesso all'attuale utente autenticato all'interno di un servlet Filtro

package com.acme.test; 

import java.io.IOException; 

import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 

import org.springframework.security.core.Authentication; 
import org.springframework.security.core.context.SecurityContext; 
import org.springframework.security.core.context.SecurityContextHolder; 
import org.springframework.stereotype.Component; 

@Component 
public class TestFilter implements Filter { 

    /* 
    * (non-Javadoc) 
    * 
    * @see javax.servlet.Filter#init(javax.servlet.FilterConfig) 
    */ 
    @Override 
    public void init(FilterConfig filterConfig) throws ServletException { 
     // TODO Auto-generated method stub 

    } 

    /* 
    * (non-Javadoc) 
    * 
    * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, 
    * javax.servlet.ServletResponse, javax.servlet.FilterChain) 
    */ 
    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
      throws IOException, ServletException { 

     SecurityContext securityContext = SecurityContextHolder.getContext(); 
     Authentication auth = securityContext.getAuthentication(); 

     // auth is null here 

     chain.doFilter(request, response); 
    } 

    /* 
    * (non-Javadoc) 
    * 
    * @see javax.servlet.Filter#destroy() 
    */ 
    @Override 
    public void destroy() { 
     // TODO Auto-generated method stub 

    } 

} 

scopo autenticazione recuperato con autenticazione auth = securityContext.getAuthentication(); è nullo. Mentre si utilizza lo snippet sopra riportato in un MVC @Controller funziona bene (come previsto).

Perché sta succedendo?

+0

vorrei guardare catena di filtri di sicurezza a molla, per ignorare la configurazione di default della molla e inserire il filtro nella posizione giusta. L'Autenticazione potrebbe essere disponibile solo in una determinata posizione http://docs.spring.io/spring-security/site/docs/3.1.x/reference/security-filter-chain.html – jpprade

+0

@jpprade grazie. Sono principalmente interessato ai filtri generici, quindi preferirei non sovrascrivere un filtro di sicurezza.Sembra (dalle risposte in basso) che la configurazione dell'ordine del Filtro funzioni. – dimi

risposta

16

all'interno doFilter:

HttpServletRequest request = (HttpServletRequest) request; 
HttpSession session = request.getSession(false); 

SecurityContextImpl sci = (SecurityContextImpl) session.getAttribute("SPRING_SECURITY_CONTEXT"); 

if (sci != null) { 
     UserDetails cud = (UserDetails) sci.getAuthentication().getPrincipal(); 
     // do whatever you need here with the UserDetails 
} 

Spero che questo aiuti

+0

Ha funzionato davvero ... La soluzione di @ mordechai-tamam ha funzionato. Potresti spiegare cosa sta succedendo qui ... Sono principalmente interessato a capire cosa sta succedendo. – dimi

+0

HttpSessionSecurityContextRepository memorizza il contesto di sicurezza nella HttpSession tra richieste. E per ogni richiesta viene inserito in un ThreadLocal da cui si accede. Qui c'è un bel commento di @Ralph: http://stackoverflow.com/questions/6408007/spring-securitys-securitycontextholder-session-or-request-bound –

+0

Grazie per le informazioni Vipul ... roba interessante. Tuttavia, questo non spiega completamente perché SecurityContextHolder.getContext(); non ottiene un riferimento a un SecurityContext che contiene l'utente corrente. È perché il mio filtro viene eseguito prima di SecurityContextPersistenceFilter? – dimi

2

È possibile vedere here, che per accedere a SecurityContext, il filtro di sicurezza deve venire prima.

Se ti stai chiedendo come farlo, dipende dal modo in cui hai configurato la tua applicazione web. Nel mio caso, sto usando Primavera-Boot, basata su Servlet-3 stile di configurazione, e la configurazione contesto Primavera in Java (senza XML) Quindi, la mia configurazione è simile al seguente:

@Configuration 
@EnableWebMvc 
@EnableWebMvcSecurity 
public class WebCtxConfig extends WebMvcConfigurerAdapter { 

    @Autowired 
    ApplicationContext ctx; 


    @Bean 
    FilterRegistrationBean springSecurityFilter() { 
     FilterChainProxy o = (FilterChainProxy) ctx 
       .getBean(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME); 
     FilterRegistrationBean trVal = new FilterRegistrationBean(); 
     trVal.setFilter(o); 
     trVal.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE + 1); 
     return trVal; 
    } 

    @Bean 
    public FilterRegistrationBean applicationContextIdFilter(final IThreadLifecycleManager threadLifecycleManager) { 
     FilterRegistrationBean retVal = new FilterRegistrationBean(); 
     YourFilter filter = new YourFilter(); 
     retVal.setFilter(filter); 
     retVal.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE + 2); 
     return retVal; 
    } 
} 

Si noti che da impostando l'ordine, è possibile controllare l'ordine dei filtri.

+0

Questo ha funzionato e sembra buono. Mi chiedo perché anche il frammento di @ vipul-paralikar abbia funzionato. Qual è l'approccio giusto? – dimi

+0

La mia risposta, dimostra il modo in cui è possibile ordinare i filtri, in modo da poter posizionare i filtri aggiuntivi prima/dopo FilterChainProxy. Il punto è che prima che fosse invocato FilterChainProxy (una delle catene lo sta effettivamente facendo), il contesto di sicurezza è vuoto. Quindi, la mia soluzione si adatta nel caso in cui il filtro non sia correlato a nessuna azione correlata all'autenticazione e, comunque, si basa sul fatto che un utente è già autenticato. – Modi

2

La buona descrittore di deployment web.xml vecchia è un modo semplice per determinare l'ordine dei filtri. Dalla specifica Servlet 3.0: L'ordine del contenitore usa nella costruzione della catena di filtri da applicare per una particolare richiesta URI è il seguente:

  1. Prima, il filtro corrispondente mapping nello stesso ordine in cui questi elementi vengono visualizzati nel descrittore di distribuzione.
  2. Successivamente, i mapping dei filtri corrispondenti nello stesso ordine in cui questi elementi vengono visualizzati nel descrittore di distribuzione.

In breve, è necessario inserire il <filter-mapping> per voi filtro dopo quello per la sicurezza primavera.

anche dallo stesso documento specifica: Se l'ordine in cui gli ascoltatori, servlet, vengono richiamati filtri è importante per un'applicazione poi un descrittore di distribuzione deve essere utilizzato.

+0

Grazie; Non sto usando la configurazione XML, ma la tua risposta aiuta a comprendere il significato dell'ordine dei filtri. – dimi

3

Le seguenti opere frammento e fornisce un esempio Principal:

@Override 
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
     throws IOException, ServletException { 
    HttpServletRequest req = (HttpServletRequest) request; 

    Principal principal = req.getUserPrincipal(); 

    if (principal != null) { 
     // do something with the Principal 
    } 

    chain.doFilter(request, response); 
}