Spring?Boot?Shiro?auto-configure工作流程詳解
01-Shiro 自動配置原理
Shiro 與 Spring Boot 集成可以通過 shiro-spring-boot-stater 實現(xiàn),并能完成必要類自動裝配。 實現(xiàn)方式是通過 Spring Boot 的自動配置機制,即 WEB-INF/spring.factories
中通過 EnableAutoConfiguration
指定了 6 個自動化配置類:
org.springframework.boot.autoconfigure.EnableAutoConfiguration = \ org.apache.shiro.spring.config.web.autoconfigure.ShiroWebAutoConfiguration,\ org.apache.shiro.spring.config.web.autoconfigure.ShiroWebFilterConfiguration,\ org.apache.shiro.spring.config.web.autoconfigure.ShiroWebMvcAutoConfiguration,\ org.apache.shiro.spring.boot.autoconfigure.ShiroBeanAutoConfiguration,\ org.apache.shiro.spring.boot.autoconfigure.ShiroAutoConfiguration,\ org.apache.shiro.spring.boot.autoconfigure.ShiroAnnotationProcessorAutoConfiguration
它們之間的關系為:
當配置項 shiro.enabled = true
且 shiro.web.enabled = false
時,ShiroWeb*Configuration 配置不生效。 當 shiro.web.enabled = true
時,上述六個皆生效,不過 ShiroWebAutoConfiguration 上有注解 @AutoConfigureBefore(ShiroAutoConfiguration.class)
, 保證能在 ShiroAutoConfiguration 之前,使用 web 配置覆蓋 standalone 配置
02-自動配置類
Shiro 中的核心是 SecurityManager,它將 Authenticator、Authorizer、SessionManager 等關鍵模塊組合在一起。 在 ShiroWebAutoConfiguration 中包含了上述幾個核心模塊的默認初始化過程。
對 Authenticator 來說(ShiroWebAutoConfiguration 返回的都是父類方法的內容,所以下面我直接將方法體替換為父類的):
@Bean @ConditionalOnMissingBean @Override protected AuthenticationStrategy authenticationStrategy() { return new AtLeastOneSuccessfulStrategy(); } @Bean @ConditionalOnMissingBean @Override protected Authenticator authenticator() { ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator(); authenticator.setAuthenticationStrategy(authenticationStrategy()); return authenticator; }
默認情況下,使用的是 ModularRealmAuthenticator,策略類使用的事 AtLeastOneSuccessfulStrategy,即多個 Realms 時,至少一個成功則認為是成功。
對 Authorizer 來說:
@Bean @ConditionalOnMissingBean @Override protected Authorizer authorizer() { ModularRealmAuthorizer authorizer = new ModularRealmAuthorizer(); if (permissionResolver != null) { // 負責從 permission 字符串里解析出 Permission 對象 authorizer.setPermissionResolver(permissionResolver); // 這兩個都是通過 @Autowired 注入進來的 } if (rolePermissionResolver != null) { // 負責從 role 字符串里解析出 Permission 集合 authorizer.setRolePermissionResolver(rolePermissionResolver); // 這兩個都是通過 @Autowired 注入進來的 } return authorizer; }
對于 SessionManager 來說:
@Bean @ConditionalOnMissingBean @Override protected SessionManager sessionManager() { if (useNativeSessionManager) { // 從環(huán)境變量 shiro.userNativeSessionManager 取,默認為 false // 省略了其他設置 return new DefaultWebSessionManager(); } return new ServletContainerSessionManager(); }
對于 SecurityManager 來說:
@Bean @ConditionalOnMissingBean @Override protected SessionsSecurityManager securityManager(List<Realm> realms) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setSubjectDAO(subjectDAO()); securityManager.setSubjectFactory(subjectFactory()); securityManager.setRememberMeManager(rememberMeManager()); securityManager.setAuthenticator(authenticator()); securityManager.setAuthorizer(authorizer()); securityManager.setRealms(realms); securityManager.setSessionManager(sessionManager()); securityManager.setEventBus(eventBus); if (cacheManager != null) { securityManager.setCacheManager(cacheManager); } return securityManager; }
對于其他對象,例如 SubjectDAO/SubjectFactory、SessionDAO/SessionFactory/SessionManager、RememberMeManager、EventBus,在系統(tǒng)中屬于比較底層的輔助模塊,一般與業(yè)務牽扯比較小,所以通過情況下不需要修改。 我簡單介紹下它們的作用,以及 Shiro Web 應用中使用得默認類型:
- SubjectFactory 有兩個默認實現(xiàn),DefaultSubjectFactory 和 DefaultWebSubjectFactory 分別用來創(chuàng)建 standalone 和 Web 程序中的 Subject 對象。
- SubjectDAO 有一個默認實現(xiàn),DefaultSubjectDAO 負責將 Subject 對象存儲到其所屬的 Session 對象中。
- RememberMeManager 負責將 Subject 的 principals 存儲到 cookie 中。
- EventBus 是 Shiro 中的事件總線,負責在 Shiro 全聲明周期觸發(fā)特定事件或接受事件通知。
- SessionDAO/SessionFactory/SessionManager 是與 Session 管理、持久化相關的模塊。
03-Filter 相關的配置類
ShiroWebFilterConfiguration 中定義了與 Servlet Filter 相關的對象。 對于 ShiroFilterFactoryBean,負責創(chuàng)建 shiroFilter 對象:
@Bean @ConditionalOnMissingBean @Override protected ShiroFilterFactoryBean shiroFilterFactoryBean() { ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean(); // 從環(huán)境變量中取 filterFactoryBean.setLoginUrl(loginUrl); // shiro.loginUrl filterFactoryBean.setSuccessUrl(successUrl); // shiro.successUrl filterFactoryBean.setUnauthorizedUrl(unauthorizedUrl); // shiro.unauthorizedUrl filterFactoryBean.setSecurityManager(securityManager); // 由 @Autowired 注入 filterFactoryBean.setShiroFilterConfiguration(shiroFilterConfiguration()); // 由 @Autowired 注入或默認使用 ShiroFilterConfiguration filterFactoryBean.setGlobalFilters(globalFilters()); // 由 @Autowired 注入 filterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap()); // 由 @Autowired 注入 filterFactoryBean.setFilters(filterMap); // 由 @Autowired 注入 return filterFactoryBean; }
對于 filterShiroFilterRegistrationBean 來說,負責向 ServletContext 中注冊 shiroFilter 對象:
@Bean(name = REGISTRATION_BEAN_NAME) @ConditionalOnMissingBean(name = REGISTRATION_BEAN_NAME) protected FilterRegistrationBean<AbstractShiroFilter> filterShiroFilterRegistrationBean() throws Exception { FilterRegistrationBean<AbstractShiroFilter> filterRegistrationBean = new FilterRegistrationBean<>(); filterRegistrationBean.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ERROR); filterRegistrationBean.setFilter((AbstractShiroFilter) shiroFilterFactoryBean().getObject()); // 有前面的 FactoryBean 創(chuàng)建 filterRegistrationBean.setName(FILTER_NAME); // shiroFilter filterRegistrationBean.setOrder(1); return filterRegistrationBean; }
關于 globalFilters,默認只有 InvalidRequestFilter:
@Bean(name = "globalFilters") @ConditionalOnMissingBean protected List<String> globalFilters() { return Collections.singletonList(DefaultFilter.invalidRequest.name()); }
通過前面的分析,如果業(yè)務需要針對不同的 URL 使用不同的 shiro-filter chain,可以通過自定義 shiroFilterChainDefinition 并將其注入都容器中即可,例如:
@Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); chainDefinition.addPathDefinition("/manage/index", "user"); chainDefinition.addPathDefinition("/manage/logout", "logout"); chainDefinition.addPathDefinition("/manage/**", "authc"); // shiro 放行 swagger chainDefinition.addPathDefinition("/swagger-ui/**", "user"); chainDefinition.addPathDefinition("/swagger-resources/**", "user"); chainDefinition.addPathDefinition( "/v3/api-docs/**","user"); chainDefinition.addPathDefinition("/**", "anon"); return chainDefinition; }
04-總結
今天,我介紹了 shiro-spring-boot-starter 中對 Shiro 進行自動化配置的細節(jié)。 通過對這些配置的了解,能夠在遇到具體的業(yè)務問題時修改特定模塊的實現(xiàn)方式,對理解和使用 Shiro 框架是非常必要的事情。 希望今天的內容能對你有所幫助,更多關于Spring Boot Shiro auto-configure的資料請關注腳本之家其它相關文章!
相關文章
java中struts2實現(xiàn)文件上傳下載功能實例解析
這篇文章主要介紹了java中struts2實現(xiàn)文件上傳下載功能的方法,以實例形式較為詳細的分析了struts2實現(xiàn)文件上傳下載功能的具體實現(xiàn)技巧與相關問題的解決方法,具有一定的參考借鑒價值,需要的朋友可以參考下2015-01-01IDEA2023.3.4開啟SpringBoot項目的熱部署(圖文)
本文使用的開發(fā)工具是idea,使用的是springboot框架開發(fā)的項目,配置熱部署,可以提高開發(fā)效率,文中通過圖文介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧2024-02-02Spring?Cloud?oauth2?認證服務搭建過程示例
這篇文章主要為大家介紹了Spring?Cloud?oauth2?認證服務搭建過程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06淺談如何在項目中使用Spring Cloud Alibaba Sentinel組件
隨著微服務的流行,服務和服務之間的穩(wěn)定性變得越來越重要。本文主要介紹了使用Spring Cloud Alibaba Sentinel組件,感興趣的可以了解一下2021-07-07