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:
- Utilizzare un authenticationFilter personalizzato con un authenticationSuccessHandler. Ovviamente non funziona perché l'utente è già registrato in questo punto.
- Effettuare un'implementazione del filtro di immissione del punto di riferimento.
- Fare un filtro personalizzato nella posizione BASIC_AUTH_FILTER
- Creare un provider di autenticazione personalizzato (Faticato molto senza fortuna!). Sto riprovando mentre ricevo delle risposte.
- 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 { ... }
Inserisci soluzione come una risposta, per favore, invece di modificare la tua domanda. ;) – bluish