SpringBoot3.5.4 整合Shiro時 運行失敗,檢查思路及最終解決方案
1. 創建過程
- 新建一個Shiro,去github上查看simple,需要用到哪些內容;
- 根據顯示的內容,在創建項目的時候導入SpringWeb,Thymeleaf
- 檢查pom.xml,確定導入的內容是最新的自己想要的SpringBoot3.5.4 的最新版。
- 在themleaf創建個首頁,編寫一個controller,測試springboot項目正常啟動
- 使用的Springboot3.x,所以在github的Shiro倉庫中參照:https://github.com/apache/shiro/tree/main/samples/spring-boot-3-web
- 引入git的pom.xml的依賴
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>2.0.0-alpha-4</version>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>2.0.0-alpha-4</version>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>2.0.0-alpha-4</version>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>2.0.0-alpha-4</version>
<classifier>jakarta</classifier>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>2.0.0-alpha-4</version>
<classifier>jakarta</classifier>
</dependency>
- 編寫Configuration 參照samples/spring-boot-3-web/src/main/java/org/apache/shiro/samples/WebApp.java
package com.demo.config;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.TextConfigurationRealm;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* Apache Shiro 核心配置類
* 用于集成 Shiro 權限框架到 Spring Boot 3.x 應用
*/
@Configuration
public class ShiroConfig {
/**
* 創建并配置Realm Bean用于權限管理
*
* @return 配置好的TextConfigurationRealm實例
*/
@Bean
public Realm realm() {
TextConfigurationRealm realm = new TextConfigurationRealm();
// 配置用戶及其對應的權限角色
// 配置用戶:格式為 username = password, role1, role2, ...
realm.setUserDefinitions(
"admin=admin,admin,manager,user\n"
+ "manager=manager,manager,user\n"
+ "user=user,user");
// 配置角色及其關系 這里不是“角色繼承”,而是“角色擁有的權限”
// 配置角色權限(可選):格式為 role = permission1, permission2, ...
realm.setRoleDefinitions(
"admin=*:*:*\n"
+ "manager=read:write\n"
+ "user=read"
);
return realm;
}
/**
* 配置 Shiro 過濾器鏈
* 定義哪些路徑需要什么樣的過濾器(權限控制)
*
* @return ShiroFilterChainDefinition 實例
*/
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
// /login 路徑允許匿名訪問(anon),即未登錄用戶也可以訪問,用于登錄頁面或登錄接口。
chainDefinition.addPathDefinition("/login", "anon");
// 訪問 /logout 需要登出(logout),即用戶可登出。
chainDefinition.addPathDefinition("/logout", "logout");
// 訪問根路徑 / 需要認證(authc),即用戶必須已登錄才可訪問。
chainDefinition.addPathDefinition("/**", "authc");
return chainDefinition;
}
/**
* 【關鍵】配置 SecurityManager
* 這是 Shiro 的核心,必須顯式聲明為 Bean
* shiro-spring-boot-starter 會自動使用這個 Bean
*
* @param realm 從 Spring 容器注入的 Realm
* @return 配置好的 SecurityManager
*/
@Bean
public DefaultWebSecurityManager securityManager(Realm realm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager ();
securityManager.setRealm(realm);
return securityManager;
}
}
問題點
- 期間一直報錯java.lang.IllegalStateException,ClassNotFoundException,多方查找資料后發現是因為 Shiro 和 Spring Boot 版本不兼容導致的。是一個典型的 Jakarta EE 9+ 遷移問題,其中 javax.servlet 包被重命名為 jakarta.servlet
解決方案直接看最后,中間都是找問題和解決問題的過程
思路及解決方案
網絡上提出的解決方案有下面幾種
1. 降級 Spring Boot 版本,降到SpringBoot 2.x 使用javax.servlet的那個版本,因為本身想根據視頻中的思路,學習最新的知識。故而pass;
2. 升級 Shiro 版本,目前所使用的版本就是直接從github上查找所取下來的最新版的master版本,2.0.0-alpha-4,所以不存在不是最新的版的情況,先放一邊;
3. 添加 Jakarta Servlet API 兼容性依賴,添加一個橋接的依賴包,使Javax和Jakarta整合,合理;
使用上述方式意義嘗試后,依舊提示有問題,又去通義上讓AI給寫一個Shiro的整合方案,檢查后發現少注入的一個SecurityManager,

因為SecurityManager是已經被廢止的對象,原本想使用上級對象,但是發現其實返回的也是 DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager ();,所以使用了DefaultWebSecurityManager 補充后重新測試,程序能正常加載

