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