SpringSecurity过滤器顺序

官网地址 

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

SpringSecurity过滤器顺序_第1张图片

 

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

SpringSecurity过滤器顺序_第2张图片

 

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

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

SpringSecurity过滤器顺序_第3张图片

 

怎么替换默认的过滤器: 

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: 配置跨域

@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			// by default uses a Bean by the name of corsConfigurationSource
			.cors().and()
			...
	}

	@Bean
	CorsConfigurationSource corsConfigurationSource() {
		CorsConfiguration configuration = new CorsConfiguration();
		configuration.setAllowedOrigins(Arrays.asList("https://example.com"));
		configuration.setAllowedMethods(Arrays.asList("GET","POST"));
		UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
		source.registerCorsConfiguration("/**", configuration);
		return source;
	}

 

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

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

 

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

 

 

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

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

 

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

 

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

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

 

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

 

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

 

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

AccessDeniedException访问权限异常

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

SpringSecurity过滤器顺序_第4张图片

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

 http.exceptionHandling()
                .accessDeniedHandler(new MyAccessDeniedHandler())
                .authenticationEntryPoint(new MyAuthenticationEntryPoint());

 

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

 

 

注:

CsrfFilter类

@Override
	protected void doFilterInternal(HttpServletRequest request,
			HttpServletResponse response, FilterChain filterChain)
					throws ServletException, IOException {
		request.setAttribute(HttpServletResponse.class.getName(), response);
        // 获取与session绑定的csrfToken,没有就新建一个
		CsrfToken csrfToken = this.tokenRepository.loadToken(request);
		final boolean missingToken = csrfToken == null;
		if (missingToken) {
			csrfToken = this.tokenRepository.generateToken(request);
			this.tokenRepository.saveToken(csrfToken, request, response);
		}
        
		request.setAttribute(CsrfToken.class.getName(), csrfToken);
		request.setAttribute(csrfToken.getParameterName(), csrfToken);
        
        // 如果不是与csrf相关的请求就直接跳过
		if (!this.requireCsrfProtectionMatcher.matches(request)) {
			filterChain.doFilter(request, response);
			return;
		}
        // 否则直接比对 头部/表单里的csrfToken 和 session绑定的CsrfToken
		String actualToken = request.getHeader(csrfToken.getHeaderName());
		if (actualToken == null) {
			actualToken = request.getParameter(csrfToken.getParameterName());
		}
		if (!csrfToken.getToken().equals(actualToken)) {
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Invalid CSRF token found for "
						+ UrlUtils.buildFullRequestUrl(request));
			}
			if (missingToken) {
				this.accessDeniedHandler.handle(request, response,
						new MissingCsrfTokenException(actualToken));
			}
			else {
				this.accessDeniedHandler.handle(request, response,
						new InvalidCsrfTokenException(csrfToken, actualToken));
			}
			return;
		}

		filterChain.doFilter(request, response);
	}

 

 

 

 

你可能感兴趣的:(spring,security)