如果不是前后端分离项目,使用SpringSecurity做登录功能会很省心,只要简单的几项配置,便可以轻松完成登录成功失败的处理,当访问需要认证的页面时,可以自动重定向到登录页面。但是前后端分离的项目就不一样了,不能直接由后台处理,而是要向前端返回相应的json提示。
在本例的介绍中,主要解决了以下几个问题:
1.使用json格式数据进行登录。 2.登录成功或失败处理返回json提示。 3.未登录时访问需要认证的url时,返回json提示。 4.session过期时返回json提示。 一、引入security依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> 二、编写配置文件 package com.hanstrovsky.config; ... /** * @author Hanstrovsky */ @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) // security默认不支持注解的方式的权限控制,加上这个注解开启 public class WebSecurityConfig extends WebSecurityConfigurerAdapter { private final MyUserDetailsService myUserDetailsService; private final MyPasswordEncoder myPasswordEncoder; public WebSecurityConfig(MyUserDetailsService myUserDetailsService, MyPasswordEncoder myPasswordEncoder) { this.myUserDetailsService = myUserDetailsService; this.myPasswordEncoder = myPasswordEncoder; } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 定义加密解密方式 auth.userDetailsService(myUserDetailsService).passwordEncoder(myPasswordEncoder); } @Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .httpBasic() // 访问需要认证的url,进行json提示 .and().exceptionHandling() .authenticationEntryPoint((req, resp, e) -> { resp.setContentType("application/json;charset=utf-8"); PrintWriter out = resp.getWriter(); FrontResult frontResult = FrontResult.init(FrontResult.LOGIN, "未登录或登录超时!"); out.write(new ObjectMapper().writeValueAsString(frontResult)); out.flush(); out.close(); }) .and() .authorizeRequests() .anyRequest().authenticated()// 必须认证之后才能访问 .and() .formLogin()// 表单登录 .permitAll() // 和表单登录相关的接口统统都直接通过 .and() .logout().deleteCookies("JSESSIONID")// 注销登录,删除cookie // 自定义注销成功,返回json .logoutSuccessHandler(new LogoutSuccessHandler() { @Override public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException { resp.setContentType("application/json;charset=utf-8"); PrintWriter out = resp.getWriter(); FrontResult frontResult = FrontResult.init(FrontResult.SUCCEED, "注销成功!"); out.write(new ObjectMapper().writeValueAsString(frontResult)); out.flush(); out.close(); } }) .and() // session 超时返回json提示 .sessionManagement() .maximumSessions(5).maxSessionsPreventsLogin(true)// 同一用户最大同时在线数量5个,超出后阻止登录 // session 超时返回json提示 .expiredSessionStrategy(new SessionInformationExpiredStrategy() { @Override public void onExpiredSessionDetected( SessionInformationExpiredEvent sessionInformationExpiredEvent) throws IOException, ServletException { HttpServletResponse resp = sessionInformationExpiredEvent.getResponse(); // 返回提示 resp.setContentType("application/json;charset=utf-8"); PrintWriter out = resp.getWriter(); FrontResult frontResult = FrontResult.init(FrontResult.LOGIN, "登录超时!"); out.write(new ObjectMapper().writeValueAsString(frontResult)); out.flush(); out.close(); } }); //用重写的Filter替换掉原有的UsernamePasswordAuthenticationFilter http.addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);} //注册自定义的UsernamePasswordAuthenticationFilter,使用json格式数据登录 @Bean CustomAuthenticationFilter customAuthenticationFilter() throws Exception { CustomAuthenticationFilter filter = new CustomAuthenticationFilter(); // 自定义登录成功或失败 返回json提示 filter.setAuthenticationSuccessHandler((req, resp, authentication) -> { resp.setContentType("application/json;charset=utf-8"); PrintWriter out = resp.getWriter(); FrontResult frontResult = FrontResult.init(FrontResult.SUCCEED, "登录成功!"); out.write(new ObjectMapper().writeValueAsString(frontResult)); out.flush(); out.close(); }); filter.setAuthenticationFailureHandler(new AuthenticationFailureHandler() { @Override public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException { resp.setContentType("application/json;charset=utf-8"); PrintWriter out = resp.getWriter(); String errorMessage = "登录失败"; FrontResult frontResult = FrontResult.init(FrontResult.FAILED, errorMessage); out.write(new ObjectMapper().writeValueAsString(frontResult)); out.flush(); out.close(); } }); filter.setFilterProcessesUrl("/user/login"); //重用WebSecurityConfigurerAdapter配置的AuthenticationManager,不然要自己组装AuthenticationManager filter.setAuthenticationManager(authenticationManagerBean()); return filter; } } 三、实现Json登录的处理逻辑