Spring?Boot?Shiro?auto-configure工作流程詳解
01-Shiro 自動(dòng)配置原理
Shiro 與 Spring Boot 集成可以通過(guò) shiro-spring-boot-stater 實(shí)現(xiàn),并能完成必要類自動(dòng)裝配。 實(shí)現(xiàn)方式是通過(guò) Spring Boot 的自動(dòng)配置機(jī)制,即 WEB-INF/spring.factories 中通過(guò) EnableAutoConfiguration 指定了 6 個(gè)自動(dòng)化配置類:
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
它們之間的關(guān)系為:

當(dāng)配置項(xiàng) shiro.enabled = true 且 shiro.web.enabled = false 時(shí),ShiroWeb*Configuration 配置不生效。 當(dāng) shiro.web.enabled = true 時(shí),上述六個(gè)皆生效,不過(guò) ShiroWebAutoConfiguration 上有注解 @AutoConfigureBefore(ShiroAutoConfiguration.class), 保證能在 ShiroAutoConfiguration 之前,使用 web 配置覆蓋 standalone 配置
02-自動(dòng)配置類
Shiro 中的核心是 SecurityManager,它將 Authenticator、Authorizer、SessionManager 等關(guān)鍵模塊組合在一起。 在 ShiroWebAutoConfiguration 中包含了上述幾個(gè)核心模塊的默認(rèn)初始化過(guò)程。
對(duì) Authenticator 來(lái)說(shuō)(ShiroWebAutoConfiguration 返回的都是父類方法的內(nèi)容,所以下面我直接將方法體替換為父類的):
@Bean
@ConditionalOnMissingBean
@Override
protected AuthenticationStrategy authenticationStrategy() {
return new AtLeastOneSuccessfulStrategy();
}
@Bean
@ConditionalOnMissingBean
@Override
protected Authenticator authenticator() {
ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
authenticator.setAuthenticationStrategy(authenticationStrategy());
return authenticator;
}
默認(rèn)情況下,使用的是 ModularRealmAuthenticator,策略類使用的事 AtLeastOneSuccessfulStrategy,即多個(gè) Realms 時(shí),至少一個(gè)成功則認(rèn)為是成功。
對(duì) Authorizer 來(lái)說(shuō):
@Bean
@ConditionalOnMissingBean
@Override
protected Authorizer authorizer() {
ModularRealmAuthorizer authorizer = new ModularRealmAuthorizer();
if (permissionResolver != null) {
// 負(fù)責(zé)從 permission 字符串里解析出 Permission 對(duì)象
authorizer.setPermissionResolver(permissionResolver); // 這兩個(gè)都是通過(guò) @Autowired 注入進(jìn)來(lái)的
}
if (rolePermissionResolver != null) {
// 負(fù)責(zé)從 role 字符串里解析出 Permission 集合
authorizer.setRolePermissionResolver(rolePermissionResolver); // 這兩個(gè)都是通過(guò) @Autowired 注入進(jìn)來(lái)的
}
return authorizer;
}
對(duì)于 SessionManager 來(lái)說(shuō):
@Bean
@ConditionalOnMissingBean
@Override
protected SessionManager sessionManager() {
if (useNativeSessionManager) { // 從環(huán)境變量 shiro.userNativeSessionManager 取,默認(rèn)為 false
// 省略了其他設(shè)置
return new DefaultWebSessionManager();
}
return new ServletContainerSessionManager();
}
對(duì)于 SecurityManager 來(lái)說(shuō):
@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;
}
對(duì)于其他對(duì)象,例如 SubjectDAO/SubjectFactory、SessionDAO/SessionFactory/SessionManager、RememberMeManager、EventBus,在系統(tǒng)中屬于比較底層的輔助模塊,一般與業(yè)務(wù)牽扯比較小,所以通過(guò)情況下不需要修改。 我簡(jiǎn)單介紹下它們的作用,以及 Shiro Web 應(yīng)用中使用得默認(rèn)類型:
- SubjectFactory 有兩個(gè)默認(rèn)實(shí)現(xiàn),DefaultSubjectFactory 和 DefaultWebSubjectFactory 分別用來(lái)創(chuàng)建 standalone 和 Web 程序中的 Subject 對(duì)象。
- SubjectDAO 有一個(gè)默認(rèn)實(shí)現(xiàn),DefaultSubjectDAO 負(fù)責(zé)將 Subject 對(duì)象存儲(chǔ)到其所屬的 Session 對(duì)象中。
- RememberMeManager 負(fù)責(zé)將 Subject 的 principals 存儲(chǔ)到 cookie 中。
- EventBus 是 Shiro 中的事件總線,負(fù)責(zé)在 Shiro 全聲明周期觸發(fā)特定事件或接受事件通知。
- SessionDAO/SessionFactory/SessionManager 是與 Session 管理、持久化相關(guān)的模塊。
03-Filter 相關(guān)的配置類
ShiroWebFilterConfiguration 中定義了與 Servlet Filter 相關(guān)的對(duì)象。 對(duì)于 ShiroFilterFactoryBean,負(fù)責(zé)創(chuàng)建 shiroFilter 對(duì)象:
@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 注入或默認(rèn)使用 ShiroFilterConfiguration
filterFactoryBean.setGlobalFilters(globalFilters()); // 由 @Autowired 注入
filterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap()); // 由 @Autowired 注入
filterFactoryBean.setFilters(filterMap); // 由 @Autowired 注入
return filterFactoryBean;
}
對(duì)于 filterShiroFilterRegistrationBean 來(lái)說(shuō),負(fù)責(zé)向 ServletContext 中注冊(cè) shiroFilter 對(duì)象:
@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;
}
關(guān)于 globalFilters,默認(rèn)只有 InvalidRequestFilter:
@Bean(name = "globalFilters")
@ConditionalOnMissingBean
protected List<String> globalFilters() {
return Collections.singletonList(DefaultFilter.invalidRequest.name());
}
通過(guò)前面的分析,如果業(yè)務(wù)需要針對(duì)不同的 URL 使用不同的 shiro-filter chain,可以通過(guò)自定義 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-總結(jié)
今天,我介紹了 shiro-spring-boot-starter 中對(duì) Shiro 進(jìn)行自動(dòng)化配置的細(xì)節(jié)。 通過(guò)對(duì)這些配置的了解,能夠在遇到具體的業(yè)務(wù)問(wèn)題時(shí)修改特定模塊的實(shí)現(xiàn)方式,對(duì)理解和使用 Shiro 框架是非常必要的事情。 希望今天的內(nèi)容能對(duì)你有所幫助,更多關(guān)于Spring Boot Shiro auto-configure的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Mybatis結(jié)果集映射與生命周期詳細(xì)介紹
結(jié)果集映射指的是將數(shù)據(jù)表中的字段與實(shí)體類中的屬性關(guān)聯(lián)起來(lái),這樣 MyBatis 就可以根據(jù)查詢到的數(shù)據(jù)來(lái)填充實(shí)體對(duì)象的屬性,幫助我們完成賦值操作2022-10-10
Java環(huán)境中MyBatis與Spring或Spring MVC框架的集成方法
和MyBatis類似,Spring或者Spring MVC框架在Web應(yīng)用程序的運(yùn)作中同樣主要負(fù)責(zé)處理數(shù)據(jù)庫(kù)事務(wù),這里我們就來(lái)看一下Java環(huán)境中MyBatis與Spring或Spring MVC框架的集成方法2016-06-06
SpringBoot數(shù)據(jù)庫(kù)查詢超時(shí)配置詳解
這篇文章主要介紹了SpringBoot數(shù)據(jù)庫(kù)查詢超時(shí)配置,超時(shí)配置可以避免長(zhǎng)時(shí)間占用數(shù)據(jù)庫(kù)連接,提高系統(tǒng)的響應(yīng)速度和吞吐量,還可以快速的反饋可以提升用戶體驗(yàn),避免用戶因長(zhǎng)時(shí)間等待而感到挫敗,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下2024-11-11
java中JSONObject轉(zhuǎn)換為HashMap(方法+main方法調(diào)用實(shí)例)
這篇文章主要介紹了java中JSONObject轉(zhuǎn)換為HashMap(方法+main方法調(diào)用實(shí)例),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
springboot整合minio實(shí)現(xiàn)文件存儲(chǔ)功能
MinIO?是一個(gè)基于Apache?License?v2.0開(kāi)源協(xié)議的對(duì)象存儲(chǔ)服務(wù),它兼容亞馬遜S3云存儲(chǔ)服務(wù)接口,非常適合于存儲(chǔ)大容量非結(jié)構(gòu)化的數(shù)據(jù),本文給大家介紹了springboot整合minio實(shí)現(xiàn)文件存儲(chǔ)功能,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2023-12-12
idea項(xiàng)目實(shí)現(xiàn)移除和添加git
本文指導(dǎo)讀者如何從官網(wǎng)下載并安裝Git,以及在IDEA中配置Git的詳細(xì)步驟,首先,用戶需訪問(wèn)Git官方網(wǎng)站下載適合自己操作系統(tǒng)的Git版本并完成安裝,接著,在IDEA中通過(guò)設(shè)置找到git.exe文件以配置Gi2024-10-10

