好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

Spring security 重写Filter实现json登录

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

JSON登录

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

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传递用户名密码,只需要将这个过滤器替换掉即可,自定义过滤器如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

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中作出如下修改:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

@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登录

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

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);

     }

}

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

@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登录的详细内容...

  阅读:30次