一、先从配置类入手,主要是@Bean了一个ShiroFilterFactoryBean:

@Data
@Configuration
@Slf4j
@EnableConfigurationProperties(ShiroProperties.class)
public class ShiroConfiguration { //.......这里省略了大部分跟主题无关的配置代码 /**
* 这里名字叫 shiroFilter,后续通过FilterRegistrationBean从spring容器中向servlet容器中注册filter
* @param securityManager
* @return
* @author
* @create
*/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean getShiroFilterFactoryBean (DefaultWebSecurityManager securityManager,
ShiroProperties sp,IUserService userService){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置 SecurityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
//配置shiroFilter子过滤器
loadFilter(shiroFilterFactoryBean,getCasFilter(sp,userService),getJwtFilter(),getWeComFilter());
//配置拦截规则
loadShiroFilterChain(shiroFilterFactoryBean, sp);
return shiroFilterFactoryBean;
}   /**
* CAS过滤器
*/
@Bean
public CustomizedCasFilter getCasFilter(ShiroProperties sp, IUserService userService) {
CustomizedCasFilter casFilter = new CustomizedCasFilter();
//.......
return casFilter;
} /**
* JWT过滤器
*
* @return
* @author
* @create 2020年8月19日
*/
@Bean
public CustomizedJwtFilter getJwtFilter() {
CustomizedJwtFilter jwtFilter = new CustomizedJwtFilter();
return jwtFilter;
} /**
* 企业微信过滤器
* @param
* @return
*/
@Bean
public CustomizedWeComFilter getWeComFilter() {
CustomizedWeComFilter weComFilter = new CustomizedWeComFilter();
return weComFilter;
} /**
* 添加过滤器
* @param bean
* @param casFilter
* @param jwtFilter
*/
private void loadFilter(ShiroFilterFactoryBean bean,CasFilter casFilter,
CustomizedJwtFilter jwtFilter,
CustomizedWeComFilter weComFilter) {
Map<String, Filter> filters = new HashMap<>();
filters.put("cas", casFilter);
filters.put("jwt", jwtFilter);
filters.put("weCom",weComFilter);
bean.setFilters(filters);
} /**
* 加载shiroFilter权限控制规则
*
* @author
* @create
*/
private void loadShiroFilterChain (ShiroFilterFactoryBean shiroFilterFactoryBean, ShiroProperties sp){
//下面这些规则配置最好配置到配置文件中
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
// shiro集成cas后,首先添加该规则
filterChainDefinitionMap.put("/api/**", "jwt");
filterChainDefinitionMap.put("/cas/**", "cas");
filterChainDefinitionMap.put("/wecom/**", "weCom");
filterChainDefinitionMap.put("/test/**", "anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
} /**
* 在spring容器处在某一声明周期时时,为shiro中的相关bean执行对应的bean生命周期方法
*
* @author
* @create
*/
@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor () {
return new LifecycleBeanPostProcessor();
} .......
}

 

二、ShiroFilterFactoryBean(源码解析,代码中注释带序号的为代码执行顺序)-- 向Spring容器中注入了SpringShiroFilter:

public class ShiroFilterFactoryBean implements FactoryBean, BeanPostProcessor {
private static final transient Logger log = LoggerFactory.getLogger(ShiroFilterFactoryBean.class);
private SecurityManager securityManager;
//这里是我们向注入的多个filter 见配置类中的loadFilter()方法
private Map<String, Filter> filters = new LinkedHashMap();
private List<String> globalFilters = new ArrayList();
//见配置类中loadShiroFilterChain
private Map<String, String> filterChainDefinitionMap;
private String loginUrl;
private String successUrl;
private String unauthorizedUrl;
private AbstractShiroFilter instance; public ShiroFilterFactoryBean() {
this.globalFilters.add(DefaultFilter.invalidRequest.name());
this.filterChainDefinitionMap = new LinkedHashMap();
} public SecurityManager getSecurityManager() {
return this.securityManager;
} ...... public Map<String, Filter> getFilters() {
return this.filters;
} public Map<String, String> getFilterChainDefinitionMap() {
return this.filterChainDefinitionMap;
} ...... // 1、 这里会在spring容器加载的时候调用,向spring容器中注入getObject()返回的对象
public Object getObject() throws Exception {
if (this.instance == null) {
//2、调用createInstance()方法
this.instance = this.createInstance();
} return this.instance;
} public Class getObjectType() {
return ShiroFilterFactoryBean.SpringShiroFilter.class;
} public boolean isSingleton() {
return true;
} protected FilterChainManager createFilterChainManager() {
DefaultFilterChainManager manager = new DefaultFilterChainManager();
    
Map<String, Filter> defaultFilters = manager.getFilters();
Iterator var3 = defaultFilters.values().iterator(); while(var3.hasNext()) {
Filter filter = (Filter)var3.next();
this.applyGlobalPropertiesIfNecessary(filter);
}      //4、在这个地方获取了shiroFilter中的子过滤器,即我们在配置类中设置的loadFilter()
Map<String, Filter> filters = this.getFilters();
String name;
Filter filter;
if (!CollectionUtils.isEmpty(filters)) {        //5、这个地方迭代,并将子过滤器添加到了manager中
for(Iterator var10 = filters.entrySet().iterator(); var10.hasNext(); manager.addFilter(name, filter, false)) {
Entry<String, Filter> entry = (Entry)var10.next();
name = (String)entry.getKey();
filter = (Filter)entry.getValue();
this.applyGlobalPropertiesIfNecessary(filter);
if (filter instanceof Nameable) {
((Nameable)filter).setName(name);
}
}
} manager.setGlobalFilters(this.globalFilters);
Map<String, String> chains = this.getFilterChainDefinitionMap();
if (!CollectionUtils.isEmpty(chains)) {
Iterator var12 = chains.entrySet().iterator(); while(var12.hasNext()) {
Entry<String, String> entry = (Entry)var12.next();
String url = (String)entry.getKey();
String chainDefinition = (String)entry.getValue();
          //这里很重要 后面DefaultFilterChainManager filterChains属性在这里添加值
manager.createChain(url, chainDefinition);
}
}      //这里很重要 后面DefaultFilterChainManager filterChains属性在这里添加值
manager.createDefaultChain("/**");
return manager;
} protected AbstractShiroFilter createInstance() throws Exception {
log.debug("Creating Shiro Filter instance.");
SecurityManager securityManager = this.getSecurityManager();
String msg;
if (securityManager == null) {
msg = "SecurityManager property must be set.";
throw new BeanInitializationException(msg);
} else if (!(securityManager instanceof WebSecurityManager)) {
msg = "The security manager does not implement the WebSecurityManager interface.";
throw new BeanInitializationException(msg);
} else {    //3、调用createFilterChainManager()
FilterChainManager manager = this.createFilterChainManager();
PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver(); //6、将manager注入到chainResolver中,此时的manager有子过滤器,因而chainResolver也是可以获取到子过滤器的
chainResolver.setFilterChainManager(manager);        //7、返回SpringShiroFilter对象,即向Spring容器中注入SpringShiroFilter bean对象(带chain)
return new ShiroFilterFactoryBean.SpringShiroFilter((WebSecurityManager)securityManager, chainResolver);
}
} //.........删除无关代码 private void applyGlobalPropertiesIfNecessary(Filter filter) {
this.applyLoginUrlIfNecessary(filter);
this.applySuccessUrlIfNecessary(filter);
this.applyUnauthorizedUrlIfNecessary(filter);
} public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Filter) {
log.debug("Found filter chain candidate filter '{}'", beanName);
Filter filter = (Filter)bean;
this.applyGlobalPropertiesIfNecessary(filter);
this.getFilters().put(beanName, filter);
} else {
log.trace("Ignoring non-Filter bean '{}'", beanName);
} return bean;
} public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
} private static final class SpringShiroFilter extends AbstractShiroFilter {
protected SpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
if (webSecurityManager == null) {
throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
} else {
this.setSecurityManager(webSecurityManager);
if (resolver != null) {
this.setFilterChainResolver(resolver);
} }
}
}
}

