系列十一、Spring Security登录接口兼容JSON格式登录

一、Spring Security登录接口兼容JSON格式登录

1.1、概述

        前后端分离中,前端和后端的数据交互通常是JSON格式,而Spring Security的登录接口默认支持的是form-data或者x-www-form-urlencoded的,如下所示:

系列十一、Spring Security登录接口兼容JSON格式登录_第1张图片

系列十一、Spring Security登录接口兼容JSON格式登录_第2张图片

那么如何让Spring Security的登录接口也支持JSON格式登录呢?请看下文分析 

1.2、自定义过滤器

/**
 * @Author : 一叶浮萍归大海
 * @Date: 2024/1/13 9:30
 * @Description:
 */
public class MyUsernamePasswordAuthenticationFilter7007 extends UsernamePasswordAuthenticationFilter {

    @Override
    public 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 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 {

    @Resource
    private MyAuthenticationSuccessHandler7007 successHandler;
    @Resource
    private MyAuthenticationFailureHandler7007 failureHandler;
    @Resource
    private MyLogoutSuccessHandler7007 logoutSuccessHandler;
    @Resource
    private MyAuthenticationEntryPoint7007 authenticationEntryPoint;
    @Resource
    private MyAccessDeniedHandler7007 accessDeniedHandler;
    @Resource
    private UserDetailsService userDetailsServiceImpl;

    /**
     * 密码加密器
     *
     * @return
     */
    @Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    /**
     * 定义基于MyBatis-Plus的用户
     *
     * @return
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsServiceImpl);
    }

    /**
     * 角色继承
     *
     * @return
     */
    @Bean
    protected RoleHierarchy roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        roleHierarchy.setHierarchy("ROLE_admin > ROLE_dba");

        return roleHierarchy;
    }

    @Bean
    public MyUsernamePasswordAuthenticationFilter7007 usernamePasswordAuthenticationFilter() throws Exception {
        MyUsernamePasswordAuthenticationFilter7007 usernamePasswordAuthenticationFilter = new MyUsernamePasswordAuthenticationFilter7007();
        usernamePasswordAuthenticationFilter.setFilterProcessesUrl("/login");
        usernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManager());
        // 登录成功回调
        usernamePasswordAuthenticationFilter.setAuthenticationSuccessHandler(successHandler);
        // 登录失败回调
        usernamePasswordAuthenticationFilter.setAuthenticationFailureHandler(failureHandler);
        return usernamePasswordAuthenticationFilter;

    }

    @Override
    protected 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);
    }

}

1.4、测试

系列十一、Spring Security登录接口兼容JSON格式登录_第3张图片

你可能感兴趣的:(Spring,Security,OAuth2.0系列,Spring,Security,OAuth2)