在Spring 3.1中使用remember-me功能登录用户

时间:2011-10-18 12:05:08

标签: spring spring-mvc spring-security security remember-me

我目前以编程方式(例如,当他们通过Facebook或其他方式登录而不是使用我的登录表单)登录用户时使用:

SecurityContextHolder.getContext().setAuthentication(
  new UsernamePasswordAuthenticationToken(user, "", authorities)
);

我想要做的是将用户登录,就好像他们在登录表单中设置了remember-me选项一样。所以我猜我需要使用RememberMeAuthenticationToken而不是UsernamePasswordAuthenticationToken?但是我应该为构造函数的key参数添加什么?

RememberMeAuthenticationToken(String key, Object principal, Collection<? extends GrantedAuthority> authorities) 

更新 :我正在使用Persistent Token Approach described here。因此,基于简单哈希的令牌方法中没有关键字。

2 个答案:

答案 0 :(得分:14)

我假设您已在配置中设置了<remember-me>

记住我工作的方式是设置一个cookie,当用户在会话结束后回到网站时会识别该cookie。

您必须继承您正在使用的RememberMeServicesTokenBasedPersistentTokenBased),并将onLoginSuccess()公开。例如:

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>

将RememberMeServices注入您正在进行程序化登录的bean中。然后使用您创建的UsernamePasswordAuthenticationToken在其上调用onLoginSuccess()。这将设置cookie。

UsernamePasswordAuthenticationToken auth = 
    new UsernamePasswordAuthenticationToken(user, "", authorities);
SecurityContextHolder.getContext().setAuthentication(auth);
getRememberMeServices().onLoginSuccess(request, response, auth);  

<强>更新

@at对此进行了改进,没有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);  

答案 1 :(得分:2)

这是构造函数的源。

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);
}

密钥经过哈希处理,用于确定安全上下文中用于此用户的身份验证是否为“伪造”身份。

查看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;
}

因此,要回答您的问题,您需要传递代表用户的key Authentication字段的哈希码