Iniciar sesión de usuario con la funcionalidad de recordar-me en Spring 3.1
spring-mvc spring-security (2)
Actualmente, inicio sesión en los usuarios mediante programación (como cuando inician sesión a través de Facebook u otros medios que no utilizan mi formulario de inicio de sesión) con:
SecurityContextHolder.getContext().setAuthentication(
new UsernamePasswordAuthenticationToken(user, "", authorities)
);
Lo que quiero hacer en su lugar es iniciar sesión en el usuario como si configuraran la opción recordarme en el formulario de inicio de sesión. Entonces, ¿supongo que necesito usar RememberMeAuthenticationToken
lugar de UsernamePasswordAuthenticationToken
? ¿Pero qué pongo para el argumento key
del constructor?
RememberMeAuthenticationToken(String key, Object principal, Collection<? extends GrantedAuthority> authorities)
ACTUALIZACIÓN : Estoy usando el enfoque de token persistente descrito aquí . Por lo tanto, no hay ninguna clave como en el enfoque de token basado en hash simple.
Esta es la fuente para el constructor.
public RememberMeAuthenticationToken(String key, Object principal, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
if ((key == null) || ("".equals(key)) || (principal == null) || "".equals(principal)) {
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
}
this.keyHash = key.hashCode();
this.principal = principal;
setAuthenticated(true);
}
La clave está en hash y se usa para determinar si la autenticación utilizada para este usuario en el contexto de seguridad no es "forjada".
Echa un vistazo a la fuente RememberMeAuthenicationProvider
.
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!supports(authentication.getClass())) {
return null;
}
if (this.key.hashCode() != ((RememberMeAuthenticationToken) authentication).getKeyHash()) {
throw new BadCredentialsException(messages.getMessage("RememberMeAuthenticationProvider.incorrectKey",
"The presented RememberMeAuthenticationToken does not contain the expected key"));
}
return authentication;
}
Entonces, para responder a su pregunta, necesita pasar el código hash del campo key
de la Authentication
representa al usuario .
Supongo que ya tiene <remember-me>
configurado en su configuración.
La forma en que funciona recordarme es que configura una cookie que se reconoce cuando el usuario regresa al sitio una vez que ha expirado su sesión.
Tendrá que subclasificar los RememberMeServices
( TokenBased
o PersistentTokenBased
) que está utilizando y hacer público el onLoginSuccess (). Por ejemplo:
public class MyTokenBasedRememberMeServices extends PersistentTokenBasedRememberMeServices {
@Override
public void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) {
super.onLoginSuccess(request, response, successfulAuthentication);
}
}
<remember-me services-ref="rememberMeServices"/>
<bean id="rememberMeServices" class="foo.MyTokenBasedRememberMeServices">
<property name="userDetailsService" ref="myUserDetailsService"/>
<!-- etc -->
</bean>
Inyecte sus servicios RememberMe en el bean donde está haciendo el inicio de sesión programático. Luego onLoginSuccess()
en él, usando el UsernamePasswordAuthenticationToken que creaste. Eso establecerá la cookie.
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(user, "", authorities);
SecurityContextHolder.getContext().setAuthentication(auth);
getRememberMeServices().onLoginSuccess(request, response, auth);
ACTUALIZAR
@at mejoró esto, sin subclasificación de RememberMeServices:
UsernamePasswordAuthenticationToken auth =
new UsernamePasswordAuthenticationToken(user, "", authorities);
SecurityContextHolder.getContext().setAuthentication(auth);
// This wrapper is important, it causes the RememberMeService to see
// "true" for the "_spring_security_remember_me" parameter.
HttpServletRequestWrapper wrapper = new HttpServletRequestWrapper(request) {
@Override public String getParameter(String name) { return "true"; }
};
getRememberMeServices().loginSuccess(wrapper, response, auth);