Java 为春季社交活动实施“记住我”计划

Java 为春季社交活动实施“记住我”计划,java,spring-security,spring-social,Java,Spring Security,Spring Social,我有一个支持spring安全性的项目。我已经使用登录表单实现了一个RememberMe,它运行良好。但我也有来自谷歌/facebook的社交登录,效果很好。问题是他们不记得用户。有没有办法设置类似的“记住我”功能 正常登录页面的当前spring配置: <http access-denied-page="/login?authorization_error=true" disable-url-rewriting="true" authentication-manager-re

我有一个支持spring安全性的项目。我已经使用登录表单实现了一个RememberMe,它运行良好。但我也有来自谷歌/facebook的社交登录,效果很好。问题是他们不记得用户。有没有办法设置类似的“记住我”功能

正常登录页面的当前spring配置:

<http access-denied-page="/login?authorization_error=true"
        disable-url-rewriting="true" authentication-manager-ref="formAuthenticationManager"
        xmlns="http://www.springframework.org/schema/security">
        <intercept-url pattern="/account/**" access="ROLE_USER" />

        <remember-me key="iRemember"
            token-validity-seconds="1209600" user-service-ref="formClientDetailsUserService" />
        <form-login authentication-failure-url="/login?authentication_error=true"
            default-target-url="/account/" login-page="/login"
            login-processing-url="/login.do" />
        <logout logout-success-url="http://example.com" logout-url="/logout" />
        <anonymous />
    </http>

我有一些类似的要求

我尝试将用于身份验证的url设置为
/auth/facebook?\u spring\u security\u memory\u me=true
(请参阅
AbstractMemberServices.MemberRequested
)。但是,我不会放过这一切。它的编码如下:

protected boolean detectRejection(HttpServletRequest request) {
    Set<?> parameterKeys = request.getParameterMap().keySet();
    return parameterKeys.size() > 0 
            && !parameterKeys.contains("oauth_token") 
            && !parameterKeys.contains("code") 
            && !parameterKeys.contains("scope");
}

下面是我将
RememberMeServices
springsocial
集成所做的工作。正如@Sanjay所说,它基于
AlwaysRemember=true
逻辑

与默认的
TokenBasedMemberMeservices
不同,我们定制了一点:

public class DynamicRememberMeServices extends TokenBasedRememberMeServices {

public final static String PARAM_BASED_KEY = "remember-me-param-based"; 
public final static String REMEMBER_ME_KEY = "remember-me";

private Logger logger = LoggerFactory.getLogger(getClass());

public DynamicRememberMeServices(String key, UserDetailsService userDetailsService){
    super(key, userDetailsService);
    super.setParameter(REMEMBER_ME_KEY);
    super.setCookieName(REMEMBER_ME_KEY);
}

@Override
protected boolean rememberMeRequested(HttpServletRequest request, String parameter) {
    if("on".equalsIgnoreCase(request.getParameter(PARAM_BASED_KEY)) ){
        logger.debug("param based request");
        return super.rememberMeRequested(request, parameter);
    }
    logger.debug("always remember me");
    return true;
}
}

login.html
上:

<form th:action="@{/login}" method="post">
   User Name : <input type="text" name="username"/> 
   Password: <input type="password" name="password"/>
   <input type="hidden" name="remember-me-param-based" value="on" /> 
   Remember me: <input type='checkbox' name='remember-me' checked="checked"/>
   <input type="hidden" name="_csrf" th:value="${_csrf.token}"/>
   <input type="submit" value="Sign In"/>
</form>

<a th:href="@{/auth/facebook}">Or via facebook</a>

用户名:
密码:
记住我:
因此,在facebook登录(通过
/auth/facebook
)的情况下,它将通过返回
true
来使用
AlwaysMemberMe
策略,但对于传统的
表单登录
,这取决于:

  • 如果请求正文中的
    记住我参数based=on
    ,它将根据给定参数(
    记住我
    )检查continue as traditional
    TokenbasedMemberMeservices
  • 如果缺少
    基于memory me param的
    ,它将始终作为
    memberme
    工作

IMHO我的实现至少为“传统登录”用户提供了选择。

我们切换到Java配置并创建了记住我的服务:

@Bean
public MyRememberMeServices myRememberMeServices(){
        MyRememberMeServices service = new MyRememberMeServices (REMEMBERME_KEY, formUserDetailsService);
        service.setAlwaysRemember(true);
        service.setCookieName("xxxx");
        service.setParameter("_spring_security_remember_me");
        service.setTokenValiditySeconds(123);
        return service;
    };
然后在社交登录的SignInAdapter实现上:

@Override
public String signIn(String userId, Connection<?> connection, NativeWebRequest request) {

    // load the user based on the account id

    // create an authentication object to store in context


    // set remember-me cookie
    myRememberMeServices.onLoginSuccess(
        (HttpServletRequest) request.getNativeRequest(),
        (HttpServletResponse) request.getNativeResponse(),
        authentication);

    // forward to the original URL
    return extractOriginalUrl(request);
}
@覆盖
公共字符串签名(字符串用户ID、连接、NativeWebRequest请求){
//根据帐户id加载用户
//创建要存储在上下文中的身份验证对象
//请记住我的曲奇
MyMemberServices.onLoginSAccess(
(HttpServletRequest)请求。getNativeRequest(),
(HttpServletResponse)请求。getNativeResponse(),
认证);
//转发到原始URL
返回提取器originalurl(请求);
}

为了回答这个问题,按照最初的提问方式(使用XML配置),Spring Security 3.2+支持memory me元素上的services ref属性。因此,在您的安全配置中,您将有:

<security:http xmlns="http://www.springframework.org/schema/security">
  ...
  <remember-me services-ref="rememberMeServices" key="secret-key">
</security:http>

<bean id="rememberMeServices" class="com.example.MyRememberMeServices">
  <constructor-arg index="0" value="secret-key" />
  <constructor-arg index="1" ref="userDetailsService" />
  <property name="tokenValiditySeconds" value="1000000" />
</bean>

...

其中MyMemberServices可以是checklist的版本,也可以是beku8的DynamicMemberServices。我更喜欢beku8的版本,因为它为正常登录留下了启用“记住我”的选择。

我对始终使用“记住我”感兴趣,并且我添加了setAlwaysRemember(true)。但春天似乎忽视了这一点。那么,我如何将MemberMeServices与社交网站联系起来呢?MemberMeServices.setAlwaysRemember(true),正如我所记得的那样,上面的设置对我有效。我尝试了你的方法,但仍然无法将MemberMe服务与社交登录网站联系起来。有这样的设置吗?您使用的是
SocialAuthenticationFilter
而不是
ProviderSignInController
对吗?如果是这样,您只需以常规方式注入它,如
http.rememberMeServices(rememberMeServices())
@beku8您能否提供一个使用SocialAuthenticationFilter时使用http.rememberMeServices(rememberMeServices())的示例?将您的方法与beku8的版本相结合。没用
<security:http xmlns="http://www.springframework.org/schema/security">
  ...
  <remember-me services-ref="rememberMeServices" key="secret-key">
</security:http>

<bean id="rememberMeServices" class="com.example.MyRememberMeServices">
  <constructor-arg index="0" value="secret-key" />
  <constructor-arg index="1" ref="userDetailsService" />
  <property name="tokenValiditySeconds" value="1000000" />
</bean>