Spring Security

Spring Security

  spring提供的安全框架。主要提供了认证和授权的功能。简单梳理看看。
  原理简单说就是Spring Security在基于Servlet应用中,其底层采用了Filter机制实现了对请求的认证,授权和漏洞防御等功能。

DelegatingFilterProxy

  我们知道,Filter是Servlet规范里面的东西。基于Servlet规范,我们可以为ServletR勇气注入一些自定义Filters。
  但是在Spring应用中,实现了Filter接口的Bean无法被Servlet容器感知到。因此,Spring提供了一个DelegatingFilterProxy代理类,DelegatingFilterProxy实现了Filter,因此它可以被注入到FilterChain中,同时,当请求到来时,它会把请求转发到Spring容器中实现了Filter接口的Bean实体。也就是说,DelegatingFilterProxy桥接了Servlet容器和Spring容器。
  默认情况下,DelegatingFilterProxy从Spring容器中获取得到的就是FilterChainProxy实体,而FilterChainProxy也是一个代理类,它最终会将请求转发到SpringSecurity提供的SecurityFilterChain中。
  FilterChainProxy就是Spring Security真正的入口起始点。调试代码的时候,可以将断点设置在FilterChainProxy#doFilter就可以追踪SpringSecurity完整调用流程。

FilterChainProxy

public class FilterChainProxy extends GenericFilterBean {
//FILTER_APPLIED 变量是一个标记,用来标记过滤器是否已经执行过了
	private static final String FILTER_APPLIED = FilterChainProxy.class.getName().concat(".APPLIED");
//filterChains 是过滤器链,注意,这个是过滤器链,而不是一个个的过滤器
	private List<SecurityFilterChain> filterChains;
//filterChainValidator 是 FilterChainProxy 配置完成后的校验方法,默认使用的 NullFilterChainValidator 实际上对应了一个空方法,也就是不做任何校验
	private FilterChainValidator filterChainValidator = new NullFilterChainValidator();
  
  
  //FilterChain为servlet的过滤器链
  @Override
public void doFilter(ServletRequest request, ServletResponse response,
		FilterChain chain) throws IOException, ServletException {
  //为true,表示尚未执行过;false表示,已经标记
	boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
	if (clearContext) {
		try {
			request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
      //执行spring security的过滤器
			doFilterInternal(request, response, chain);
		}
		finally {
      //清除SecurityContextHolder 中保存的用户信息,同时移除 request 中的标记
			SecurityContextHolder.clearContext();
			request.removeAttribute(FILTER_APPLIED);
		}
	}
	else {
		doFilterInternal(request, response, chain);
	}
}

  在 doFilter 方法中,正常来说,clearContext 参数每次都是 true,于是每次都先给 request 标记上 FILTER_APPLIED 属性,然后执行 doFilterInternal 方法去走过滤器,执行完毕后,最后在 finally 代码块中清除 SecurityContextHolder 中保存的用户信息,同时移除 request 中的标记。

private void doFilterInternal(ServletRequest request, ServletResponse response,
		FilterChain chain) throws IOException, ServletException {
	FirewalledRequest fwRequest = firewall
			.getFirewalledRequest((HttpServletRequest) request);
	HttpServletResponse fwResponse = firewall
			.getFirewalledResponse((HttpServletResponse) response);
  //根据当前request,从FilterChainProxy中配置的多个过滤器链(可以只有一个),找到和当前相匹配的一个securityFilterChain,并获取filters
	List<Filter> filters = getFilters(fwRequest);
	if (filters == null || filters.size() == 0) {
		if (logger.isDebugEnabled()) {
			logger.debug(UrlUtils.buildRequestUrl(fwRequest)
					+ (filters == null ? " has no matching filters"
							: " has an empty filter list"));
		}
		fwRequest.reset();
    //如果filters为null,表示当前请求不需要执行security的过滤器链,直接执行servlet上的过滤器链
		chain.doFilter(fwRequest, fwResponse);
		return;
	}
  //如果需要执行security的过滤器链,首先构造一个虚拟的过滤器链
	VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
	vfc.doFilter(fwRequest, fwResponse);
}
 
 
  //request匹配到的过滤器链上的所有filters
private List<Filter> getFilters(HttpServletRequest request) {
	for (SecurityFilterChain chain : filterChains) {
		if (chain.matches(request)) {
			return chain.getFilters();
		}
	}
	return null;
}

  doFilterInternal 方法就比较重要了:

  1. 首先将请求封装为一个 FirewalledRequest 对象,在这个封装的过程中,也会判断请求是否合法。
  2. 对响应进行封装。
  3. 调用 getFilters 方法找到过滤器链。该方法就是根据当前的请求,从 filterChains 中找到对应的过滤器链,然后由该过滤器链去处理请求。
  4. 如果找出来的 filters 为 null,或者集合中没有元素,那就是说明当前请求不需要经过过滤器。直接执行 chain.doFilter ,这个就又回到原生过滤器中去了。那么什么时候会发生这种情况呢?那就是针对项目中的静态资源,如果我们配置了资源放行,如 web.ignoring().antMatchers(“/hello”);,那么当你请求 /hello 接口时就会走到这里来,也就是说这个不经过 Spring Security Filter。
  5. 如果查
  • 17
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值