关于网上说的http方式配置无效问题,经验证,有点误导人,并且配置方式感觉过于复杂。
目前这种方式感觉是最简洁的一种方式。
一、核心配置:
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Resource private SessionRegistry sessionRegistry; /** * 设置URL的验证规则 Request层面的配置,对应XML Configuration中的<http>元素 * * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/login.html", "/logout.html").permitAll() .anyRequest().authenticated(); //登陆和登出可以匿名访问,其他的请求都必须要有权限认证 http.addFilterBefore(myValidCodeProcessingFilter(), UsernamePasswordAuthenticationFilter.class);//添加自定义验证规则 http.formLogin() .loginPage("/login.html")//设置登陆页面 .loginProcessingUrl("/login")//登陆处理路径 http.logout() .logoutUrl("/logout.html")//设置登出处理的url .logoutSuccessUrl("/");//设置登出成功后跳转页面,默认是跳转到登录页面 http.headers() .frameOptions()//解决不允许显示在iframe的问题 .sameOrigin() .httpStrictTransportSecurity() .disable(); http.csrf() .disable();//关闭crsf //session管理 //session失效后跳转 http.sessionManagement() .invalidSessionUrl("/login.html"); http.sessionManagement()//只允许一个用户登录,如果同一个账户两次登录,那么第一个账户将被踢下线,跳转到登录页面 .maximumSessions(1) .sessionRegistry(sessionRegistry) .expiredUrl("/login.html"); } //session失效跳转 private SessionInformationExpiredStrategy sessionInformationExpiredStrategy() { return new SimpleRedirectSessionInformationExpiredStrategy("/login.html"); } @Bean public SessionRegistry sessionRegistry() { return new SessionRegistryImpl(); } //SpringSecurity内置的session监听器 @Bean public HttpSessionEventPublisher httpSessionEventPublisher() { return new HttpSessionEventPublisher(); } @Bean public MyValidCodeProcessingFilter myValidCodeProcessingFilter() throws Exception { MyValidCodeProcessingFilter filter = new MyValidCodeProcessingFilter(); filter.setAuthenticationManager(authenticationManagerBean()); //设置登陆成功后跳转的URL filter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/index.html")); //设置登陆失败后跳转的URL //如果不设置这两个属性,会导致登陆成功后访问默认地址/ filter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/login.html?error=1")); filter.setSessionAuthenticationStrategy(new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry)); return filter; } //其他代码省略··· }
二、重要的一步:重写User的hashCode、toString和equals方法。(如果继承的UserDetails,则重写UserDetails的三个方法)
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; import java.util.Collection; /** * @author Xie Yuan You * <p>Created in 上午 11:30 2017/3/1 0001 * @version v.0.0.1 * */ public class SecurityUser extends User { /** * */ private static final long serialVersionUID = 1L; private User sysUser; public SecurityUser(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) { super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); } public User getSysUser() { return sysUser; } public void setSysUser(User sysUser) { this.sysUser = sysUser; } /** * 重写方法用于sessionRegistry * @return */ @Override public String toString() { return super.getUsername(); } /** * 重写方法用于sessionRegistry * @return */ @Override public boolean equals(Object rhs) { return this.toString().equals(rhs.toString()); } /** * 重写方法用于sessionRegistry * @return */ @Override public int hashCode() { return super.getUsername().hashCode(); } }
三、重写UsernamePasswordAuthenticationFilter:用户名密码验证通过后,注册session
public class MyValidCodeProcessingFilter extends UsernamePasswordAuthenticationFilter { //省略部分代码...... @Resource private SessionRegistry sessionRegistry; @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { //省略部分代码...... UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password); //用户名密码验证通过后,注册session sessionRegistry.registerNewSession(request.getSession().getId(),token.getPrincipal()); //省略部分代码...... this.setDetails(request, token); return this.getAuthenticationManager().authenticate(token); } }