三、FilterRegistrationBean:上面两步已经将BeanName为shiroFilter的SpringShiroFilter注入到了Spring容器中,现在来说一下是如何从Spring容器中注册到Servlet容器中的。

一般我们在Spring中配置Filter是这样写的:

@Configuration
public class FilterConfig {
/**
* 注册DelegatingFilterProxy(Shiro)
*
* @return
* @author
* @create 2020年8月19日
*/
@Bean
public FilterRegistrationBean shiroFilterRegistrationBean () {
FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
// 该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理
filterRegistration.addInitParameter("targetFilterLifecycle", "true");
filterRegistration.setEnabled(true);
filterRegistration.addUrlPatterns("/*");
return filterRegistration;
}
}

他具体的工作原理是什么?

1、Spring容器在启动时会调用org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext的selfInitialize(ServletContext servletContext)方法。
    private void selfInitialize(ServletContext servletContext) throws ServletException {
this.prepareWebApplicationContext(servletContext);
this.registerApplicationScope(servletContext);
WebApplicationContextUtils.registerEnvironmentBeans(this.getBeanFactory(), servletContext);
Iterator var2 = this.getServletContextInitializerBeans().iterator(); while(var2.hasNext()) {
ServletContextInitializer beans = (ServletContextInitializer)var2.next();
beans.onStartup(servletContext);
} }

