@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService detailsService;
@Autowired
private SignedUsernamepasswordAuthenticationProvider provider;
@Autowired
private RememberMeAuthenticationProvider RememberMeprovider;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private FilterInvocationSecurityMetadataSource securityMetadataSource;
@Resource
private SessionRegistry sessionRegistry;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//添加用户验证
auth.authenticationProvider(provider);
auth.authenticationProvider(RememberMeprovider);
// 不删除凭据,以便记住用户
auth.eraseCredentials(false);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 解决不允许显示在iframe的问题
http.headers().frameOptions().disable();
// 自定义过滤器
MyFilterSecurityInterceptor filterSecurityInterceptor = new MyFilterSecurityInterceptor(securityMetadataSource,
accessDecisionManager(), authenticationManager);
// 在适当的地方加入
// 此处可以加入logoutFilter
http.addFilterAt(cuzLogoutFilter(), LogoutFilter.class);
// 此处可以添加remmebermeAuth..FILTER
http.addFilterAfter(rememberMeAuthenticationFilter(),
RememberMeAuthenticationFilter.class);
// 添加UsernamePasswordAuthenticationFilter
http.addFilterAt(myUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
//session并发控制过滤器
http.addFilterAt(new ConcurrentSessionFilter(sessionRegistry,sessionInformationExpiredStrategy()),ConcurrentSessionFilter.class);
// 此处可以添加filterSecurityInterceptor..FILTER
// http.addFilterBefore(filterSecurityInterceptor,FilterSecurityInterceptor.class);
AccessDeniedHandler accessDeniedHandler = new CustomAccessDeniedHandler("/error/illegalAccess");
http // .csrf().disable()//取消CSRF
.authorizeRequests().antMatchers("/css/**").permitAll().antMatchers("/login").permitAll().anyRequest()// all
.authenticated().and().formLogin().loginPage("/login").permitAll().defaultSuccessUrl("/home", true)
.failureUrl("/login?error").and().logout().clearAuthentication(true).logoutUrl("/logout")
.logoutSuccessUrl("/login").and().sessionManagement().invalidSessionUrl("/login").maximumSessions(1)
.expiredUrl("/login").and().and().exceptionHandling().accessDeniedPage("/accessDenied")// .accessDeniedHandler(accessDeniedHandler)//拒绝访问时跳转
.and()
// .rememberMe()//启用记住我功能
// .tokenValiditySeconds(2419200)//记住我四周
// .key("manageKey")
;
// http.exceptionHandling().authenticationEntryPoint(new
// LoginUrlAuthenticationEntryPoint("/login")).and().logout().logoutUrl("/logout").logoutSuccessUrl("/login").and().exceptionHandling().accessDeniedPage("/accessDenied");
super.configure(http);
}
// logoutFilter
@Bean
public LogoutFilter cuzLogoutFilter() {
CuzLogoutFilter filter = new CuzLogoutFilter("/login", customLogoutHandler());
return filter;
}
public LogoutHandler[] customLogoutHandler() {
return new LogoutHandler[] { new SecurityContextLogoutHandler(), new CustomLogoutHandler(),
tokenBasedRememberMeServices() };
}
@Override
public void configure(WebSecurity web) throws Exception {
// 图片资源不拦截
web.ignoring().antMatchers("/app/**");
web.ignoring().antMatchers("/common/**");
web.ignoring().antMatchers("/app/css/**");
web.ignoring().antMatchers("*/images/**");
web.ignoring().antMatchers("/app/js/**");
web.ignoring().antMatchers("/plugins/**");
web.ignoring().antMatchers("/favicon.ico");
web.ignoring().antMatchers("/login/captcha");
web.ignoring().antMatchers("/error/illegalAccess");
super.configure(web);
}
// session失效跳转
private SessionInformationExpiredStrategy sessionInformationExpiredStrategy() {
return new SimpleRedirectSessionInformationExpiredStrategy("/login");
}
@Bean
public SessionRegistry sessionRegistry() {
return new CustomSessionRegistryImpl();
}
// SpringSecurity内置的session监听器
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
/**
* 投票器
*/
/**
* AccessdecisionManager在Spring security中是很重要的。
*
* 在验证部分简略提过了,所有的Authentication实现需要保存在一个GrantedAuthority对象数组中。 这就是赋予给主体的权限。
* GrantedAuthority对象通过AuthenticationManager 保存到
* Authentication对象里,然后从AccessDecisionManager读出来,进行授权判断。
*
* Spring Security提供了一些拦截器,来控制对安全对象的访问权限,例如方法调用或web请求。
* 一个是否允许执行调用的预调用决定,是由AccessDecisionManager实现的。 这个 AccessDecisionManager
* 被AbstractSecurityInterceptor调用, 它用来作最终访问控制的决定。
* 这个AccessDecisionManager接口包含三个方法:
*
* void decide(Authentication authentication, Object secureObject,
* List config) throws AccessDeniedException; boolean
* supports(ConfigAttribute attribute); boolean supports(Class clazz);
*
* 从第一个方法可以看出来,AccessDecisionManager使用方法参数传递所有信息,这好像在认证评估时进行决定。
* 特别是,在真实的安全方法期望调用的时候,传递安全Object启用那些参数。 比如,让我们假设安全对象是一个MethodInvocation。
* 很容易为任何Customer参数查询MethodInvocation,
* 然后在AccessDecisionManager里实现一些有序的安全逻辑,来确认主体是否允许在那个客户上操作。
* 如果访问被拒绝,实现将抛出一个AccessDeniedException异常。
*
* 这个 supports(ConfigAttribute) 方法在启动的时候被
* AbstractSecurityInterceptor调用,来决定AccessDecisionManager
* 是否可以执行传递ConfigAttribute。 supports(Class)方法被安全拦截器实现调用,
* 包含安全拦截器将显示的AccessDecisionManager支持安全对象的类型。
*/
private AbstractAccessDecisionManager accessDecisionManager() {
List> decisionVoters = new ArrayList();
decisionVoters.add(new AuthenticatedVoter());
decisionVoters.add(new RoleVoter());// 角色投票器,默认前缀为ROLE_
RoleVoter AuthVoter = new RoleVoter();
AuthVoter.setRolePrefix("AUTH_");// 特殊权限投票器,修改前缀为AUTH_,用于自定义角色
decisionVoters.add(AuthVoter);
AbstractAccessDecisionManager accessDecisionManager = new AffirmativeBased(decisionVoters);//一票通过投票策略,还可以选用一票否决策略,多票通过策略,也可以自定义需求
//CustomAccessDecisionManager accessDecisionManager1 = new CustomAccessDecisionManager();// 用自定义的一票通过投票策略//此处采用用户自定义的投票器
//改成系统定义的策略器,因为自定义的虽然至此任意前缀的权限,但也意味着管理的复制性
return accessDecisionManager;
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() {
AuthenticationManager authenticationManager = null;
try {
authenticationManager = super.authenticationManagerBean();
} catch (Exception e) {
e.printStackTrace();
}
return authenticationManager;
}
/**
* 验证异常处理器,登录失败后调用
*其配置进CuzUsernamePasswordAuthenticationFilter中
* @return
*/
private SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler() {
return new SimpleUrlAuthenticationFailureHandler("/login");
}
/**
* 登录成功后跳转 如果需要根据不同的角色做不同的跳转处理,那么继承AuthenticationSuccessHandler重写方法
*其配置进CuzUsernamePasswordAuthenticationFilter中
* @return
*/
private SimpleUrlAuthenticationSuccessHandler authenticationSuccessHandler() {
return new SimpleUrlAuthenticationSuccessHandler("/home");
}
@Bean
public CuzUsernamePasswordAuthenticationFilter myUsernamePasswordAuthenticationFilter() throws Exception {
CuzUsernamePasswordAuthenticationFilter myUsernamePasswordAuthenticationFilter = new CuzUsernamePasswordAuthenticationFilter();
myUsernamePasswordAuthenticationFilter.setPostOnly(true);
myUsernamePasswordAuthenticationFilter.setAuthenticationManager(this.authenticationManager());
myUsernamePasswordAuthenticationFilter.setUsernameParameter("username");
myUsernamePasswordAuthenticationFilter.setPasswordParameter("password");
// myUsernamePasswordAuthenticationFilter.set
// myUsernamePasswordAuthenticationFilter.setVerificationCodeParameter("verification_code");
myUsernamePasswordAuthenticationFilter
.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login", "POST"));
myUsernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(simpleUrlAuthenticationFailureHandler());
myUsernamePasswordAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler());
myUsernamePasswordAuthenticationFilter.setSessionAuthenticationStrategy(
new CustomConcurrentSessionControlAuthenticationStrategy(sessionRegistry));
myUsernamePasswordAuthenticationFilter.setRememberMeServices(tokenBasedRememberMeServices());
// myUsernamePasswordAuthenticationFilter
return myUsernamePasswordAuthenticationFilter;
}
public static class MyFilterSecurityInterceptor extends FilterSecurityInterceptor {
//其作用在与在request中加入"__spring_security_filterSecurityInterceptor_filterApplied属性
//同时管理调用资源文件对应的权限
public MyFilterSecurityInterceptor(FilterInvocationSecurityMetadataSource securityMetadataSource,
AccessDecisionManager accessDecisionManager, AuthenticationManager authenticationManager) {
this.setSecurityMetadataSource(securityMetadataSource);// 加入资源管理器
this.setAccessDecisionManager(accessDecisionManager);// 加入决策管理器
this.setAuthenticationManager(authenticationManager);// 加入验证管理器
}
}
@Bean
public FilterInvocationSecurityMetadataSource MyFilterInvocationSecurityMetadataSource() {
return new CustomInvocationSecurityMetadataSource();
}
// 配置remmeber me
@Bean
public TokenBasedRememberMeServices tokenBasedRememberMeServices() {
// 自定义RememberMeService,可以加入数据库操作,比如当设置用户使用退出功能退出应用后,下次remmeberme功能不可用,当前系统未添加此功能
TokenBasedRememberMeServices tbrms = new CustomTokenBasedRememberMeServices("_spring_security_Key",
detailsService);
// 设置cookie过期时间为2天
tbrms.setTokenValiditySeconds(60 * 60 * 24 * 2);
// 设置checkbox的参数名为rememberMe(默认为remember-me),注意如果是ajax请求,参数名不是checkbox的name而是在ajax的data里
tbrms.setParameter("_spring_security_remember_me");
tbrms.setCookieName("_spring_security_Key");
return tbrms;
}
@Bean
public RememberMeAuthenticationProvider rememberMeAuthenticationProvider() {
RememberMeAuthenticationProvider rmap = new CustomRememberMeAuthenticationProvider("_spring_security_Key");
return rmap;
}
@Bean
public RememberMeAuthenticationFilter rememberMeAuthenticationFilter() throws Exception {
// 自定义RememberMeAuthenticationFilter,可添加额外操作
RememberMeAuthenticationFilter myFilter = new CuzRememberMeAuthenticationFilter(authenticationManager,
tokenBasedRememberMeServices());
return myFilter;
}
}
安全配置文件,首先继承WebSecurityConfigurerAdapter类,相关的pom配置请查看spring网站的依赖。
@EnableWebSecurity和@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)加载class上,以便通知spring boot初始化时初始化相关的WebSecurity的bean.@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)是用来使能方法安全的,按自己需求看看是否需要。
然后就可以去具体配置了哈。
为了实现登录效验,我们实现相关filter,然后重载configure(HttpSecurity http),然后按照官方的fiter次序依次添加我们需要的fiter.在上面的代码片段中,fiter都是自定义的,也较容易,依次继承相关的fiter,写自己的实现就ok了。
我们通过spring官方网站了解知道,验证是通过auth..manager调用provider来实现的。因此,需要配置provider.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//添加用户验证
auth.authenticationProvider(provider);
auth.authenticationProvider(RememberMeprovider);
// 不删除凭据,以便记住用户
auth.eraseCredentials(false);
}
我定义了两个provider.分别实现AuthenticationProvider接口,继承RememberMeAuthenticationProvider(spring自带的RememberMeAuthenticationProvider好像是空的哈)。
不多说,贴代码:
public class CustomRememberMeAuthenticationProvider extends RememberMeAuthenticationProvider{
public CustomRememberMeAuthenticationProvider(String key) {
super(key);
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!supports(authentication.getClass())) {
return null;
}
if (super.getKey().hashCode() != ((RememberMeAuthenticationToken) authentication)
.getKeyHash()) {
throw new BadCredentialsException(
messages.getMessage("RememberMeAuthenticationProvider.incorrectKey",
"The presented RememberMeAuthenticationToken does not contain the expected key"));
}
return authentication;
}
public boolean supports(Class authentication) {
return (RememberMeAuthenticationToken.class.isAssignableFrom(authentication));
}
}
public class SignedUsernamepasswordAuthenticationProvider implements AuthenticationProvider {
@Autowired
private CustomUserDetailsService userService;
/**
* 自定义验证方式
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!supports(authentication.getClass())) {
return null;
}
String username = authentication.getName();
String password = (String) authentication.getCredentials();
SigedUserDetails user = (SigedUserDetails) userService.loadUserByUsername(username);
if(user == null){
throw new BadCredentialsException("Username not found.");
}
//加密过程在这里体现
;//admin:ab4ad1624d29173c70d739c389e1daa3,Q123456W:2db436d701334d81c11ad8eb781e92c2
if (!MD5Util.encrypt(password).equals(user.getPassword())) {
throw new BadCredentialsException("Wrong password.");
}
Collection authorities = user.getAuthorities();
return new UsernamePasswordAuthenticationToken(user, password, authorities);
}
@Override
public boolean supports(Class authentication) {
// TODO Auto-generated method stub
//return true;
return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
import java.util.Iterator;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.context.MessageSource;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.web.authentication.session.ConcurrentSessionControlAuthenticationStrategy;
import org.springframework.security.web.authentication.session.SessionAuthenticationException;
import org.springframework.util.Assert;
/**
* Created by 为 on 2017-9-26
*/
public class CustomConcurrentSessionControlAuthenticationStrategy extends ConcurrentSessionControlAuthenticationStrategy {
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
private final SessionRegistry sessionRegistry;
private boolean exceptionIfMaximumExceeded = false;
private int maximumSessions = 1;
public CustomConcurrentSessionControlAuthenticationStrategy(SessionRegistry sessionRegistry) {
super(sessionRegistry);
Assert.notNull(sessionRegistry, "The sessionRegistry cannot be null");
this.sessionRegistry = sessionRegistry;
}
public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
List<SessionInformation> sessions = this.sessionRegistry.getAllSessions(authentication.getPrincipal(), false);
int sessionCount = sessions.size();
int allowedSessions = this.getMaximumSessionsForThisUser(authentication);
if(sessionCount >= allowedSessions) {
if(allowedSessions != -1) {
if(sessionCount == allowedSessions) {
HttpSession session = request.getSession(false);
if(session != null) {
Iterator var8 = sessions.iterator();
while(var8.hasNext()) {
SessionInformation si = (SessionInformation)var8.next();
if(si.getSessionId().equals(session.getId())) {
return;
}
}
}
}
this.allowableSessionsExceeded(sessions, allowedSessions, this.sessionRegistry);
}
}
}
protected int getMaximumSessionsForThisUser(Authentication authentication) {
return this.maximumSessions;
}
protected void allowableSessionsExceeded(List<SessionInformation> sessions, int allowableSessions, SessionRegistry registry) throws SessionAuthenticationException {
if(!this.exceptionIfMaximumExceeded && sessions != null) {
SessionInformation leastRecentlyUsed = null;
Iterator var5 = sessions.iterator();
while(true) {
SessionInformation session;
do {
if(!var5.hasNext()) {
leastRecentlyUsed.expireNow();
((CustomSessionRegistryImpl)sessionRegistry).addSessionInfo(leastRecentlyUsed.getSessionId(),leastRecentlyUsed);
return;
}
session = (SessionInformation)var5.next();
} while(leastRecentlyUsed != null && !session.getLastRequest().before(leastRecentlyUsed.getLastRequest()));
leastRecentlyUsed = session;
}
} else {
throw new SessionAuthenticationException(this.messages.getMessage("ConcurrentSessionControlAuthenticationStrategy.exceededAllowed", new Object[]{Integer.valueOf(allowableSessions)}, "Maximum sessions of {0} for this principal exceeded"));
}
}
public void setExceptionIfMaximumExceeded(boolean exceptionIfMaximumExceeded) {
this.exceptionIfMaximumExceeded = exceptionIfMaximumExceeded;
}
public void setMaximumSessions(int maximumSessions) {
Assert.isTrue(maximumSessions != 0, "MaximumLogins must be either -1 to allow unlimited logins, or a positive integer to specify a maximum");
this.maximumSessions = maximumSessions;
}
public void setMessageSource(MessageSource messageSource) {
Assert.notNull(messageSource, "messageSource cannot be null");
this.messages = new MessageSourceAccessor(messageSource);
}
}
@Slf4j
public class CustomSessionRegistryImpl implements SessionRegistry, ApplicationListener<SessionDestroyedEvent> {
private static final String SESSIONIDS = "sessionIds";
private static final String PRINCIPALS = "principals";
@Autowired
private RedisTemplate redisTemplate;
// private final ConcurrentMap<Object, Set<String>> principals = new ConcurrentHashMap();
// private final Map<String, SessionInformation> sessionIds = new ConcurrentHashMap();
public CustomSessionRegistryImpl() {
}
public List<Object> getAllPrincipals() {
return new ArrayList(this.getPrincipalsKeySet());
}
public List<SessionInformation> getAllSessions(Object principal, boolean includeExpiredSessions) {
Set<String> sessionsUsedByPrincipal = this.getPrincipals(((SigedUserDetails)principal).getUsername());
if (sessionsUsedByPrincipal == null) {
return Collections.emptyList();
} else {
List<SessionInformation> list = new ArrayList(sessionsUsedByPrincipal.size());
Iterator var5 = sessionsUsedByPrincipal.iterator();
while (true) {
SessionInformation sessionInformation;
do {
do {
if (!var5.hasNext()) {
return list;
}
String sessionId = (String) var5.next();
sessionInformation = this.getSessionInformation(sessionId);
} while (sessionInformation == null);
} while (!includeExpiredSessions && sessionInformation.isExpired());
list.add(sessionInformation);
}
}
}
public SessionInformation getSessionInformation(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract");
return (SessionInformation) this.getSessionInfo(sessionId);
}
public void onApplicationEvent(SessionDestroyedEvent event) {
String sessionId = event.getId();
this.removeSessionInformation(sessionId);
}
public void refreshLastRequest(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract");
SessionInformation info = this.getSessionInformation(sessionId);
if (info != null) {
info.refreshLastRequest();
}
}
public void registerNewSession(String sessionId, Object principal) {
Assert.hasText(sessionId, "SessionId required as per interface contract");
Assert.notNull(principal, "Principal required as per interface contract");
if (this.log.isDebugEnabled()) {
this.log.debug("Registering session " + sessionId + ", for principal " + principal);
}
if (this.getSessionInformation(sessionId) != null) {
this.removeSessionInformation(sessionId);
}
this.addSessionInfo(sessionId, new SessionInformation(principal, sessionId, new Date()));
// this.sessionIds.put(sessionId, new SessionInformation(principal, sessionId, new Date()));
Set<String> sessionsUsedByPrincipal = (Set) this.getPrincipals(principal.toString());
if (sessionsUsedByPrincipal == null) {
sessionsUsedByPrincipal = new CopyOnWriteArraySet();
Set<String> prevSessionsUsedByPrincipal = (Set) this.putIfAbsentPrincipals(principal.toString(), sessionsUsedByPrincipal);
if (prevSessionsUsedByPrincipal != null) {
sessionsUsedByPrincipal = prevSessionsUsedByPrincipal;
}
}
((Set) sessionsUsedByPrincipal).add(sessionId);
this.putPrincipals(principal.toString(), sessionsUsedByPrincipal);
if (this.log.isTraceEnabled()) {
this.log.trace("Sessions used by '" + principal + "' : " + sessionsUsedByPrincipal);
}
}
public void removeSessionInformation(String sessionId) {
Assert.hasText(sessionId, "SessionId required as per interface contract");
SessionInformation info = this.getSessionInformation(sessionId);
if (info != null) {
if (this.log.isTraceEnabled()) {
this.log.debug("Removing session " + sessionId + " from set of registered sessions");
}
this.removeSessionInfo(sessionId);
Set<String> sessionsUsedByPrincipal = (Set) this.getPrincipals(info.getPrincipal().toString());
if (sessionsUsedByPrincipal != null) {
if (this.log.isDebugEnabled()) {
this.log.debug("Removing session " + sessionId + " from principal's set of registered sessions");
}
sessionsUsedByPrincipal.remove(sessionId);
if (sessionsUsedByPrincipal.isEmpty()) {
if (this.log.isDebugEnabled()) {
this.log.debug("Removing principal " + info.getPrincipal() + " from registry");
}
this.removePrincipal(((SigedUserDetails)info.getPrincipal()).getUsername());
}
if (this.log.isTraceEnabled()) {
this.log.trace("Sessions used by '" + info.getPrincipal() + "' : " + sessionsUsedByPrincipal);
}
}
}
}
public void addSessionInfo(final String sessionId, final SessionInformation sessionInformation) {
BoundHashOperations<String, String, SessionInformation> hashOperations = redisTemplate.boundHashOps(SESSIONIDS);
hashOperations.put(sessionId, sessionInformation);
}
public SessionInformation getSessionInfo(final String sessionId) {
BoundHashOperations<String, String, SessionInformation> hashOperations = redisTemplate.boundHashOps(SESSIONIDS);
return hashOperations.get(sessionId);
}
public void removeSessionInfo(final String sessionId) {
BoundHashOperations<String, String, SessionInformation> hashOperations = redisTemplate.boundHashOps(SESSIONIDS);
hashOperations.delete(sessionId);
}
public Set<String> putIfAbsentPrincipals(final String key, final Set<String> set) {
BoundHashOperations<String, String, Set<String>> hashOperations = redisTemplate.boundHashOps(PRINCIPALS);
hashOperations.putIfAbsent(key, set);
return hashOperations.get(key);
}
public void putPrincipals(final String key, final Set<String> set) {
BoundHashOperations<String, String, Set<String>> hashOperations = redisTemplate.boundHashOps(PRINCIPALS);
hashOperations.put(key,set);
}
public Set<String> getPrincipals(final String key) {
BoundHashOperations<String, String, Set<String>> hashOperations = redisTemplate.boundHashOps(PRINCIPALS);
return hashOperations.get(key);
}
public Set<String> getPrincipalsKeySet() {
BoundHashOperations<String, String, Set<String>> hashOperations = redisTemplate.boundHashOps(PRINCIPALS);
return hashOperations.keys();
}
public void removePrincipal(final String key) {
BoundHashOperations<String, String, Set<String>> hashOperations = redisTemplate.boundHashOps(PRINCIPALS);
hashOperations.delete(key);
}
}
贴代码真麻烦!这两个代码是实现分布式session的,如果没有这个需求可以去掉的。
注意,本人在用了这个session策略后,rememberme老重复登录,检查发现,需要在public class CuzRememberMeAuthenticationFilter extends RememberMeAuthenticationFilter实现时重载dofiter方法,然后在。。贴代码吧
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (SecurityContextHolder.getContext().getAuthentication() == null) {
Authentication rememberMeAuth = getRememberMeServices().autoLogin(request,
response);
if (rememberMeAuth != null) {
// Attempt authenticaton via AuthenticationManager
try {
rememberMeAuth = authenticationManager.authenticate(rememberMeAuth);
// Store to SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(rememberMeAuth);
SigedUserDetails userdelail = (SigedUserDetails) rememberMeAuth.getPrincipal();
Collection<? extends GrantedAuthority> authorities = userdelail.getAuthorities();
Authentication auth = new UsernamePasswordAuthenticationToken(
userdelail.getUserName(), userdelail.getPassword(), authorities);
SecurityContextHolder.getContext().setAuthentication(auth);
SecurityContextHolder.getContext().setAuthentication(rememberMeAuth);
CustomConcurrentSessionControlAuthenticationStrategy sessionStrategy = new CustomConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
sessionStrategy.onAuthentication(auth, request, response);
sessionStrategy.onAuthentication(rememberMeAuth, request, response);
onSuccessfulAuthentication(request, response, rememberMeAuth);
if (logger.isDebugEnabled()) {
logger.debug("SecurityContextHolder populated with remember-me token: '"
+ SecurityContextHolder.getContext().getAuthentication()
+ "'");
}
// Fire event
if (this.eventPublisher != null) {
eventPublisher
.publishEvent(new InteractiveAuthenticationSuccessEvent(
SecurityContextHolder.getContext()
.getAuthentication(), this.getClass()));
}
if (successHandler != null) {
successHandler.onAuthenticationSuccess(request, response,
rememberMeAuth);
return;
}
}
catch (AuthenticationException authenticationException) {
if (logger.isDebugEnabled()) {
logger.debug(
"SecurityContextHolder not populated with remember-me token, as "
+ "AuthenticationManager rejected Authentication returned by RememberMeServices: '"
+ rememberMeAuth
+ "'; invalidating remember-me token",
authenticationException);
}
rememberMeServices.loginFail(request, response);
onUnsuccessfulAuthentication(request, response,
authenticationException);
}
}
chain.doFilter(request, response);
}
else {
if (logger.isDebugEnabled()) {
logger.debug("SecurityContextHolder not populated with remember-me token, as it already contained: '"
+ SecurityContextHolder.getContext().getAuthentication() + "'");
}
chain.doFilter(request, response);
}
}
把自己的user..token保存进去。就ok了。写这篇博客主要也是为了这个事情,当时弄了几天额。。。。