问题
I'm trying to apply spring security with custom user detail service and custom authentication provider. Also, I'm trying to apply the remember-me functionality.
However, somehow, after I configured the custom user detail service and custom authentication provider, the remember me stop working.
When I check cookies from the client browser, it has the remember-me cookie. But, if I redeploy (restart) the server or restart the client browser, it redirects to the login page.
Here I'm attaching my configuration and custom files.
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<!-- enable use-expressions -->
<security:annotation-config/>
<http auto-config="false" use-expressions="true">
<headers>
<cache-control />
</headers>
<intercept-url pattern="/resources/**" access="permitAll()"/>
<intercept-url pattern="/signin" access="permitAll()" />
<intercept-url pattern="/403" access="permitAll()" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
<!-- redirect to 403 access denied <intercept-url pattern="/update**" access="hasRole('ROLE_ADMIN')
and isFullyAuthenticated()" /> -->
<form-login login-page="/signin"
default-target-url="/"
authentication-failure-url="/signin?error"
username-parameter="username"
password-parameter="password"
login-processing-url="/auth/login_check"
authentication-success-handler-ref="loginSuccessHandler" />
<logout logout-url="/logout" logout-success-url="/signin?logout" delete-cookies="JSESSIONID" />
<!-- enable csrf protection -->
<!--<csrf disabled="true"/>-->
<!--<remember-me-->
<!--token-validity-seconds="1209600"-->
<!--remember-me-parameter="remember-me"-->
<!--data-source-ref="dataSource" user-service-ref="customUserDetailService"/>-->
<remember-me services-ref="rememberMeServices" />
<csrf disabled="true"/>
<!--<custom-filter ref="statelessCSRFFilter" before="CSRF_FILTER"/>-->
</http>
<!-- Select users and user_roles from database -->
<!--<authentication-manager>-->
<!--<authentication-provider>-->
<!--<jdbc-user-service data-source-ref="dataSource"-->
<!--users-by-username-query="select username,password, enabled from users where username=?"-->
<!--authorities-by-username-query="select username, role from user_roles where username =? "-->
<!--group-authorities-by-username-query="select g.id, g.group_name, ga.authority from groups g, group_members gm, group_authorities ga where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id"/>-->
<!--</authentication-provider>-->
<!--</authentication-manager>-->
<beans:bean id="customUserDetailService" class="com.euroscope.app.service.security.CustomUserService"></beans:bean>
<beans:bean id="customAuthenticationProvider" class="com.euroscope.app.handler.CustomAuthenticationProvider"></beans:bean>
<beans:bean id="loginSuccessHandler" class="com.euroscope.app.handler.LoginSuccessHandler"></beans:bean>
<!--<beans:bean id="statelessCSRFFilter" class="com.euroscope.app.filter.StatelessCSRFFilter" />-->
<beans:bean id="rememberMeFilter" class= "org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter">
<beans:constructor-arg ref="authenticationManager"/>
<beans:constructor-arg ref="rememberMeServices"/>
</beans:bean>
<beans:bean id="rememberMeServices" class= "org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices">
<beans:constructor-arg value="euroscope"/>
<beans:constructor-arg ref="customUserDetailService"/>
<beans:constructor-arg ref="tokenRepository" />
<beans:property name="alwaysRemember" value="true" />
</beans:bean>
<beans:bean id="rememberMeAuthenticationProvider" class= "org.springframework.security.authentication.RememberMeAuthenticationProvider">
<beans:constructor-arg value="euroscope"/>
</beans:bean>
<beans:bean id="tokenRepository" class="org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl">
<beans:property name="dataSource" ref="dataSource"/>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="rememberMeAuthenticationProvider" />
<authentication-provider ref="customAuthenticationProvider" />
<authentication-provider user-service-ref="customUserDetailService" />
</authentication-manager>
</beans:beans>
Login Success handler
@Component
@Slf4j
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication auth) throws IOException, ServletException
{
HttpSession session = request.getSession();
Employee employee = (Employee)auth.getPrincipal();
log.debug("Employee : "+employee);
session.setAttribute("employee",employee);
response.sendRedirect(request.getContextPath() + "/");
}
}
package com.euroscope.app.handler;
import com.euroscope.app.domain.security.Employee;
import com.euroscope.app.service.security.CustomUserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import java.util.Collection;
/**
* Created by ksyeng on 7/9/15.
*/
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
private static final Logger logger = LoggerFactory.getLogger(CustomAuthenticationProvider.class);
@Autowired
CustomUserService customUserService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = (String) authentication.getCredentials();
Employee employee;
Collection<? extends GrantedAuthority> authorities;
try {
logger.debug("Custom Authentication : "+authentication);
employee = (Employee)customUserService.loadUserByUsername(username);
// employee = customUserService.loadUserByUsername(username);
// String hashedPassword = passwordEncoder.encodePassword(password, saltSource.getSalt(user));
// log.info("username : " + username + " / password : " + password + " / hash password : " + hashedPassword);
logger.debug("Username : " + employee.getUsername() + " / Password : " + employee.getPassword());
// if (!hashedPassword.equals(user.getPassword())) throw new BadCredentialsException("비밀번호가 일치하지 않습니다.");
authorities = employee.getAuthorities();
return new UsernamePasswordAuthenticationToken(employee, password, authorities);
} catch(UsernameNotFoundException e) {
e.printStackTrace();
logger.debug(e.toString());
throw new UsernameNotFoundException(e.getMessage());
} catch(BadCredentialsException e) {
e.printStackTrace();
logger.debug(e.toString());
throw new BadCredentialsException(e.getMessage());
} catch(Exception e) {
e.printStackTrace();
logger.debug(e.toString());
throw new RuntimeException(e.getMessage());
}
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
Custom User Service
package com.euroscope.app.service.security;
import com.euroscope.app.domain.security.Employee;
import com.euroscope.app.domain.security.Role;
import com.euroscope.app.mapper.security.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
/**
* Created by ksyeng on 7/9/15.
*/
@Slf4j
@Service
public class CustomUserService implements UserDetailsService {
@Resource
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Employee employee = userMapper.getUser(username);
ArrayList<Role> authList = userMapper.getRoles(username);
log.debug("Auth Roles : "+authList.toString());
employee.setAuthorities(authList);
if(employee == null){
throw new UsernameNotFoundException("Can't Find Any Matching User");
}
log.debug(employee.toString());
return employee;
}
}
回答1:
Whatever authentication filters (ie, subclasses of AbstractAuthenticationProcessingFilter) you are using will need to be aware of the RememberMeServices
, for example:
<beans:bean .. class="x.x..YourCustomAuthenticationFilter">
<beans:property name="rememberMeServices" ref="rememberMeServices"/>
<beans:property name="authenticationManager" ref="authenticationManager"/>
</beans:bean>
and RememberMeAuthenticationFilter
should be registered after YourCustomAuthenticationFilter
来源:https://stackoverflow.com/questions/31382144/spring-security-remember-me-doesnt-work