一、Spring Security登录接口兼容JSON格式登录
1.1、概述
前后端分离中,前端和后端的数据交互通常是JSON格式,而Spring Security的登录接口默认支持的是form-data或者x-www-form-urlencoded的,如下所示:
那么如何让Spring Security的登录接口也支持JSON格式登录呢?请看下文分析
1.2、自定义过滤器
/*** @Author : 一叶浮萍归大海* @Date: 2024/1/13 9:30* @Description:*/
public class MyUsernamePasswordAuthenticationFilter7007 extends UsernamePasswordAuthenticationFilter {@Overridepublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {if (!HttpMethod.POST.name().equals(request.getMethod())) {throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());}String sessionCode = (String) request.getSession().getAttribute("code");if (MediaType.APPLICATION_JSON_VALUE.equals(request.getContentType()) || MediaType.APPLICATION_JSON_UTF8_VALUE.equals(request.getContentType())) {Map<String, String> loginData = new HashMap<>(16);try {loginData = new ObjectMapper().readValue(request.getInputStream(), Map.class);} catch (Exception e) {e.printStackTrace();} finally {String paramCode = loginData.get("code");try {checkCode(response,paramCode,sessionCode);} catch (Exception e) {throw new RuntimeException(e);}}String username = loginData.get(getUsernameParameter());String password = loginData.get(getPasswordParameter());if (username == null) {username = "";}if (password == null) {password = "";}username = username.trim();UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);setDetails(request,authRequest);return this.getAuthenticationManager().authenticate(authRequest);} else {try {checkCode(response,request.getParameter("code"),sessionCode);} catch (Exception e) {throw new RuntimeException(e);}return super.attemptAuthentication(request, response);}}/*** 检查验证码* @param response* @param paramCode* @param sessionCode*/private void checkCode(HttpServletResponse response, String paramCode, String sessionCode) throws Exception {if (StringUtils.isBlank(paramCode)) {R r = R.error(ResponseEnum.VERIFY_CODE_IS_NULL.getCode(), ResponseEnum.VERIFY_CODE_IS_NULL.getMessage());response.setContentType("application/json;charset=utf-8");PrintWriter out = response.getWriter();out.write(new ObjectMapper().writeValueAsString(r));out.flush();out.close();return;}if (StringUtils.isBlank(sessionCode)) {R r = R.error(ResponseEnum.VERIFY_CODE_IS_EXPIRED.getCode(), ResponseEnum.VERIFY_CODE_IS_EXPIRED.getMessage());response.setContentType("application/json;charset=utf-8");PrintWriter out = response.getWriter();out.write(new ObjectMapper().writeValueAsString(r));out.flush();out.close();return;}if (!StringUtils.equals(paramCode.toLowerCase(), sessionCode.toLowerCase())) {R r = R.error(ResponseEnum.VERIFY_CODE_IS_NOT_MATCH.getCode(), ResponseEnum.VERIFY_CODE_IS_NOT_MATCH.getMessage());response.setContentType("application/json;charset=utf-8");PrintWriter out = response.getWriter();out.write(new ObjectMapper().writeValueAsString(r));out.flush();out.close();return;}}
}
1.3、配置类
/*** @Author : 一叶浮萍归大海* @Date: 2024/1/11 21:50* @Description: Spring Security配置类*/
@Configuration
public class MyWebSecurityConfigurerAdapter7007 extends WebSecurityConfigurerAdapter {@Resourceprivate MyAuthenticationSuccessHandler7007 successHandler;@Resourceprivate MyAuthenticationFailureHandler7007 failureHandler;@Resourceprivate MyLogoutSuccessHandler7007 logoutSuccessHandler;@Resourceprivate MyAuthenticationEntryPoint7007 authenticationEntryPoint;@Resourceprivate MyAccessDeniedHandler7007 accessDeniedHandler;@Resourceprivate UserDetailsService userDetailsServiceImpl;/*** 密码加密器** @return*/@BeanPasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}/*** 定义基于MyBatis-Plus的用户** @return*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsServiceImpl);}/*** 角色继承** @return*/@Beanprotected RoleHierarchy roleHierarchy() {RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();roleHierarchy.setHierarchy("ROLE_admin > ROLE_dba");return roleHierarchy;}@Beanpublic MyUsernamePasswordAuthenticationFilter7007 usernamePasswordAuthenticationFilter() throws Exception {MyUsernamePasswordAuthenticationFilter7007 usernamePasswordAuthenticationFilter = new MyUsernamePasswordAuthenticationFilter7007();usernamePasswordAuthenticationFilter.setFilterProcessesUrl("/login");usernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManager());// 登录成功回调usernamePasswordAuthenticationFilter.setAuthenticationSuccessHandler(successHandler);// 登录失败回调usernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(failureHandler);return usernamePasswordAuthenticationFilter;}@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/dba/**").hasRole("dba").antMatchers("/admin/**").hasRole("admin").antMatchers("/helloWorld", "/verifyCode/getVerifyCode").permitAll().anyRequest().authenticated().and()/*** 注销登录回调*/.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler).permitAll().and().csrf().disable()/*** 未认证 & 权限不足回调*/.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler);http.addFilterAfter(usernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);}}