目录
自定义认证授权过滤器
1、SpringSecurity内置认证流程
通过研究SpringSecurity内置基于form表单认证的UsernamePasswordAuthenticationFilter过滤器,我们可以仿照自定义认证过滤器:
内置认证过滤器的核心流程:
核心流程梳理如下:
-
认证过滤器(UsernamePasswordAuthentionFilter)接收form表单提交的账户、密码信息,并封装成UsernamePasswordAuthenticationToken认证凭对象;
-
认证过滤器调用认证管理器AuthenticationManager进行认证处理;
-
认证管理器通过调用用户详情服务获取用户详情UserDetails;
-
认证管理器通过密码匹配器PasswordEncoder进行匹配,如果密码一致,则将用户相关的权限信息一并封装到Authentication认证对象中;
-
认证过滤器将Authentication认证过滤器放到认证上下文,方便请求从上下文获取认证信息;
1.1 自定义认证过滤器
UsernamePasswordAuthentionFilter过滤器继承了模板认证过滤器AbstractAuthenticationProcessingFilter抽象类,我们也可仿照实现:
-
public class MyUserNamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter { /** * 设置构造,传入自定义登录url地址 * @param defaultFilterProcessesUrl */ public MyUserNamePasswordAuthenticationFilter(String defaultFilterProcessesUrl) { super(defaultFilterProcessesUrl); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { //判断请求方法必须是post提交,且提交的数据的内容必须是application/json格式的数据 if (!request.getMethod().equals("POST") || ! (request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE) || request.getContentType().equalsIgnoreCase(MediaType.APPLICATION_JSON_UTF8_VALUE))) { throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod()); } //获取请求参数 //获取reqeust请求对象的发送过来的数据流 ServletInputStream in = request.getInputStream(); //将数据流中的数据反序列化成Map HashMap<String,String> loginInfo = new ObjectMapper().readValue(in, HashMap.class); String username = loginInfo.get(USER_NAME); username = (username != null) ? username : ""; username = username.trim(); String password = loginInfo.get(PASSWORD); password = (password != null) ? password : ""; //将用户名和密码信息封装到认证票据对象下 UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password); // Allow subclasses to set the "details" property //setDetails(request, authRequest); //调用认证管理器认证指定的票据对象 return this.getAuthenticationManager().authenticate(authRequest); } /** * 认证成功处理方法 * @param request * @param response * @param chain * @param authResult * @throws IOException * @throws ServletException */ @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException { response.getWriter().write("login success 666....."); } /** * 认证失败处理方法 * @param request * @param response * @param failed * @throws IOException * @throws ServletException */ @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException { response.getWriter().write("login failue 999"); } }
自己定义后要注入对应的bean
-
1.2 注入对应的bean
-
@Service("userDetailsService") public class MyUserDetailServiceImpl implements UserDetailsService { @Autowired private TbUserMapper tbUserMapper; /** * 使用security当用户认证时,会自动将用户的名称注入到该方法中 * 然后我们可以自己写逻辑取加载用户的信息,然后组装成UserDetails认证对象 * @param userName * @return 用户的基础信息,包含密码和权限集合,security底层会自动比对前端输入的明文密码 * @throws UsernameNotFoundException */ @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { //1.根据用户名称获取用户的账户信息 TbUser dbUser=tbUserMapper.findUserInfoByName(userName); //判断该用户是否存在 if (dbUser==null) { throw new UsernameNotFoundException("用户名输入错误!"); } //2.组装UserDetails对象 //获取当前用户对应的权限集合(自动将以逗号间隔的权限字符串封装到权限集合中) List<GrantedAuthority> list = AuthorityUtils.commaSeparatedStringToAuthorityList(dbUser.getRoles()); /* 参数1:账户 参数2:密码 参数3:权限集合 */ User user = new User(dbUser.getUsername(), dbUser.getPassword(), list); return user; } }
1.3 定义SecurityConfig类
配置默认认证过滤器,保证自定义的认证过滤器要在默认的认证过滤器之前;
/** * 配置授权策略 * @param http * @throws Exception */ @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable();//禁用跨站请求伪造 http.authorizeRequests()//对资源进行认证处理 .antMatchers("/authentication/form").permitAll()//登录路径无需拦截 .anyRequest().authenticated(); //除了上述资源外,其它资源,只有 认证通过后,才能有权访问 http //坑-过滤器要添加在默认过滤器之前,否则,登录失效 .addFilterBefore(myUserNamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); } @Bean public MyUserNamePasswordAuthenticationFilter myUserNamePasswordAuthenticationFilter() throws Exception { //设置默认登录路径 MyUserNamePasswordAuthenticationFilter myUserNamePasswordAuthenticationFilter = new MyUserNamePasswordAuthenticationFilter("/authentication/form"); myUserNamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManagerBean()); return myUserNamePasswordAuthenticationFilter; }