2、bean.onStartup(servletContext)调用 RegistrationBean.onStartup()方法,该方法又调用抽象方法register()。

 public final void onStartup(ServletContext servletContext) throws ServletException {
String description = this.getDescription();
if (!this.isEnabled()) {
logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");
} else {
this.register(description, servletContext);
}
} protected abstract void register(String description, ServletContext servletContext);

3、register()方法由RegistrationBean的子类DynamicRegistrationBean实现,并调用由子类AbstractFilterRegistrationBean实现的addRegistration()方法。

  protected final void register(String description, ServletContext servletContext) {
D registration = this.addRegistration(description, servletContext);
if (registration == null) {
logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");
} else {
this.configure(registration);
}
} protected abstract D addRegistration(String description, ServletContext servletContext);

4、AbstractFilterRegistrationBean的addRegistration()方法,向ServletContext中注册了一个过滤器。而这个过滤器是子类提供的,也就是我们在Spring中注入的FilterRegistrationBean提供的,他的getFilter()方法

返回的就是我们的shiroFilter 。

AbstractFilterRegistrationBean:

   protected Dynamic addRegistration(String description, ServletContext servletContext) {
//调用子类实现的抽象方法
Filter filter = this.getFilter();
//向servletContext中注册Filter
return servletContext.addFilter(this.getOrDeduceName(filter), filter);
}
//这个方法由子类实现
public abstract T getFilter();

FilterRegistrationBean:

public class FilterRegistrationBean<T extends Filter> extends AbstractFilterRegistrationBean<T> {
private T filter; public FilterRegistrationBean() {
super(new ServletRegistrationBean[0]);
} public FilterRegistrationBean(T filter, ServletRegistrationBean<?>... servletRegistrationBeans) {
super(servletRegistrationBeans);
Assert.notNull(filter, "Filter must not be null");
this.filter = filter;
} public T getFilter() {
return this.filter;
} public void setFilter(T filter) {
Assert.notNull(filter, "Filter must not be null");
this.filter = filter;
}
}

至此,shiroFilter从Spring容器中注册到了Servlet容器中了。

