盘点SpringSecurity框架中的八大经典设计模式
有小伙伴建议,源码分析太枯燥了,要是能够结合设计模式一起来,这样更有助于大家理解 Spring Security 源码,同时还能复习一波设计模式。
因此今天就试着整一篇,和大家来聊一聊 Spring Security 中涉及到的设计模式,不过 Spring Security 中涉及到的设计模式还是非常多的,这里跟大家讲几个,剩下的欢迎小伙伴们留言补充。
1.模板方法模式
Template Pattern(模板方法模式)是一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行,这是一种行为型模式。
模板方法方式优点如下:
在父类中提取了公共的部分代码,便于代码复用和扩展。部分方法是由子类实现的,子类可以通过扩展方式增加相应的功能,符合开闭原则。缺点如下:
对每个不同的实现都需要定义一个子类,导致类的个数增加,系统更加复杂,设计也更加抽象。父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,增加了代码理解难度。介绍完模板方法模式,大家可能大概猜到了 Spring Security 中哪些地方用到模板方法模式了。
我举几个简单的例子。
第一个例子是 AbstractUserDetailsAuthenticationProvider 类的设计。大家都知道这个类是用来做验证的,认证的逻辑在这个方法中都定义好了,但是该类却定义了两个抽象方法:
retrieveUser 该方法用户从数据源中获取用户对象。additionalAuthenticationChecks 该方法用来做额外的校验(登录凭证的校验)这两个抽象方法是在 DaoAuthenticationProvider 中实现的。DaoAuthenticationProvider 的实现就是从数据库中加载用户,默认检验登录凭证也都是验证密码。
如果你的数据源来自其他地方,或者登录凭证不是密码,那么自定义类继承自 AbstractUserDetailsAuthenticationProvider 并重写它里边的这两个方法即可。
2.责任链模式
Chain of Responsibility Pattern(责任链模式) ,在这种模式中,通常每个接收者都包含对另一个接收者的引用,如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。在这个过程中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,所以责任链将请求的发送者和请求的处理者解耦了。
责任链模式优点如下:
降低对象之间的耦合度。增强了系统的可扩展性。当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序。简化了对象之间的连接,每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用。责任分担,每个类只需要处理自己该处理的工作,符合类的单一职责原则。缺点如下:
对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。职责链建立的合理性要靠客户端来保证,增加了客户端的复杂性。很明显,Spring Security 中的过滤器链就是一种责任链模式。一个请求到达后,被过滤器链中的过滤器逐个进行处理,
过滤器链中的过滤器每个都具有不同的职能并且互不相扰,我们还可以通过 HttpSecurity 来动态配置过滤器链中的过滤器(即添加/删除过滤器链中的过滤器)。
具体的代码在 FilterChainProxy$VirtualFilterChain 中,如下:
那么接下来我们就来看看 VirtualFilterChain:
private static class VirtualFilterChain implements FilterChain {private final FilterChain originalChain;private final List additionalFilters;private final FirewalledRequest firewalledRequest;private final int size;private int currentPosition = 0;private VirtualFilterChain(FirewalledRequest firewalledRequest,FilterChain chain, List additionalFilters) {iginalChain = chain;this.additionalFilters = additionalFilters;this.size = additionalFilters.size();this.firewalledRequest = firewalledRequest;}@Overridepublic void doFilter(ServletRequest request, ServletResponse response)throws IOException, ServletException {if (currentPosition == size) {if (logger.isDebugEnabled()) {logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)+ " reached end of additional filt
er chain; proceeding with original chain");}// Deactivate path stripping as we exit the security filter set();originalChain.doFilter(request, response);}else {currentPosition++;Filter nextFilter = (currentPosition - 1);if (logger.isDebugEnabled()) {logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)+ " at position " + currentPosition + " of " + size+ " in additional filter chain; firing Filter: ‘"+ Class().getSimpleName() + "’");}nextFilter.doFilter(request, response, this);}}}VirtualFilterChain 类中首先声明了 5 个全局属性,originalChain 表示原生的过滤器链,也就是 Web Filter;additionalFilters 表示 Spring Security 中的过滤器链;firewalledRequest 表示当前请求;size 表示过滤器链中过滤器的个数;currentPosition 则是过滤器链遍历时候的下标。doFilter 方法就是 Spring Security 中过滤器挨个执行的过程,如果 currentPosition == size,表示过滤器链已经执行完毕,此时通过调用 originalChain.doFilter 进入到原生过滤链方法中,同时也退出了 Spring Security 过滤器链。否则就从 additionalFilters 取出 Spring Security 过滤器链中的一个个过滤器,挨个调用 doFilter 方法。nextFilter.doFilter 就是过滤器链挨个往下走。关于 FilterChainProxy 的介绍,参见:[深入理解 FilterChainProxy【源码篇】]
3.策略模式
Strategy Pattern(策略模式),它定义了一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式(Policy)。
策略模式的优点:
策略模式提供了对“开闭原则”的完美支持,用户可以在不修改原有系统的基础上选择具体的策略,也可以灵活地扩展新的策略。策略模式提供了管理相关的策略的方式。策略模式提供了可以替换继承关系的办法。使用策略模式可以避免使用多重条件转移语句。策略模式的缺点:
客户端必须知道所有的策略类,并自行决定使用哪一个策略类。策略模式将造成产生很多策略类(可以通过使用享元模式在一定程度上减少对象的数量)。Spring Security 中使用策略模式的地方也有好几个。
第一个就是用户登录信息存储。
在 SecurityContextHolder 中定义登录用户信息存储的方法,就定义了三种不同的策略:
public class SecurityContextHolder {// ~ Static fields/initializers// =====================================================================================
public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";
public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";
public static final String MODE_GLOBAL = "MODE_GLOBAL";
public static final String SYSTEM_PROPERTY = "spring.security.strategy";
private static String strategyName = Property(SYSTEM_PROPERTY);
private static SecurityContextHolderStrategy strategy;
}用户可以自行选择使用哪一种策略!具体参见:[在 Spring Security 中,我就想从子线程获取用户登录信息,怎么办?]
spring系列框架有哪些
还有一个就是 session 并发管理。
在 AbstractAuthenticationProcessingFilter#doFilter 方法中,有如下代码:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException {//省略Authentication(authResult, request, response);//省略}这就是一种策略模式。
Session 并发管理可以参考:
[什么是会话固定攻击?Spring Boot 中要如何防御会话固定攻击?][集化部署,Spring Security 要如何处理 session 共享?]当然,这样的例子还有很多,我就不一一列举了。
4.代理模式
Proxy Pattern(代理模式) :给某一个对象提供一个代理,并由代理对象控制对原对象的引用,它是一种对象结构型模式。
代理模式的优点:
一定程度上降低了系统的耦合度。代理对象可以扩展目标对象的功能。代理对象可以保护目标对象。缺点:
在客户端和真实对象之间增加了代理,可能会导致请求的处理速度变慢。增加了系统复杂度。代理模式在 Spring Security 中最重要的应用就是 Spring Security 过滤器链接入 Web Filter 的过程,使用了 Spring 提供的 DelegatingFilterProxy,这就是一个典型的代理模式:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。