2013-08-13 13 views
5

Ho un'applicazione Web SpringMVC che deve autenticarsi su un servizio web RESTful utilizzando Spring Security inviando il nome utente e la password. Quando un utente viene registrato, un cookie deve essere impostato sul browser dell'utente e nelle chiamate successive la sessione utente viene convalidata con un altro servizio web RESTful utilizzando il cookie.Spring MVC + Spring Security login con un servizio web di riposo

Ho cercato ovunque, ma non sono stato in grado di trovare un buon esempio su come ottenerlo, e tutti i miei tentativi sono stati vani.

Ecco quello che ho in mente:

posso avere due autenticazione-fornitori dichiarati, le prime verifiche del biscotto, e se non riesce per qualsiasi motivo, si va al secondo, che controlla con il nome utente e la password (fallirà anche se non ci sono username e password in quella richiesta).

Entrambi i servizi restituiscono le autorizzazioni dell'utente ogni volta e la sicurezza di primavera è "stateless".

D'altra parte, mi sono chiesto se questo approccio è corretto, dal momento che è stato così difficile trovare un esempio o qualcun altro con lo stesso problema. Questo approccio è sbagliato?

Il motivo per cui voglio eseguire questa operazione invece dell'autenticazione JDBC è perché l'intera applicazione Web è stateless e il database è sempre accessibile tramite servizi web RESTful che racchiudono una "coda di petizioni", vorrei rispettarlo anche per l'autenticazione e la convalida degli utenti.

Cosa ho provato fino ad ora? Potrei incollare il lungo springSecurity-context.xml, ma li elenco solo per ora:

  1. Utilizzare un authenticationFilter personalizzato con un authenticationSuccessHandler. Ovviamente non funziona perché l'utente è già registrato in questo punto.
  2. Effettuare un'implementazione del filtro di immissione del punto di riferimento.
  3. Fare un filtro personalizzato nella posizione BASIC_AUTH_FILTER
  4. Creare un provider di autenticazione personalizzato (Faticato molto senza fortuna!). Sto riprovando mentre ricevo delle risposte.
  5. Stavo iniziando a utilizzare CAS quando ho deciso di scrivere una domanda. Forse in futuro potrei considerare di avere un server CAS nella mia webapp, tuttavia per il momento, sembra un enorme overkill.

Grazie in anticipo!

BTW, sto usando Spring Security 3.1.4 e Spring MVC 3.2.3

EDIT: ho potuto fare grazie ad @coder RISPOSTA

Ecco qualche luce su quello che ho fatto, cercherò di documentare tutto questo e postare qui o in un post sul blog a volte presto:

<http use-expressions="true" create-session="stateless" entry-point-ref="loginUrlAuthenticationEntryPoint" 
     authentication-manager-ref="customAuthenticationManager"> 
    <custom-filter ref="restAuthenticationFilter" position="FORM_LOGIN_FILTER" /> 
    <custom-filter ref="restPreAuthFilter" position="PRE_AUTH_FILTER" /> 
    <intercept-url pattern="/signin/**" access="permitAll" /> 
    <intercept-url pattern="/img/**" access="permitAll" /> 
    <intercept-url pattern="/css/**" access="permitAll" /> 
    <intercept-url pattern="/js/**" access="permitAll" /> 
    <intercept-url pattern="/**" access="hasRole('ROLE_USER')" /> 

</http> 

<authentication-manager id="authManager" alias="authManager"> 
    <authentication-provider ref="preauthAuthProvider" /> 
</authentication-manager> 

<beans:bean id="restPreAuthFilter" class="com.company.CustomPreAuthenticatedFilter"> 
    <beans:property name="cookieName" value="SessionCookie" /> 
    <beans:property name="checkForPrincipalChanges" value="true" /> 
    <beans:property name="authenticationManager" ref="authManager" /> 
</beans:bean> 

