Spring Security介绍

  • 开源
  • 提供企业级的安全认证和授权

Spring安全拦截器

  • 认证管理器

    • 认证模式

      • Basic

        HTTP 1.0中使用的认证方法,使用用户名和密码Base64编码的方式

        浏览器弹出对话框,用户输入用户名和密码,加入头部

        无状态

        安全性不足

      • Digest

        解决安全性问题

        浏览器对用户名和密码请求方法,URL等进行MD5运算,发送到服务器

        服务器获取到用户名密码,请求方法,URL等MD5运算,查看是否相等

        安全性问题依然存在

      • X.509

  • 访问决策管理器

  • 运行身份管理器

常用权限拦截器

Spring-Security拦截器链流程图

介绍几个常用的Filter

  1. SecurityContextPersistenceFilter

    基于ThreadLocal

  2. LogoutFilter

    发送注销请求时,清空用户的session,cookie,重定向

  3. AbstractAuthenticationProcessingFilter

    用户登录的请求

  4. DefaultLoginPageGeneratingFilter

    生成登录页面

  5. BasicAuthencationFilter

  6. SecurityContextHolderAwareRequestFilter

    包装,提供额外的数据

  7. RememberMeAuthemticationFilter

    提供RememberMe功能,当cookie中存在rememberme时,登录成功后生成唯一cookie

  8. ExceptionTranlationFilter

    请求到对应的页面,响应异常

    ExceptionTranslationFilter异常处理过滤器,该过滤器用来处理在系统认证授权过程中抛出的异常(也就是下一个过滤器FilterSecurityInterceptor),主要是 处理 AuthenticationExceptionAccessDeniedException

  9. SessionManagerFilter

  10. FilterSecurityInterceptor(授权)

    用户没有登录,抛出未登录异常

    用户登录,但是没有权限访问该资源,抛出拒绝访问的异常

    用户登录,有权限,则放行

    此过滤器为认证授权过滤器链中最后一个过滤器,该过滤器之后就是请求真正的 服务

Filter如何执行

FilterChainProxy会按照顺序调用一组Filter,完成授权验证

请求首先经过Servlet Filter链,这里面包含6个Filter

可以看到如下的一个Filter

ApplicationFilterConfig[name=springSecurityFilterChain, filterClass=org.springframework.boot.web.servlet.DelegatingFilterProxyRegistrationBean$1]

这个就是Spring Security Filter的入口,它的类型是DelegationFilterProxy

那么,这个DelegationFilterProxy到底执行了什么样的操作呢?可以简单看一下源码

重点看一下部分的源码:

public class DelegatingFilterProxy extends GenericFilterBean {

    // 类中的属性
@Nullable
private String contextAttribute; @Nullable
private WebApplicationContext webApplicationContext; @Nullable
private String targetBeanName; private boolean targetFilterLifecycle = false; /**
* 重点在于这个属性
*/
@Nullable
private volatile Filter delegate; private final Object delegateMonitor = new Object(); @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException { // Lazily initialize the delegate if necessary.
Filter delegateToUse = this.delegate;
if (delegateToUse == null) {
synchronized (this.delegateMonitor) {
delegateToUse = this.delegate;
if (delegateToUse == null) {
WebApplicationContext wac = findWebApplicationContext();
if (wac == null) {
throw new IllegalStateException("No WebApplicationContext found: " +
"no ContextLoaderListener or DispatcherServlet registered?");
}
delegateToUse = initDelegate(wac);
}
this.delegate = delegateToUse;
}
} // Let the delegate perform the actual doFilter operation.
invokeDelegate(delegateToUse, request, response, filterChain);
}
// ....... /**
* Initialize the Filter delegate, defined as bean the given Spring
* application context.
* <p>The default implementation fetches the bean from the application context
* and calls the standard {@code Filter.init} method on it, passing
* in the FilterConfig of this Filter proxy. * @param wac the root application context
* @return the initialized delegate Filter
* @throws ServletException if thrown by the Filter
*/
protected Filter initDelegate(WebApplicationContext wac) throws ServletException {
String targetBeanName = getTargetBeanName();
Assert.state(targetBeanName != null, "No target bean name set");
Filter delegate = wac.getBean(targetBeanName, Filter.class);
if (isTargetFilterLifecycle()) {
delegate.init(getFilterConfig());
}
return delegate;
} // 调用delegate的doFilter方法
protected void invokeDelegate(
Filter delegate, ServletRequest request, ServletResponse response, FilterChain filterChain)
throws ServletException, IOException { delegate.doFilter(request, response, filterChain);
}
}

根据以上代码的注释我们可以看出大概的执行流程

那类中的Filter delegate是什么呢?断点调式运行可以找到以下东西

这是Spring Security 提供的一个FilterChainProxy,关注其中的关键源码

public class FilterChainProxy extends GenericFilterBean {

    // 包含一组SecurityFilterChain
private List<SecurityFilterChain> filterChains; @Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
if (clearContext) {
try {
request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
doFilterInternal(request, response, chain);
}
finally {
SecurityContextHolder.clearContext();
request.removeAttribute(FILTER_APPLIED);
}
}
else {
doFilterInternal(request, response, chain);
}
} private void doFilterInternal(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException { FirewalledRequest fwRequest = firewall
.getFirewalledRequest((HttpServletRequest) request);
HttpServletResponse fwResponse = firewall
.getFirewalledResponse((HttpServletResponse) response); // 根据请求获取匹配的一组Filter
// 这里返回的Filter就是上述的那些AuthenticationFilter,比如UsernamePasswordAuthenticationFilter
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(); chain.doFilter(fwRequest, fwResponse); return;
} VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
vfc.doFilter(fwRequest, fwResponse);
} /**
* Returns the first filter chain matching the supplied URL.
*
* @param request the request to match
* @return an ordered array of Filters defining the filter chain
*/
private List<Filter> getFilters(HttpServletRequest request) {
for (SecurityFilterChain chain : filterChains) {
if (chain.matches(request)) {
return chain.getFilters();
}
} return null;
} }

到此,我们可以总结出如下的流程图:

最新文章

  1. dp px 转换工具
  2. Android入门(十一)SQLite CURD
  3. Python开发【第七篇】:面向对象
  4. jquery 使用textarea
  5. struts1日期转换处理
  6. 【leetcode❤python】24. Swap Nodes in Pairs
  7. ServiceStack.OrmLite 笔记9 -code first 必须的代码优先
  8. OpenGL的gluLookAt和glOrtho的关系
  9. tomcat log
  10. vmtouch - the Virtual Memory Toucher
  11. myeclipse10.7破解成功 但 无法打war包 securecrt alert:integrity check error 解决方案
  12. 创建理想的SEQUENCE和自增长的trigger
  13. jQuery选择
  14. hdu 3405 world islands
  15. CSS3影子 box-shadow使用和技巧总结
  16. 【转】linux系统中如何进入退出vim编辑器,方法及区别
  17. Tomcat证书安装(pfx和jks)
  18. eregi
  19. 使用Log4net 日志系统
  20. MapReduce业务 - 图片关联计算

热门文章

  1. Django_测试板块(六)
  2. solr - 安装ik中文分词 和初始化富文本检索
  3. 【Spring专场】「AOP容器」不看源码就带你认识核心流程以及运作原理
  4. GoLang设计模式19 - 桥接模式
  5. OSI/RM体系结构
  6. java日志打印使用指南
  7. web刷题记录 极客大挑战2019Knife upload buy a flag
  8. JuiceFS 在理想汽车的使用和展望
  9. Java多线程专题2: JMM(Java内存模型)
  10. Python 单元测试 生产HTML测试报告