附加
碎碎念
思緒很多,找了各方資料,就是不行,原因就是Spring6已經遷移了一個方法,5還在用;
SpringBoot2使用的javax到Springboot3之后包統一都換了。但是Shiro,的底層的部分邏輯仍然導入使用的是javax.servlet,就導致包都是重復且混亂的,使用SpringBoot3,引用以及配置的jdk最低都是17,17根本就沒有javax了,就需要導入javax.servlet包 為了適配 Shiro,,導入了又顯示沖突,來來回回,還是太菜。
解決方案
反正實現這部分功能肯定需要用上這種安全框架,針對于這個就得出幾種解決方案:
- 降版本,把SpringBoot從3降到2,自然就好了,網上那么多都是2的,真是,來源是不都是一個人,別的就copy copy;回歸到幸福的jdk1.8;
- 等,等Shiro的官方在出一個新版本,將現在出現的bug修復掉,就緒使用Shiro;
- 換!!使用Spring Security,Spring官方這些地方都嵌合的非常好,使用新版Spring也會推出新的其他框架,都是互相適配的,全家桶的舒適感,除了難點都挺好;
- 把自動裝配去了,手寫配置類去實現;
手寫
代碼如下:
好像還不行.....
package com.demo.config;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.SimpleAccountRealm;
import org.apache.shiro.spring.boot.autoconfigure.ShiroAnnotationProcessorAutoConfiguration;
import org.apache.shiro.spring.boot.autoconfigure.ShiroBeanAutoConfiguration;
import org.apache.shiro.spring.config.web.autoconfigure.ShiroWebFilterConfiguration;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
import jakarta.servlet.DispatcherType;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Apache Shiro 核心配置類
* 用于集成 Shiro 權限框架到 Spring Boot 3.x 應用
*/
@Configuration
@SpringBootApplication(exclude = {
ShiroBeanAutoConfiguration.class,
ShiroAnnotationProcessorAutoConfiguration.class,
ShiroWebFilterConfiguration.class // 關鍵:禁用有問題的自動配置
})
public class ShiroConfigR{
public FilterRegistrationBean<DelegatingFilterProxy> shiroFilterRegistration() {
FilterRegistrationBean<DelegatingFilterProxy> registration = new FilterRegistrationBean<>();
DelegatingFilterProxy filter = new DelegatingFilterProxy("shiroFilter");
filter.setTargetFilterLifecycle(true);
registration.setFilter(filter);
registration.setEnabled(true);
registration.addUrlPatterns("/*");
registration.setOrder(1);
// 使用新 API,不要用 setDispatcherTypes(...)
// Spring Boot 3 中應使用 setDispatcherTypes 枚舉集合
registration.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD));
return registration;
}
// 使用簡單內存 Realm(生產環境替換為數據庫查詢)
@Bean
public Realm realm() {
SimpleAccountRealm realm = new SimpleAccountRealm();
// 添加一個測試賬戶
realm.addAccount("admin", "123456", "admin");
return realm;
}
@Bean
public DefaultSecurityManager securityManager() {
DefaultSecurityManager manager = new DefaultSecurityManager ();
manager.setRealm(realm());
return manager;
}
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean() {
ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
filter.setSecurityManager(securityManager());
// 設置未登錄跳轉登錄頁
filter.setLoginUrl("/login");
// 登錄成功后跳轉首頁
filter.setSuccessUrl("/index");
// 無權限跳轉頁
filter.setUnauthorizedUrl("/unauthorized");
// 配置攔截規則
Map<String, String> chain = new LinkedHashMap<>();
chain.put("/login", "anon");
chain.put("/doLogin", "anon");
chain.put("/css/**", "anon");
chain.put("/js/**", "anon");
chain.put("/favicon.ico", "anon");
chain.put("/**", "authc"); // 其他路徑需要認證
filter.setFilterChainDefinitionMap(chain);
return filter;
}
}
繼續排查
根據成功者的項目學習排查錯誤尋找解決方案,Ruoyi是怎么實現的呢
前提
刷git的時候看到了ruoyi,ruoyi同時支持Spring boot2, spring boot3,而且他的權限模塊也是使用的Shiro,去看一看他是怎么實現的。
參照學習: 插件集成 | RuoYi
對比項目差別點,檢查自身錯誤
跟著若依吧他需要的包導進去:
- 沒有使用
shiro-spring-boot-starter;myproject:去掉,會不會使用依賴移動器找不到導致的導入失敗; - 重新定義了
spring-web,spring-webmvc;myproject:引入并指定版本 - 引入使用了
jakarta.servlet-api,沒有javax.servlet-api;myproject:刪掉 - 為了使用Shiro 單獨引入使用了
shiro-core,shiro-spring,shiro-web,在shiro-web排除了shiro-web,并且都指定使用了jakarta的classifier; - 同一個
pom.xml中引入的依賴,同一個包下所使用的版本都是同一個version;
檢查錯誤信息
- 發現導入 的Maven倉庫里有兩個spring-web,是不是這里出現的問題

mvn clean install,清除緩存重新再引入依賴- 刪除不起作用反而會產生干擾的包
<!-- 引入Shiro BOM統一版本管理(可選但推薦) -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-bom</artifactId>
<!-- 使用最新兼容版本 -->
<version>${shiro.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>6.2.9</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
- 重新
mvn clean install,檢查依賴,沒有Spring5.3.2的依賴了,可能是解決了
![]()
- 驗證,檢查各個包中主要使用的類,是否都拋棄了
javax換成了Jakarta;
![]()
![]()
- 項目啟動測試,沒有問題
![]()
- 為避免同情況發送,決定統一依賴包 使用
<poperites> </poperites>管理
![]()
![]()
![]()
測試Shiro
編寫認證授權的Relam
package com.demo.config;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class UserRealm extends AuthorizingRealm {
/**
* 獲取授權信息 授權
*
* @param principals 身份憑證集合,包含用戶的身份信息
* @return AuthorizationInfo 授權信息對象,包含用戶的權限信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 創建簡單的授權信息對象
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 添加用戶相關權限
info.addStringPermission("user:add");
info.addStringPermission("user:delete");
info.addStringPermission("user:update");
System.out.println("執行了授權-----》");
return info;
}
/**
* 執行身份認證信息獲取操作 認證
*
* @param token 認證令牌,包含用戶提交的認證信息
* @return AuthenticationInfo 認證信息對象,包含正確的用戶名和密碼
* @throws AuthenticationException 認證異常,當認證過程中出現錯誤時拋出
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 創建簡單的認證信息對象,使用硬編碼的用戶名"admin"和密碼"123456"
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo("admin", "123456", getName());
System.out.println("執行了認證----》");
return info;
}
}
控制器
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/index")
@RequiresAuthentication
public String index() {
return "index";
}
@GetMapping("/unauthorized")
public String unauthorized() {
return "unauthorized";
}
}
跳轉的頁面編寫

測試


至此,可算解決了。。。。。








浙公網安備 33010602011771號