spring security 使用 application/json 接收数据


不了解 security 的请看 security 的简单使用

https://blog.51cto.com/5013162/2404946


在使用 spring security 登录用户的时候 发现使用 application/josn 后台不能获取到数据 看 UsernamePasswordAuthenticationFilter 源码发现

	//获取密码
	protected String obtainPassword(HttpServletRequest request) {
		 return request.getParameter(passwordParameter);
	}
	//获取用户名
	protected String obtainUsername(HttpServletRequest request) {
		 return request.getParameter(usernameParameter);
	}

是直接从request 获取的 不是从 requestBody 中获取的

那我们就只需要重写这两个方法从 requestBody 中获取参数

重写 UsernamePasswordAuthenticationFilter 类

	public class UserAuthenticationFilter extends UsernamePasswordAuthenticationFilter {


		private ThreadLocal<Map<String,String>> threadLocal = new ThreadLocal<>();

		@Override
		protected String obtainPassword(HttpServletRequest request) {
				String password = this.getBodyParams(request).get(super.SPRING_SECURITY_FORM_PASSWORD_KEY);
				if(!StringUtils.isEmpty(password)){
						return password;
				}
				return super.obtainPassword(request);
		}

		@Override
		protected String obtainUsername(HttpServletRequest request) {
				String username = this.getBodyParams(request).get(super.SPRING_SECURITY_FORM_USERNAME_KEY);
				if(!StringUtils.isEmpty(username)){
						return username;
				}
				return super.obtainUsername(request);
		}

		/**
		 * 获取body参数  body中的参数只能获取一次 
		 * @param request
		 * @return
		 */
		private Map<String,String> getBodyParams(HttpServletRequest request){
				Map<String,String> bodyParams =  threadLocal.get();
				if(bodyParams==null) {
						ObjectMapper objectMapper = new ObjectMapper();
						try (InputStream is = request.getInputStream()) {
								bodyParams = objectMapper.readValue(is, Map.class);
						} catch (IOException e) {
						}
						if(bodyParams==null) bodyParams = new HashMap<>();
						threadLocal.set(bodyParams);
				}

				return bodyParams;
		}
}

自定义 SecurityConfig 类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

		@Autowired
		UserDetailServiceImpl userDetailService;
		@Autowired
		LoginSuccessHandler loginSuccessHandler;

		@Override
		protected void configure(AuthenticationManagerBuilder auth) throws Exception {
				//自定义用户验证和加密方式
				auth.userDetailsService(userDetailService).passwordEncoder(new BCryptPasswordEncoder());
		}

		@Override
		protected void configure(HttpSecurity http) throws Exception {
				http.formLogin()                    //  定义当需要用户登录时候,转到的登录页面。
		//          .loginPage("/login.html") //自定义登录页面
//                .loginProcessingUrl("/login") //自定义登录接口地址
//                .successHandler(loginSuccessHandler)
								.and()
								// 定义哪些URL需要被保护、哪些不需要被保护
								.authorizeRequests().antMatchers("/login").permitAll() //不需要保护的URL
								.anyRequest()               // 任何请求,登录后可以访问
								.authenticated()
								.and()
								.logout().logoutSuccessUrl("/login").permitAll() // 登出
								.and()
								.csrf().disable();
				//配置自定义过滤器 增加post json 支持
				http.addFilterAt(UserAuthenticationFilterBean(), UsernamePasswordAuthenticationFilter.class);
		}


		private UserAuthenticationFilter UserAuthenticationFilterBean() throws Exception {
				UserAuthenticationFilter userAuthenticationFilter = new UserAuthenticationFilter();
				userAuthenticationFilter.setAuthenticationManager(super.authenticationManager());
				userAuthenticationFilter.setAuthenticationSuccessHandler(loginSuccessHandler);
				return userAuthenticationFilter;
		}
}

登录成功处理类 LoginSuccessHandler.class

@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
		@Override
		public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {

				httpServletResponse.setContentType("application/json;charset=UTF-8");

				httpServletResponse.getWriter().write(authentication.getName());
		}
}

用户校验处理类

@Component
public class UserDetailServiceImpl implements UserDetailsService {
		/**
		 * 用户校验
		 * @param s
		 * @return
		 * @throws UsernameNotFoundException
		 */
		@Override
		public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
				Collection<GrantedAuthority> collection = new ArrayList<>();//权限集合
				String password = new BCryptPasswordEncoder().encode("123456");
				User user = new User(s,password,collection);

				return user;
		}

}

改造完成 支持 post application/json 同时也支持 post form-data/x-www-form-urlencoded 都可以获取到传入的参数