Implementing a Remember me for Spring-Social

I have a spring security enabled project. I have implemented remember me using a login form which works fine. But I also have social media login accounts from google / facebook which works great. The problem is that they don't remember the user. Is there a way to set up a similar "remember me" functionality?

My current spring config for normal login page:

<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>

      

+3


source to share


4 answers


We switched to Java configuration and created a "remember me" service:

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

      



and then in the SignInAdapter implementation for the social login:

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

      

+1


source


I have a similar requirement.

I tried to use url for authentication like /auth/facebook?_spring_security_remember_me=true

(see AbstractRememberMeServices.rememberMeRequested

). But then org.springframework.social.security.SocialAuthenticationFilter.detectRejection won't skip this pass. It is encoded like this:

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

      



I think if we can add another article in there, it might work. Then I decided to override it by subclassing SocialAuthenticationFilter

. But then SpringSocialConfigurer

it is not entered into, but determined using a keyword new

. Subclassing SpringSocialConfigurer

also doesn't seem like a solution, because there are many useful private fields inside. So, I think the solution is to just copy SpringSocialConfigurer

to another class and use it along with the subclass SocialAuthenticationFilter

. If I got it right, this is all like a hack, and I think we should create a ticket to properly memorize support.

Of course, if we want me to always be in the know, it's easy by setting the field alwaysRemember

to RememberMeServices

, and I do it like this:

@Bean
public RememberMeServices rememberMeServices() {

    TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices(rememberMeKey, userService);
    rememberMeServices.setAlwaysRemember(true);
    return rememberMeServices;

}

      

+2


source


So here's what I did to integrate RememberMeServices

with Spring social

. Just like @Sanjay says its based on logic AlwaysRemember=true

.

Instead of the standard one, TokenBasedRememberMeServices

we customize a little:

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

      

}

and on 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>

      

So in case of facebook login (via /auth/facebook

), it will use the strategy AlwaysRememberMe

by returning true

, but for traditional form-login

it depends:

  • If remember-me-param-based=on

    from the request body, it will check the continuation as traditional TokenBasedRememberMeServices

    based on the given parameter ( remember-me

    ).
  • If remember-me-param-based

    missing, it works like AlwaysRememberMe

    .

IMHO my implementation at least gives a choice for "regular login" users.

+1


source


To answer this question, the original way to request it (with XML configuration), Spring Security 3.2+ supports the services-ref attribute on the remember-me element. Therefore, in your security configuration, you would:

<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>

      

where MyRememberMeServices can be the checklist version or beku8 DynamicRememberMeServices. I prefer the beku8 version as it leaves the option to enable mem-me for regular logins.

+1


source







All Articles