前言
进入springboot 2.7 后,一个重要的类WebSecurityConfigurerAdapter过期了
正文
①:如果想使用自定义的用户,只需要向Spring容器中注入一个UserDetailsService实例即可,此时用户是存在内存中的。如果用户是存在数据库中的,需要提供UserDetailsService接口的实现类并注入到Spring容器中
@Configurationpublic class SecurityConfig { UserDetailsService userDetailsService(){ InMemoryUserDetailsManager users = new InMemoryUserDetailsManager(); users.createUser(User.withUsername("root").password("{noop}123456").roles("admin").build()); return users; }}
②:给公共资源放行,就是希望用户不用登录就能访问
(1):配置WebSecurity:注册WebSecurityCustomizer的一个实例
@BeanWebSecurityCustomizer webSecurityCustomizer() { return new WebSecurityCustomizer() { @Override public void customize(WebSecurity web) { // 在 Spring Security 5.8 中,弃用 antMatchers 了 、 mvcMatchers 和 regexMatchers 方法, // 转而使用新 requestMatchers 方法 web.ignoring().requestMatchers("/hello");// 放行/hello } };}
(2):配置HttpSecurity
@BeanSecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{ http.authorizeRequests() // 在 Spring Security 5.8 中,弃用 antMatchers 了 、 mvcMatchers 和 regexMatchers 方法, // 转而使用新 requestMatchers 方法 .requestMatchers("/login").permitAll() .anyRequest().authenticated() .and().formLogin(); return http.build();}
两种方式最大的区别在于,第一种方式是不走 Spring Security 过滤器链,而第二种方式走 Spring Security 过滤器链,在过滤器链中,给请求放行。
在我们使用 Spring Security 的时候,有的资源可以使用第一种方式额外放行,不需要验证,例如前端页面的静态资源,就可以按照第一种方式配置放行。
有的资源放行,则必须使用第二种方式,例如登录接口。大家知道,登录接口也是必须要暴露出来的,不需要登录就能访问到的,但是我们却不能将登录接口用第一种方式暴露出来,登录请求必须要走 Spring Security 过滤器链,因为在这个过程中,还有其他事情要做
③:自定义登录成功与失败处理
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { Map<String, Object> result=new HashMap<>(); result.put("message","登录成功"); result.put("status",200); response.setContentType("application/json;charset=UTF-8"); // 返回结果 String s = new ObjectMapper().writeValueAsString(result); response.getWriter().println(s); }}
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { Map<String, Object> result=new HashMap<>(); result.put("message","登录失败:"+exception.getMessage()); result.put("status",500); response.setContentType("application/json;charset=UTF-8"); // 返回结果 String s = new ObjectMapper().writeValueAsString(result); response.getWriter().println(s); }}
在HttpSecurity中进行配置
@BeanSecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{ http.authorizeRequests() // 在 Spring Security 5.8 中,弃用 antMatchers 了 、 mvcMatchers 和 regexMatchers 方法, // 转而使用新 requestMatchers 方法 .requestMatchers("/login").permitAll() .anyRequest().authenticated() .and().formLogin() .successHandler(new MyAuthenticationSuccessHandler()) .failureHandler(new MyAuthenticationFailureHandler()) .and().csrf().disable(); return http.build();}
结果
④:自定义注销登录
@Overridepublic void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException { Map<String, Object> result = new HashMap<String, Object>(); result.put("msg", "注销成功"); result.put("status", 200); response.setContentType("application/json;charset=UTF-8"); String s = new ObjectMapper().writeValueAsString(result); response.getWriter().println(s);}
在HttpSecurity中进行配置
@BeanSecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception{ http.authorizeRequests() // 在 Spring Security 5.8 中,弃用 antMatchers 了 、 mvcMatchers 和 regexMatchers 方法, // 转而使用新 requestMatchers 方法 .requestMatchers("/login").permitAll() .anyRequest().authenticated() .and().formLogin() .successHandler(new MyAuthenticationSuccessHandler()) .failureHandler(new MyAuthenticationFailureHandler()) .and().logout() .logoutRequestMatcher(new OrRequestMatcher( new AntPathRequestMatcher("/logout","GET"), new AntPathRequestMatcher("/logout1","GET"))) .invalidateHttpSession(true) .clearAuthentication(true) .logoutSuccessHandler(new MyLogoutSuccessHandler()) .and().csrf().disable(); return http.build();}
结果