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

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" propertysetDetails(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 {@Overridepublic 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 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中作出如下修改:
@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().csrf().disable(); http.addFilterAt(customAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); }@BeanCustomAuthenticationFilter customAuthenticationFilter() throws Exception {CustomAuthenticationFilter filter = new CustomAuthenticationFilter(); filter.setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {@Overridepublic 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() {@Overridepublic 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 catchpublic Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {if (request.getContentType().contains(MediaType.APPLICATION_JSON_VALUE)) {ObjectMapper mapper = new ObjectMapper(); Map 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); }}

@EnableWebSecuritypublic class SecurityConfig extends WebSecurityConfigurerAdapter { @Overrideprotected 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; }}

【Spring|Spring security如何重写Filter实现json登录】以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

    推荐阅读