SpringSecurity过滤器顺序(转)

SpringSecurity过滤器顺序

官网地址 

官网定义的关键过滤器顺序:

 

源码里所有的过滤器顺序:

 

默认情况会启动以下过滤器:

(默认设置在:WebSecurityConfigurerAdapter 的  getHttp()方法里)

 

怎么替换默认的过滤器: 

http.addFilterAt() 不能替换默认的过滤器,只是在相同的位置放置一个过滤器,原本的过滤器仍然起作用

可以disable掉默认的过滤器,例如用自定义的登出过滤器

http.logout().disable();

http.addFilterAt(new MyLogoutFilter(), LogoutFilter.class);

部分过滤器的含义:

ChannelProcessingFilter:转换协议时使用,例如将http重定向到https

ConcurrentSessionFilter:判断session是否过期以及更新最新访问时间

SecurityContextPersistenceFilter:将用户信息绑定到线程

这样全局可通过SecurityContextHolder.getContext().getAuthentication()拿到用户信息

注:如果要拿到request/response信息(这个不是过滤器设置的,是框架默认会绑定到线程)

可通过((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest()

HeaderWriterFilter:默认增加以下头部信息

X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY

关闭:http.headers().disable();

只保留缓存控制:http.headers().defaultsDisabled().cacheControl()

注:详细描述可查看官网地址

X-Content-Type-Options: nosniff 表示浏览器必须且只能根据Content-Type字段分辨资源类型(浏览器默认会 猜测资源类型)

X-XSS-Protection:防范XSS攻击

  • 0:禁用XSS保护;
  • 1:启用XSS保护;
  • 1; mode=block:启用XSS保护,并在检查到XSS攻击时,停止渲染页面(例如IE8中,检查到攻击时,整个页面会被一个#替换);

X-Frame-Options:是否允许页面被嵌套

DENY  表示该页面不允许在 frame 中展示,即便是在相同域名的页面中嵌套也不允许
SAMEORIGIN  表示该页面可以在相同域名页面的 frame 中展示
ALLOW-FROM uri  表示该页面可以在指定来源的 frame 中展示

Cache-Control/Pragma/Expires:缓存控制(简单描述

CorsFilter: 配置跨域

  1.  
    @Override
  2.  
    protected void configure(HttpSecurity http) throws Exception {
  3.  
    http
  4.  
    // by default uses a Bean by the name of corsConfigurationSource
  5.  
    .cors().and()
  6.  
    ...
  7.  
    }
  8.  
     
  9.  
    @Bean
  10.  
    CorsConfigurationSource corsConfigurationSource() {
  11.  
    CorsConfiguration configuration = new CorsConfiguration();
  12.  
    configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
  13.  
    configuration.setAllowedMethods(Arrays.asList("GET","POST"));
  14.  
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
  15.  
    source.registerCorsConfiguration("/**", configuration);
  16.  
    return source;
  17.  
    }

CsrfFilter: 防止Csrf攻击,通过配置与Session绑定的token,每次请求都需要携带最新的token

注:默认是在前后端不分离的情况下,通过jsp/ft等传递到前端。在前后端分离的情况下,可以增加过滤器使其配置在 json/或者头部

LogoutFilter:配置登出的处理 一般可设置登出成功的处理,删除cookie,使Session无效等

UsernamePasswordAuthenticationFilter:验证登录,并可以配置登录成功/失败的处理

  1.  
    http.formLogin() // 表单登录
  2.  
    // 登录的界面,前后端分离时不需要这个配置。没登录去访问系统资源时会重定向到这个界面
  3.  
    .loginPage("/login/home")
  4.  
    // 登录验证,框架自动实现
  5.  
    .loginProcessingUrl("/login/verify")
  6.  
    // 如果直接访问的是登录界面login1,返回的URL,否则会返回重定向到原本请求的URL
  7.  
    .successHandler(myAuthenticationSuccessHandler)
  8.  
    // 失败返回的URL
  9.  
    .failureHandler(myAuthenticationFailureHandler)

SecurityContextHolderAwareRequestFilter: 包装类,实现HttpServletRequest的getAuthentication getRemoteUser等方法

RememberMeAuthenticationFilter: 配置rememberMe,比如7天之内不需要登录

当拿不到用户信息时(SecurityContextHolder.getContext()为空),会去找key是remember-me的Cookie配置用户信息

AnonymousAuthenticationFilter:没有通过username和remember认证的用户赋予匿名身份

SessionManagementFilter:session管理:限制同一用户开启多个会话的数量

ExceptionTranslationFilter:一般其只处理两大类异常:

AccessDeniedException访问权限异常

AuthenticationException用户认证异常:包括匿名用户异常

配置自定义的401和403异常处理:

  1.  
     http.exceptionHandling()
  2.  
                    .accessDeniedHandler(new MyAccessDeniedHandler())
  3.  
                    .authenticationEntryPoint(new MyAuthenticationEntryPoint());

FilterSecurityInterceptor :拿到用户的权限(从SecurityContextHolder中获取Authentication对象)和资源所需权限(SecurityMetadataSource),在AccessDecisionManager里对比看用户是否有权限

注:

CsrfFilter类

  1.  
    @Override
  2.  
    protected void doFilterInternal(HttpServletRequest request,
  3.  
    HttpServletResponse response, FilterChain filterChain)
  4.  
    throws ServletException, IOException {
  5.  
    request.setAttribute(HttpServletResponse.class.getName(), response);
  6.  
    // 获取与session绑定的csrfToken,没有就新建一个
  7.  
    CsrfToken csrfToken = this.tokenRepository.loadToken(request);
  8.  
    final boolean missingToken = csrfToken == null;
  9.  
    if (missingToken) {
  10.  
    csrfToken = this.tokenRepository.generateToken(request);
  11.  
    this.tokenRepository.saveToken(csrfToken, request, response);
  12.  
    }
  13.  
     
  14.  
    request.setAttribute(CsrfToken.class.getName(), csrfToken);
  15.  
    request.setAttribute(csrfToken.getParameterName(), csrfToken);
  16.  
     
  17.  
    // 如果不是与csrf相关的请求就直接跳过
  18.  
    if (!this.requireCsrfProtectionMatcher.matches(request)) {
  19.  
    filterChain.doFilter(request, response);
  20.  
    return;
  21.  
    }
  22.  
    // 否则直接比对 头部/表单里的csrfToken 和 session绑定的CsrfToken
  23.  
    String actualToken = request.getHeader(csrfToken.getHeaderName());
  24.  
    if (actualToken == null) {
  25.  
    actualToken = request.getParameter(csrfToken.getParameterName());
  26.  
    }
  27.  
    if (!csrfToken.getToken().equals(actualToken)) {
  28.  
    if (this.logger.isDebugEnabled()) {
  29.  
    this.logger.debug("Invalid CSRF token found for "
  30.  
    + UrlUtils.buildFullRequestUrl(request));
  31.  
    }
  32.  
    if (missingToken) {
  33.  
    this.accessDeniedHandler.handle(request, response,
  34.  
    new MissingCsrfTokenException(actualToken));
  35.  
    }
  36.  
    else {
  37.  
    this.accessDeniedHandler.handle(request, response,
  38.  
    new InvalidCsrfTokenException(csrfToken, actualToken));
  39.  
    }
  40.  
    return;
  41.  
    }
  42.  
     
  43.  
    filterChain.doFilter(request, response);
  44.  
    }
原文地址:https://www.cnblogs.com/yasepix/p/14185895.html