<beans:bean id="preauthAuthProvider" 
    class="com.company.CustomPreAuthProvider"> 
    <beans:property name="preAuthenticatedUserDetailsService"> 
     <beans:bean id="userDetailsServiceWrapper" 
      class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper"> 
      <beans:property name="userDetailsService" ref="userDetailsService" /> 
     </beans:bean> 
    </beans:property> 
</beans:bean> 

<beans:bean id="userDetailsService" class="com.company.CustomUserDetailsService" /> 

<beans:bean id="loginUrlAuthenticationEntryPoint" 
    class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> 
    <beans:constructor-arg value="/signin" /> 
</beans:bean> 

<beans:bean id="customAuthenticationManager" 
    class="com.company.CustomAuthenticationManager" /> 

<beans:bean id="restAuthenticationFilter" 
    class="com.company.CustomFormLoginFilter"> 
    <beans:property name="filterProcessesUrl" value="/signin/authenticate" /> 
    <beans:property name="authenticationManager" ref="customAuthenticationManager" /> 
    <beans:property name="authenticationFailureHandler"> 
     <beans:bean 
      class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> 
      <beans:property name="defaultFailureUrl" value="/login?login_error=t" /> 
     </beans:bean> 
    </beans:property> 
</beans:bean> 

E le implementazioni personalizzate sono qualcosa di simile:

// Here, the idea is to write authenticate method and return a new UsernamePasswordAuthenticationToken 
public class CustomAuthenticationManager implements AuthenticationManager { ... } 

// Write attemptAuthentication method and return UsernamePasswordAuthenticationToken 
public class CustomFormLoginFilter extends UsernamePasswordAuthenticationFilter { ... } 

// Write getPreAuthenticatedPrincipal and getPreAuthenticatedCredentials methods and return cookieName and cookieValue respectively 
public class CustomPreAuthenticatedFilter extends AbstractPreAuthenticatedProcessingFilter { ... } 

// Write authenticate method and return Authentication auth = new UsernamePasswordAuthenticationToken(name, token, grantedAuths); (or null if can't be pre-authenticated) 
public class CustomPreAuthProvider extends PreAuthenticatedAuthenticationProvider{ ... } 

// Write loadUserByUsername method and return a new UserDetails user = new User("hectorg87", "123456", Collections.singletonList(new GrantedAuthorityImpl("ROLE_USER"))); 
public class CustomUserDetailsService implements UserDetailsService { ... } 
+0

Inserisci soluzione come una risposta, per favore, invece di modificare la tua domanda. ;) – bluish

risposta

3
  1. è possibile definire un filtro pre-autorizzazione personalizzato estendendo AbstractPreAuthenticatedProcessingFilter.
  2. Nell'implementazione del metodo getPreAuthenticatedPrincipal() è possibile verificare se il cookie esiste e se esiste il nome del cookie di restituzione è il valore principale e del cookie nelle credenziali .
  3. Usa PreAuthenticatedAuthenticationProvider e fornire la preAuthenticatedUserDetailsService personalizzato per verificare se cookie è vali, se i suoi validi anche per scaricare concesso autorità altro gettano AuthenticationException come BadCredentialsException
  4. per l'autenticazione utente tramite nome utente/password, aggiungere un filtro forma di login, base-filtro o un filtro personalizzato con provider di autenticazione personalizzato (o userdetailsService personalizzato) per convalidare utente/password

in caso di cookie esiste, filtro di autenticazione pre imposterà utente autenticato in springContext e il filtro username./password non sarà chiamato, se il cookie è errato/non valido, il punto di ingresso di autenticazione attiverà l'autenticazione icazione utilizzando username/password

Speranza che aiuta

+0

Ciao @coder, tutto ha senso. Ci proverò e pubblicheremo i risultati. Grazie! – hectorg87

+1

@ hector87 puoi condividere la tua implementazione e configurazione? Grazie. –

+0

Sì, sono interessato anche all'implementazione. Potresti postarlo da qualche parte? Grazie mille –