Spring security如何重写Filter实现json登录

作者:李昊轩的博客 时间:2023-09-15 13:33:31 

Spring security 重写Filter实现json登录

在使用SpringSecurity中,大伙都知道默认的登录数据是通过key/value的形式来传递的,默认情况下不支持JSON格式的登录数据,如果有这种需求,就需要自己来解决,本文主要解决此问题:

JSON登录

上面演示的是一种原始的登录方案,如果想将用户名密码通过JSON的方式进行传递,则需要自定义相关过滤器,通过分析源码我们发现,默认的用户名密码提取在UsernamePasswordAuthenticationFilter过滤器中,部分源码如下:


public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
   public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
   public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
   private String usernameParameter = SPRING_SECURITY_FORM_USERNAME_KEY;
   private String passwordParameter = SPRING_SECURITY_FORM_PASSWORD_KEY;
   private boolean postOnly = true;
   public UsernamePasswordAuthenticationFilter() {
       super(new AntPathRequestMatcher("/login", "POST"));
   }
   public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
       if (postOnly && !request.getMethod().equals("POST")) {
           throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
       }
       String username = obtainUsername(request);
       String password = obtainPassword(request);
       if (username == null) {
           username = "";
       }
       if (password == null) {
           password = "";
       }
       username = username.trim();
       UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);        // Allow subclasses to set the "details" property        
       setDetails(request, authRequest);
       return this.getAuthenticationManager().authenticate(authRequest);
   }
   protected String obtainPassword(HttpServletRequest request) {
       return request.getParameter(passwordParameter);
   }
   protected String obtainUsername(HttpServletRequest request) {
       return request.getParameter(usernameParameter);
   }    
   //...    
   //...
}

从这里可以看到,默认的用户名/密码提取就是通过request中的getParameter来提取的,如果想使用JSON传递用户名密码,只需要将这个过滤器替换掉即可,自定义过滤器如下:


public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

@Override
   public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
       if (request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE) || request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
           ObjectMapper mapper = new ObjectMapper();
           UsernamePasswordAuthenticationToken authRequest = null;
           try (InputStream is = request.getInputStream()) {
               Map<String, String> authenticationBean = mapper.readValue(is, Map.class);
               authRequest = new UsernamePasswordAuthenticationToken(authenticationBean.get("username"), authenticationBean.get("password"));
           } catch (IOException e) {
               e.printStackTrace();
               authRequest = new UsernamePasswordAuthenticationToken("", "");
           } finally {
               setDetails(request, authRequest);
               return this.getAuthenticationManager().authenticate(authRequest);
           }
       } else {
           return super.attemptAuthentication(request, response);
       }
   }
}

这里只是将用户名/密码的获取方案重新修正下,改为了从JSON中获取用户名密码,然后在SecurityConfig中作出如下修改:


@Override
protected void configure(HttpSecurity http) throws Exception {
           http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().csrf().disable();
           http.addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
CustomAuthenticationFilter customAuthenticationFilter() throws Exception {
           CustomAuthenticationFilter filter = new CustomAuthenticationFilter();
           filter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {
               @Override
               public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp, Authentication authentication) throws IOException, ServletException {
                   resp.setContentType("application/json;charset=utf-8");
                   PrintWriter out = resp.getWriter();
                   RespBean respBean = RespBean.ok("登录成功!");
                   out.write(new ObjectMapper().writeValueAsString(respBean));
                   out.flush();
                   out.close();
               }
           });
           filter.setAuthenticationFailureHandler(new AuthenticationFailureHandler() {
               @Override
               public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp, AuthenticationException e) throws IOException, ServletException {
                   resp.setContentype("application/json;charset=utf-8");
                   PrintWriter out = resp.getWriter();
                   RespBean respBean = RespBean.error("登录失败!");
                   out.write(new ObjectMapper().writeValueAsString(respBean));
                   out.flush();
                   out.close();
               }
           });
           filter.setAuthenticationManager(authenticationManagerBean());
           return filter;
       }

搞定~

Spring security5 使用json登录


public class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

@Override
   @SneakyThrows(IOException.class) //lombok try catch
   public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
       if (request.getContentType().contains(MediaType.APPLICATION_JSON_VALUE)) {
           ObjectMapper mapper = new ObjectMapper();
           Map<String,String> map = mapper.readValue(request.getInputStream(), Map.class);
           String username = map.get(super.getUsernameParameter());
           String password = map.get(super.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);
       }
       return super.attemptAuthentication(request, response);
   }
}

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Override
   protected void configure(HttpSecurity http) throws Exception {
      http.addFilterAt(usernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class)
   }

CustomUsernamePasswordAuthenticationFilter usernamePasswordAuthenticationFilter() throws Exception {
       CustomUsernamePasswordAuthenticationFilter filter = new CustomUsernamePasswordAuthenticationFilter();
       filter.setAuthenticationManager(super.authenticationManagerBean());
       filter.setFilterProcessesUrl(customSecurityProperties.getLoginUrl());
       //处理登录成功
       filter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandler());
       //处理登录失败
       filter.setAuthenticationFailureHandler(new AuthenticationFailureHandler());
       return filter;
   }
}

来源:https://haoxuanli.blog.csdn.net/article/details/104409200

标签:Spring,security,Filter,json登录
0
投稿

猜你喜欢

  • Android 老生常谈LayoutInflater的新认知

    2023-01-02 07:01:08
  • 详解Mybatis Generator的具体使用教程

    2022-01-16 22:39:13
  • Android 连接Wifi和创建Wifi热点的实例

    2022-07-16 06:00:52
  • C#中分部类和分部方法的应用

    2022-08-16 06:49:05
  • 使用@ConfigurationProperties实现类型安全的配置过程

    2023-07-01 00:26:05
  • Android Studio项目中导入开源库的方法

    2022-02-02 02:40:27
  • SpringBoot中使用JeecgBoot的Autopoi导出Excel的方法步骤

    2023-03-31 03:38:11
  • Java对世界不同时区timezone之间时间转换的处理方法

    2023-11-08 13:19:30
  • 在Winform程序中使用Spire.Pdf实现页面添加印章功能的实现

    2022-05-29 16:57:27
  • 使用logback实现按自己的需求打印日志到自定义的文件里

    2022-05-12 16:56:49
  • C#中Task.Yield的用途深入讲解

    2022-11-12 00:16:23
  • Java单例模式分析

    2023-11-16 03:17:06
  • android自定义控件实现简易时间轴(2)

    2021-10-03 06:52:39
  • Java 的 FileFilter文件过滤与readline读行操作实例代码

    2022-04-09 07:22:53
  • android播放器实现歌词显示功能

    2021-10-27 13:44:37
  • WCF实现进程间管道通信Demo分享

    2022-10-22 04:20:06
  • android studio数据存储建立SQLite数据库实现增删查改

    2023-11-29 17:11:42
  • Java实现控制台输出两点间距离

    2023-05-18 11:49:11
  • Android 应用中跳转到应用市场评分示例

    2023-02-14 04:03:22
  • SpringBoot Validation提示信息国际化配置方式

    2021-08-21 09:27:32
  • asp之家 软件编程 m.aspxhome.com