SpringBoot整合shiro系列-SpingBoot是如何将shiroFilter注册到servlet容器中的的更多相关文章

  1. SpringBoot 源码解析 (七)----- Spring Boot的核心能力 - 自定义Servlet、Filter、Listener是如何注册到Tomcat容器中的?(SpringBoot实现SpringMvc的原理)

    上一篇我们讲了SpringBoot中Tomcat的启动过程,本篇我们接着讲在SpringBoot中如何向Tomcat中添加Servlet.Filter.Listener 自定义Servlet.Filt ...

  2. 补习系列(6)- springboot 整合 shiro 一指禅

    目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...

  3. SpringBoot系列十二:SpringBoot整合 Shiro

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 整合 Shiro 2.具体内容 Shiro 是现在最为流行的权限认证开发框架,与它起名的只有最初 ...

  4. SpringBoot整合Shiro+MD5+Salt+Redis实现认证和动态权限管理(上)----筑基中期

    写在前面 通过前几篇文章的学习,我们从大体上了解了shiro关于认证和授权方面的应用.在接下来的文章当中,我将通过一个demo,带领大家搭建一个SpringBoot整合Shiro的一个项目开发脚手架, ...

  5. SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

    SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建 技术栈 : SpringBoot + shiro + jpa + freemark ,因为篇幅原因,这里只 ...

  6. 转:30分钟了解Springboot整合Shiro

    引自:30分钟了解Springboot整合Shiro 前言:06年7月的某日,不才创作了一篇题为<30分钟学会如何使用Shiro>的文章.不在意之间居然斩获了22万的阅读量,许多人因此加了 ...

  7. springboot整合Shiro功能案例

    Shiro 核心功能案例讲解 基于SpringBoot 有源码 从实战中学习Shiro的用法.本章使用SpringBoot快速搭建项目.整合SiteMesh框架布局页面.整合Shiro框架实现用身份认 ...

  8. SpringBoot整合Shiro实现权限控制,验证码

    本文介绍 SpringBoot 整合 shiro,相对于 Spring Security 而言,shiro 更加简单,没有那么复杂. 目前我的需求是一个博客系统,有用户和管理员两种角色.一个用户可能有 ...

  9. SpringBoot 整合Shiro 一指禅

    目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...

随机推荐

  1. Python 详解修饰器 附带 js使用修饰器

    修饰器 功能 修饰器的主要功能是,在不改变已有代码的情况下,为某一个类,方法等扩展功能 首先看这样一段代码 def foo(): for i in range(10): print(i) foo() ...

  2. 使用Drone构建Docker映像

    使用Drone构建Docker映像 实践所用软件: Git Gogs Drone Docker 私有镜像仓库 实践链接:https://www.katacoda.com/courses/cicd/bu ...

  3. ( ) 与 { } 差在哪?-- Shell十三问<第七问>

    ( ) 与 { } 差在哪?-- Shell十三问<第七问> 先说一下,为何要用 ( ) 或 { } 好了. 许多时候,我们在 shell 操作上,需要在一定条件下一次执行多个命令,也就是 ...

  4. Shell十三问更新总结版 -- 什么叫做 Shell?-- Shell十三问<第一问>

    Shell十三问更新总结版 简介 ChinaUnix 论坛 Shell 版名为網中人的前辈于 2004 年发布的精华贴,最近回炉这块内容,觉得很多东西讲的实在透彻,非常感谢前辈網中人,同时我个人也对这 ...

  5. DDOS攻击与防御简单阐述,列出DDOS的攻击方法和防御方法

    参考1:https://www.hi-linux.com/posts/50873.html#%E7%BD%91%E7%BB%9C%E5%B1%82-ddos-%E6%94%BB%E5%87%BB 什么 ...

  6. GAMES101作业2

    作业任务: 填写并调用函数 rasterize_triangle(const Triangle& t). 即实现光栅化 该函数的内部工作流程如下: 创建三角形的 2 维 bounding bo ...

  7. 201871030118-雷云云 实验三 结对项目—《D{0-1}KP 实例数据集算法实验平台》项目报告

    项目 内容 课程班级博客 班级链接 这个作业要求链接 作业链接 我的课程学习目标 (1)体验软件项目开发中的两人合作,练习结对编程(2)掌握Github协作开发程序的操作方法(3)学习遗传算法 这个作 ...

  8. 理解和解决Java并发修改异常:ConcurrentModificationException

    參考文獻:https://www.jianshu.com/p/f3f6b12330c1 文獻来源:简书 关键字: Java Exception遇到异常信息Exception in thread &qu ...

  9. Scrum Meeting 目录 && alpha 第一次Scrum Meeting博客

    是兄弟就来摸鱼小组 Scrum Meeting 博客汇总 一.Alpha阶段 标号 标题 1 [alpha]第一次Scrum Meeting(见本文) 二.Beta阶段 会议安排 时间 4月23日8时 ...

  10. C#中普通缓存的使用

    缓存的概念及优缺点在这里就不多做介绍,当然缓存包含多种有普通缓存.客户端缓存.DNS缓存.反向代理缓存以及分布式缓存等等.今天主要聊一聊C#通过编码来实现普通的缓存.话不多说直接上代码. 一.首先,新 ...