SpringBoot整合SpringSecurity,SESSION 并发管理,同账号只允许登录一次
2017-06-02 11:31
537 查看
重写了UsernamePasswordAuthenticationFilter,里面继承AbstractAuthenticationProcessingFilter,这个类里面的session认证策略,是一个空方法,貌似RememberMe也是.
所以必须自己配置一个session验证策略,以及配置并发控制.红字为关键
继承UsernamePasswordAuthenticationFilter ,注入SessionRegistry ,当用户登录验证成功后注册session
重写用户实体类的比较方法.
public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean implements ApplicationEventPublisherAware, MessageSourceAware { protected ApplicationEventPublisher eventPublisher; protected AuthenticationDetailsSource<HttpServletRequest, ?> authenticationDetailsSource = new WebAuthenticationDetailsSource(); private AuthenticationManager authenticationManager; protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor(); private RememberMeServices rememberMeServices = new NullRememberMeServices(); private RequestMatcher requiresAuthenticationRequestMatcher; private boolean continueChainBeforeSuccessfulAuthentication = false; private SessionAuthenticationStrategy sessionStrategy = new NullAuthenticatedSessionStrategy(); private boolean allowSessionCreation = true; private AuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); private AuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
NullAuthenticatedSessionStrategy 源码
public final class NullAuthenticatedSessionStrategy implements SessionAuthenticationStrategy { public NullAuthenticatedSessionStrategy() { } public void onAuthentication(Authentication authentication, HttpServletRequest request, HttpServletResponse response) { } }
所以必须自己配置一个session验证策略,以及配置并发控制.红字为关键
WebSecurityConfigurerAdapter
/**
* Created by ZhenWeiLai on on 2016-10-16.
* <p>
* 三种方法级权限控制
* <p>
* 1.securedEnabled: Spring Security’s native annotation
* 2.jsr250Enabled: standards-based and allow simple role-based constraints
* 3.prePostEnabled: expression-based
*/
@EnableWebSecurity
//@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Resource
private UserDetailsService userDetailsService;
@Resource
private FilterInvocationSecurityMetadataSource securityMetadataSource;
@Resource
private SessionRegistry sessionRegistry;
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/assets/**");
web.ignoring().antMatchers("/components/**");
web.ignoring().antMatchers("/css/**");
web.ignoring().antMatchers("/images/**");
web.ignoring().antMatchers("/js/**");
web.ignoring().antMatchers("/mustache/**");
web.ignoring().antMatchers("/favicon.ico");
//注册地址不拦截
// web.ignoring().antMatchers("/base/invoice/userinfo/u/reg");
// web.ignoring().antMatchers("/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
//解决不允许显示在iframe的问题
http.headers().frameOptions().disable();
http.addFilterAt(usernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
//session并发控制过滤器
http.addFilterAt(new ConcurrentSessionFilter(sessionRegistry,sessionInformationExpiredStrategy()),ConcurrentSessionFilter.class);
//自定义过滤器
//在适当的地方加入
http.addFilterAt(filterSecurityInterceptor(securityMetadataSource, accessDecisionManager(), authenticationManagerBean()), FilterSecurityInterceptor.class);
http.exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")).and().logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll().and().exceptionHandling().accessDeniedPage("/accessDenied");
http.authorizeRequests().anyRequest().fullyAuthenticated();
// 关闭csrf
http.csrf().disable();
/**
* 以下配置无效
*/
//session管理
//session失效后跳转
// http.sessionManagement().invalidSessionUrl("/login");
// //只允许一个用户登录,如果同一个账户两次登录,那么第一个账户将被踢下线,跳转到登录页面
// http.sessionManagement().maximumSessions(1).expiredUrl("/login");
}
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
// 自定义UserDetailsService,设置加密算法
auth.userDetailsService(userDetailsService);
//.passwordEncoder(passwordEncoder())
//不删除凭据,以便记住用户
auth.eraseCredentials(false);
}
//session失效跳转
private SessionInformationExpiredStrategy sessionInformationExpiredStrategy() {
return new SimpleRedirectSessionInformationExpiredStrategy("/login");
}
@Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
//SpringSecurity内置的session监听器
@Bean
public HttpSessionEventPublisher httpSessionEventPublisher() {
return new HttpSessionEventPublisher();
}
private UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter() throws Exception {
UsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter = new CuzUsernamePasswordAuthenticationFilter();
usernamePasswordAuthenticationFilter.setPostOnly(true);
usernamePasswordAuthenticationFilter.setAuthenticationManager(this.authenticationManager());
usernamePasswordAuthenticationFilter.setUsernameParameter("name_key");
usernamePasswordAuthenticationFilter.setPasswordParameter("pwd_key");
usernamePasswordAuthenticationFilter.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/checkLogin", "POST"));
usernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(simpleUrlAuthenticationFailureHandler());
usernamePasswordAuthenticationFilter.setAuthenticationSuccessHandler(authenticationSuccessHandler());
//session并发控制,因为默认的并发控制方法是空方法.这里必须自己配置一个
usernamePasswordAuthenticationFilter.setSessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry));
return usernamePasswordAuthenticationFilter;
}
// @Bean
// public LoggerListener loggerListener() {
// System.out.println("org.springframework.security.authentication.event.LoggerListener");
// return new LoggerListener();
// }
//
// @Bean
// public org.springframework.security.access.event.LoggerListener eventLoggerListener() {
// System.out.println("org.springframework.security.access.event.LoggerListener");
// return new org.springframework.security.access.event.LoggerListener();
// }
/**
* 投票器
*/
private AbstractAccessDecisionManager accessDecisionManager() {
List<AccessDecisionVoter<? extends Object>> 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);
return accessDecisionManager;
}
@Override
public AuthenticationManager authenticationManagerBean() {
AuthenticationManager authenticationManager = null;
try {
authenticationManager = super.authenticationManagerBean();
} catch (Exception e) {
e.printStackTrace();
}
return authenticationManager;
}
/**
* 验证异常处理器
*
* @return
*/
private SimpleUrlAuthenticationFailureHandler simpleUrlAuthenticationFailureHandler() {
return new SimpleUrlAuthenticationFailureHandler("/getLoginError");
}
// /**
// * 表达式控制器
// *
// * @return
// */
// private DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() {
// DefaultWebSecurityExpressionHandler webSecurityExpressionHandler = new DefaultWebSecurityExpressionHandler();
// return webSecurityExpressionHandler;
// }
// /**
// * 表达式投票器
// *
// * @return
// */
// private WebExpressionVoter webExpressionVoter() {
// WebExpressionVoter webExpressionVoter = new WebExpressionVoter();
// webExpressionVoter.setExpressionHandler(webSecurityExpressionHandler());
// return webExpressionVoter;
// }
// Code5 官方推荐加密算法
// @Bean("passwordEncoder")
// public BCryptPasswordEncoder passwordEncoder() {
// BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
// return bCryptPasswordEncoder;
// }
// // Code3----------------------------------------------
/**
* 登录成功后跳转
* 如果需要根据不同的角色做不同的跳转处理,那么继承AuthenticationSuccessHandler重写方法
*
* @return
*/
private SimpleUrlAuthenticationSuccessHandler authenticationSuccessHandler() {
return new SimpleUrlAuthenticationSuccessHandler("/loginSuccess");
}
/**
* Created by ZhenWeiLai on on 2016-10-16.
*/
private FilterSecurityInterceptor filterSecurityInterceptor(FilterInvocationSecurityMetadataSource securityMetadataSource, AccessDecisionManager accessDecisionManager, AuthenticationManager authenticationManager) {
FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
filterSecurityInterceptor.setSecurityMetadataSource(securityMetadataSource);
filterSecurityInterceptor.setAccessDecisionManager(accessDecisionManager);
filterSecurityInterceptor.setAuthenticationManager(authenticationManager);
return filterSecurityInterceptor;
}
}
继承UsernamePasswordAuthenticationFilter ,注入SessionRegistry ,当用户登录验证成功后注册session
/** * Created by ZhenWeiLai on 2017/6/2. */ public class CuzUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter { private boolean postOnly = true; @Resource private SessionRegistry sessionRegistry; @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { if(this.postOnly && !request.getMethod().equals("POST")) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } else { String username = this.obtainUsername(request); String password = this.obtainPassword(request); if(username == null) { username = ""; } if(password == null) { password = ""; } username = username.trim(); UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); //用户名密码验证通过后,注册session sessionRegistry.registerNewSession(request.getSession().getId(),authRequest.getPrincipal()); this.setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } } }
重写用户实体类的比较方法.
/** * 重写比较方法,SpringSecurity根据用户名来比较是否同一个用户 */ @Override public boolean equals(Object o){ if(o.toString().equals(this.username)) return true; return false; } @Override public int hashCode(){ return username.hashCode(); } @Override public String toString() { return this.username; }
相关文章推荐
- SpringBoot整合SpringSecurity,SESSION 并发管理,同账号只允许登录一次
- SpringBoot整合SpringSecurity,SESSION 并发管理,同账号只允许登录一次
- SpringBoot,Security4, redis共享session,分布式SESSION并发控制,同账号只能登录一次
- springboot(十四):springboot整合shiro-登录认证和权限管理(转)
- springboot(十四):springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- 转载:Spring Boot (十四):springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- spring-boot(八) springboot整合shiro-登录认证和权限管理
- springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- springboot整合shiro-登录认证和权限管理
- springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- springboot(十四):springboot整合shiro-登录认证和权限管理
- springboot+shiro+mybatis整合发现部分功能事务没有被spring管理
- Spring Boot项目利用Redis实现session管理实例