SpringSecurity、Shiro?和?Sa-Token怎么選,哪個更好
前言
今天我們來聊聊一個讓很多Java開發(fā)者糾結的技術選型問題:Spring Security、Apache Shiro和Sa-Token,這3個主流安全框架到底該選哪個?
有些小伙伴在工作中可能遇到過這樣的場景:新項目啟動會上,架構師堅持要用Spring Security,團隊里的老將卻說Shiro更簡單實用,而年輕的同事則力薦Sa-Token這個后起之秀。
大家各執(zhí)一詞,都有道理,到底該聽誰的?
今天這篇文章就跟大家一起聊聊這個話題,希望對你會有所幫助。
1 我們?yōu)槭裁葱枰踩蚣埽?/h2>
在深入對比之前,我們先要理解:為什么不能自己手寫安全邏輯,而非要用框架?
想象一下,如果你要為一個電商系統(tǒng)實現(xiàn)權限控制,你需要處理:
// 手寫權限控制的典型痛點
public class ManualSecurityExample {
// 1. 每個方法都要寫重復的權限校驗
public void updateProduct(Long productId, ProductDTO dto) {
// 檢查用戶是否登錄
User user = getCurrentUser();
if (user == null) {
throw new UnauthorizedException("請先登錄");
}
// 檢查用戶是否有編輯權限
if (!user.hasPermission("product:update")) {
throw new ForbiddenException("沒有操作權限");
}
// 檢查是否是自己的商品(數(shù)據(jù)級權限)
Product product = productService.getById(productId);
if (!product.getOwnerId().equals(user.getId())) {
throw new ForbiddenException("只能修改自己的商品");
}
// 實際業(yè)務邏輯...
productService.update(productId, dto);
}
// 2. 每個Controller都要寫登錄檢查
// 3. 需要自己管理Session/Token
// 4. 密碼加密、CSRF防護都要自己實現(xiàn)
// 5. 審計日志、安全事件處理...
}看到問題了嗎?
安全邏輯會像“幽靈代碼”一樣滲透到業(yè)務的每個角落,導致:
- 代碼重復率高
- 業(yè)務邏輯和安全邏輯耦合
- 難以統(tǒng)一維護和升級
- 容易遺漏安全防護點
安全框架的價值,就是把這些問題抽象化、標準化、自動化。
下面這個示意圖展示了安全框架如何將安全關注點從業(yè)務代碼中解耦出來:

理解了安全框架的價值,接下來我們深入分析這三個主流選項。
2 Spring Security:企業(yè)級的安全“瑞士軍刀”
2.1 Spring Security是什么?
Spring Security是Spring官方提供的安全框架,可以說是Spring生態(tài)中的“御林軍”。
它不僅僅是一個權限控制框架,更是一個全面的安全解決方案。
2.2 核心架構:過濾器鏈的極致運用
Spring Security的核心是過濾器鏈(Filter Chain)。
當一個請求到達時,它會經(jīng)過一系列安全過濾器,每個過濾器負責特定的安全功能:

2.3 快速搭建一個安全的REST API
// 1. 基礎配置類
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 禁用CSRF(REST API通常不需要)
.csrf().disable()
// 授權配置
.authorizeRequests()
.antMatchers("/api/public/**").permitAll() // 公開接口
.antMatchers("/api/admin/**").hasRole("ADMIN") // 需要管理員角色
.antMatchers("/api/user/**").hasAnyRole("USER", "ADMIN") // 需要用戶角色
.anyRequest().authenticated() // 其他所有請求需要認證
// 表單登錄配置(前后端分離時通常用不上)
.and()
.formLogin().disable()
// 基礎認證配置
.httpBasic()
// 異常處理
.and()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint()) // 未認證處理
.accessDeniedHandler(restAccessDeniedHandler()); // 權限不足處理
}
// 2. 用戶詳情服務(從數(shù)據(jù)庫加載用戶)
@Bean
public UserDetailsService userDetailsService() {
return username -> {
// 這里實際應該查詢數(shù)據(jù)庫
if ("admin".equals(username)) {
return User.withUsername("admin")
.password(passwordEncoder().encode("admin123"))
.roles("ADMIN")
.build();
} else if ("user".equals(username)) {
return User.withUsername("user")
.password(passwordEncoder().encode("user123"))
.roles("USER")
.build();
}
throw new UsernameNotFoundException("用戶不存在: " + username);
};
}
// 3. 密碼編碼器
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// 4. REST API認證入口點
@Bean
public AuthenticationEntryPoint restAuthenticationEntryPoint() {
return (request, response, authException) -> {
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.getWriter().write(
"{\"code\": 401, \"message\": \"未認證,請先登錄\"}"
);
};
}
}
// 5. 在Controller中使用安全注解
@RestController
@RequestMapping("/api")
public class ProductController {
@GetMapping("/public/products")
public List<Product> getPublicProducts() {
// 公開接口,無需認證
return productService.getAllProducts();
}
@GetMapping("/user/products")
@PreAuthorize("hasRole('USER')") // 需要USER角色
public List<Product> getUserProducts() {
// 獲取當前認證用戶
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
return productService.getProductsByOwner(username);
}
@PostMapping("/admin/products")
@PreAuthorize("hasRole('ADMIN')") // 需要ADMIN角色
public Product createProduct(@RequestBody ProductDTO dto) {
return productService.createProduct(dto);
}
@DeleteMapping("/admin/products/{id}")
@PreAuthorize("hasPermission(#id, 'product', 'delete')") // 方法級權限控制
public void deleteProduct(@PathVariable Long id) {
productService.deleteProduct(id);
}
}Spring Security的優(yōu)勢與痛點
優(yōu)勢:
- Spring生態(tài)原生支持:與Spring Boot、Spring Cloud無縫集成
- 功能全面:認證、授權、防護(CSRF、CORS、點擊劫持等)一應俱全
- 高度可定制:幾乎每個組件都可以自定義或替換
- 社區(qū)強大:Spring官方維護,文檔完善,社區(qū)活躍
- 企業(yè)級特性:OAuth2、SAML、LDAP等企業(yè)級集成支持
痛點:
- 學習曲線陡峭:概念復雜,配置繁瑣
- 過度設計感:簡單需求也需要復雜配置
- 調(diào)試困難:過濾器鏈復雜,問題定位困難
- 性能開銷:完整的過濾器鏈帶來一定性能損失
適用場景:
- 大型企業(yè)級應用
- 需要與Spring生態(tài)深度集成的項目
- 需要OAuth2、LDAP等企業(yè)級認證協(xié)議的項目
- 團隊有Spring Security經(jīng)驗的場景
有些小伙伴剛開始學Spring Security時,可能會被它復雜的概念搞暈,比如:SecurityContext、Authentication、UserDetails、GrantedAuthority等等。
但一旦掌握了它的設計哲學,你會發(fā)現(xiàn)它真的很強大。
3 Apache Shiro:簡單直觀的“輕騎兵”
3.1 Shiro是什么?
Apache Shiro是一個功能強大且易于使用的Java安全框架,它的設計哲學是:簡化應用安全,讓安全變得更簡單。
如果說Spring Security是重型坦克,那么Shiro就是靈活機動的輕騎兵。
3.2 核心架構:四大核心概念
Shiro的架構圍繞四個核心概念構建:

3.3 快速實現(xiàn)基于URL的權限控制
// 1. Shiro配置類
@Configuration
public class ShiroConfig {
// 創(chuàng)建ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(
SecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);
// 設置登錄頁面
factoryBean.setLoginUrl("/login");
// 設置未授權頁面
factoryBean.setUnauthorizedUrl("/unauthorized");
// 配置攔截規(guī)則
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// 靜態(tài)資源放行
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
// 公開接口
filterChainDefinitionMap.put("/api/public/**", "anon");
filterChainDefinitionMap.put("/login", "anon");
// 需要認證的接口
filterChainDefinitionMap.put("/api/user/**", "authc");
filterChainDefinitionMap.put("/api/admin/**", "authc, roles[admin]");
// 需要特定權限的接口
filterChainDefinitionMap.put("/api/products/create", "authc, perms[product:create]");
filterChainDefinitionMap.put("/api/products/delete/*", "authc, perms[product:delete]");
// 其他所有請求需要認證
filterChainDefinitionMap.put("/**", "authc");
factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return factoryBean;
}
// 創(chuàng)建SecurityManager
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 設置Realm
securityManager.setRealm(customRealm());
// 設置Session管理器
securityManager.setSessionManager(sessionManager());
// 設置緩存管理器
securityManager.setCacheManager(cacheManager());
return securityManager;
}
// 自定義Realm(連接安全數(shù)據(jù)源)
@Bean
public Realm customRealm() {
CustomRealm realm = new CustomRealm();
// 設置密碼匹配器
HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("SHA-256");
credentialsMatcher.setHashIterations(1024);
credentialsMatcher.setStoredCredentialsHexEncoded(false);
realm.setCredentialsMatcher(credentialsMatcher);
// 開啟緩存
realm.setCachingEnabled(true);
realm.setAuthenticationCachingEnabled(true);
realm.setAuthenticationCacheName("authenticationCache");
realm.setAuthorizationCachingEnabled(true);
realm.setAuthorizationCacheName("authorizationCache");
return realm;
}
}
// 2. 自定義Realm實現(xiàn)
public class CustomRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
// 認證邏輯:驗證用戶身份
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
// 從數(shù)據(jù)庫查詢用戶
User user = userService.findByUsername(username);
if (user == null) {
throw new UnknownAccountException("用戶不存在");
}
if (!user.isEnabled()) {
throw new DisabledAccountException("用戶已被禁用");
}
// 返回認證信息
return new SimpleAuthenticationInfo(
user, // 身份 principal
user.getPassword(), // 憑證 credentials
getName() // realm name
);
}
// 授權邏輯:獲取用戶的角色和權限
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
User user = (User) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 添加角色
Set<String> roles = userService.findRolesByUserId(user.getId());
authorizationInfo.setRoles(roles);
// 添加權限
Set<String> permissions = userService.findPermissionsByUserId(user.getId());
authorizationInfo.setStringPermissions(permissions);
return authorizationInfo;
}
}
// 3. 在Controller中使用Shiro
@RestController
@RequestMapping("/api")
public class ProductController {
@GetMapping("/products")
public List<Product> getProducts() {
// 獲取當前用戶
Subject currentUser = SecurityUtils.getSubject();
// 檢查是否已認證
if (!currentUser.isAuthenticated()) {
throw new UnauthorizedException("請先登錄");
}
// 檢查是否有權限
if (!currentUser.isPermitted("product:view")) {
throw new ForbiddenException("沒有查看權限");
}
// 執(zhí)行業(yè)務邏輯
return productService.getAllProducts();
}
@PostMapping("/products")
public Product createProduct(@RequestBody ProductDTO dto) {
Subject currentUser = SecurityUtils.getSubject();
// 使用Shiro的權限注解(需要AOP支持)
currentUser.checkPermission("product:create");
// 或者使用編程式檢查
// if (!currentUser.isPermitted("product:create")) {
// throw new ForbiddenException("沒有創(chuàng)建權限");
// }
return productService.createProduct(dto);
}
@GetMapping("/admin/dashboard")
public DashboardVO getAdminDashboard() {
Subject currentUser = SecurityUtils.getSubject();
// 檢查是否具有admin角色
currentUser.checkRole("admin");
return dashboardService.getAdminDashboard();
}
}Shiro的優(yōu)勢與痛點
優(yōu)勢:
- 簡單直觀:API設計簡潔,學習成本低
- 配置靈活:支持INI、XML、注解等多種配置方式
- 功能完整:認證、授權、會話管理、加密、緩存等一應俱全
- 不依賴容器:可以在任何Java環(huán)境中運行
- 易于集成:與Spring、Spring Boot等框架集成簡單
痛點:
- Spring生態(tài)整合不夠原生:需要額外配置
- 社區(qū)活躍度下降:相比Spring Security,社區(qū)維護力度減弱
- 功能擴展性有限:某些高級功能需要自己實現(xiàn)
- 文檔相對陳舊:部分文檔更新不及時
適用場景:
- 中小型項目,追求快速開發(fā)
- 非Spring項目或Spring生態(tài)不重的項目
- 團隊對Spring Security不熟悉
- 需要簡單權限控制的內(nèi)部系統(tǒng)
有些小伙伴喜歡Shiro的簡潔,特別是它的INI配置文件,幾行配置就能搞定基本的權限控制。
但當你需要更復雜的功能時,可能會發(fā)現(xiàn)需要自己寫不少代碼。
4 Sa-Token:國產(chǎn)新星的“后起之秀”
4.1 Sa-Token是什么?
Sa-Token是一個輕量級Java權限認證框架,由國內(nèi)開發(fā)者開發(fā)。
它的設計理念是:以最少的配置,完成最全面的權限認證功能。
在Spring Security和Shiro之外,Sa-Token提供了一種新的選擇。
4.2 核心特性:簡單而強大
Sa-Token的核心設計哲學可以概括為:“簡單、強大、靈活”。
它通過幾個核心組件實現(xiàn)了完整的安全控制:

4.3 5分鐘搭建完整權限系統(tǒng)
// 1. 添加依賴(pom.xml)
// <dependency>
// <groupId>cn.dev33</groupId>
// <artifactId>sa-token-spring-boot-starter</artifactId>
// <version>1.34.0</version>
// </dependency>
// 2. 配置文件(application.yml)
// sa-token:
// token-name: satoken # token名稱
// timeout: 2592000 # token有效期,單位秒,默認30天
// active-timeout: -1 # token活躍有效期,-1代表不限制
// is-concurrent: true # 是否允許并發(fā)登錄
// is-share: true # 在多人登錄同一賬號時,是否共享token
// max-login-count: 12 # 同一賬號最大登錄數(shù)量
// is-write-header: true # 是否將token寫入響應頭
// token-style: uuid # token風格
// is-log: false # 是否打印操作日志
// 3. 配置類(可選)
@Configuration
public class SaTokenConfig {
// 注冊攔截器
@Bean
public SaInterceptor saInterceptor() {
return new SaInterceptor()
// 校驗登錄狀態(tài),不包含登錄接口
.addPathPatterns("/**")
.excludePathPatterns("/api/user/login")
.excludePathPatterns("/api/public/**")
// 權限校驗規(guī)則
.check(r -> {
// 1. 檢查登錄狀態(tài)
SaRouter.match("/api/**", () -> {
StpUtil.checkLogin();
});
// 2. 角色校驗
SaRouter.match("/api/admin/**", () -> {
StpUtil.checkRole("admin");
});
// 3. 權限校驗
SaRouter.match("/api/products/create", () -> {
StpUtil.checkPermission("product.create");
});
SaRouter.match("/api/products/delete/**", () -> {
StpUtil.checkPermission("product.delete");
});
});
}
}
// 4. 登錄認證Controller
@RestController
@RequestMapping("/api/user")
public class UserController {
@PostMapping("/login")
public ApiResult login(@RequestBody LoginDTO dto) {
// 1. 驗證用戶名密碼
User user = userService.findByUsername(dto.getUsername());
if (user == null || !passwordEncoder.matches(dto.getPassword(), user.getPassword())) {
return ApiResult.error("用戶名或密碼錯誤");
}
// 2. 登錄(Sa-Token會自動創(chuàng)建token)
StpUtil.login(user.getId());
// 3. 獲取token信息
String tokenValue = StpUtil.getTokenValue();
long tokenTimeout = StpUtil.getTokenTimeout();
// 4. 返回用戶信息和token
LoginVO vo = new LoginVO();
vo.setUserId(user.getId());
vo.setUsername(user.getUsername());
vo.setToken(tokenValue);
vo.setExpireTime(tokenTimeout);
// 5. 可以設置一些session信息
StpUtil.getSession().set("userInfo", user);
return ApiResult.success("登錄成功", vo);
}
@PostMapping("/logout")
public ApiResult logout() {
// 注銷當前會話
StpUtil.logout();
return ApiResult.success("注銷成功");
}
@GetMapping("/info")
public ApiResult getUserInfo() {
// 獲取當前登錄用戶ID
Object loginId = StpUtil.getLoginId();
// 獲取用戶信息
User user = userService.findById(Long.parseLong(loginId.toString()));
// 獲取用戶權限列表
List<String> permissionList = StpUtil.getPermissionList();
// 獲取用戶角色列表
List<String> roleList = StpUtil.getRoleList();
UserInfoVO vo = new UserInfoVO();
vo.setUser(user);
vo.setPermissions(permissionList);
vo.setRoles(roleList);
return ApiResult.success(vo);
}
}
// 5. 業(yè)務Controller中使用
@RestController
@RequestMapping("/api/products")
public class ProductController {
@GetMapping("/list")
public ApiResult getProductList() {
// 無需手動檢查登錄狀態(tài),攔截器已處理
// 獲取當前登錄用戶ID
long userId = StpUtil.getLoginIdAsLong();
List<Product> products = productService.getProductsByOwner(userId);
return ApiResult.success(products);
}
@PostMapping("/create")
public ApiResult createProduct(@RequestBody ProductDTO dto) {
// 使用注解方式檢查權限
// @SaCheckPermission("product.create") 也可以這樣用
// 編程式檢查權限
StpUtil.checkPermission("product.create");
long userId = StpUtil.getLoginIdAsLong();
dto.setOwnerId(userId);
Product product = productService.createProduct(dto);
return ApiResult.success(product);
}
@DeleteMapping("/{id}")
@SaCheckPermission("product.delete") // 注解方式權限檢查
public ApiResult deleteProduct(@PathVariable Long id) {
// 除了權限檢查,還可以檢查數(shù)據(jù)權限
Product product = productService.getById(id);
long currentUserId = StpUtil.getLoginIdAsLong();
if (product.getOwnerId() != currentUserId) {
// 不是自己的商品,檢查是否有管理員權限
StpUtil.checkRole("admin");
}
productService.deleteProduct(id);
return ApiResult.success("刪除成功");
}
@GetMapping("/admin/dashboard")
@SaCheckRole("admin") // 注解方式角色檢查
public ApiResult getAdminDashboard() {
DashboardVO dashboard = dashboardService.getAdminDashboard();
return ApiResult.success(dashboard);
}
}
// 6. 進階功能:踢人下線、賬號封禁
@Service
public class AdvancedSecurityService {
// 強制注銷(踢人下線)
public void forceLogout(Object loginId) {
StpUtil.logout(loginId);
}
// 封禁賬號
public void disableAccount(Object loginId, long disableTime) {
// 封禁指定時間(單位:秒)
StpUtil.disable(loginId, disableTime);
}
// 檢查是否被封禁
public boolean isDisabled(Object loginId) {
return StpUtil.isDisable(loginId);
}
// 二級認證(敏感操作需要再次驗證)
public boolean startSecondAuth(long ttl) {
// 開啟二級認證,有效期為ttl秒
return StpUtil.openSafe(ttl);
}
// 檢查二級認證
public void checkSecondAuth() {
StpUtil.checkSafe();
}
}Sa-Token的優(yōu)勢與痛點
優(yōu)勢:
- API設計極其簡潔:
StpUtil.xxx()幾乎涵蓋了所有操作 - 開箱即用:幾乎零配置就能使用
- 功能豐富:除了基礎認證授權,還提供踢人下線、賬號封禁、二級認證等高級功能
- 國產(chǎn)框架:中文文檔完善,符合國人使用習慣
- 輕量級:依賴少,啟動快
痛點:
- 相對較新:生態(tài)不如Spring Security和Shiro成熟
- 社區(qū)規(guī)模小:遇到復雜問題可能難以找到解決方案
- 企業(yè)級特性有限:對OAuth2、LDAP等支持較弱
- 過度封裝:某些場景下靈活性不足
適用場景:
- 中小型項目,追求開發(fā)效率
- 團隊對Spring Security/Shiro不熟悉
- 需要快速搭建權限系統(tǒng)的原型或內(nèi)部工具
- 偏好國產(chǎn)框架和中文文檔的團隊
有些小伙伴第一次用Sa-Token時,會被它的簡潔驚艷到。幾行代碼就實現(xiàn)了其他框架需要大量配置的功能。
但對于大型復雜系統(tǒng),可能需要仔細評估它的擴展性和長期維護性。
5 三大框架全方位對比
了解了每個框架的單獨特點后,我們來一個全方位的對比:

5.1 詳細對比表
| 維度 | Spring Security | Apache Shiro | Sa-Token |
|---|---|---|---|
| 學習曲線 | 陡峭 ????? | 中等 ???☆☆ | 平緩 ??☆☆☆ |
| 配置復雜度 | 復雜 ????? | 中等 ???☆☆ | 簡單 ?☆☆☆☆ |
| 功能完整性 | 全面 ????? | 完整 ????☆ | 豐富 ???☆☆ |
| Spring生態(tài)集成 | 原生 ????? | 良好 ???☆☆ | 良好 ???☆☆ |
| 性能開銷 | 較高 ???☆☆ | 中等 ???☆☆ | 較低 ??☆☆☆ |
| 社區(qū)活躍度 | 活躍 ????? | 一般 ???☆☆ | 增長 ???☆☆ |
| 文檔質(zhì)量 | 優(yōu)秀(英文)????? | 良好 ???☆☆ | 優(yōu)秀(中文)????? |
| 擴展性 | 強大 ????? | 良好 ???☆☆ | 一般 ???☆☆ |
| 企業(yè)級特性 | 豐富 ????? | 有限 ??☆☆☆ | 有限 ??☆☆☆ |
5.2 技術特性詳細對比
| 特性 | Spring Security | Apache Shiro | Sa-Token |
|---|---|---|---|
| 認證方式 | 表單、Basic、OAuth2、LDAP、SAML等 | 表單、Basic、CAS等 | 表單、自定義 |
| 授權模型 | RBAC、ABAC、方法級、URL級 | RBAC、URL級、方法級 | RBAC、方法級 |
| 會話管理 | 支持,與Spring Session集成 | 強大,自帶會話管理 | 支持,簡單易用 |
| 密碼加密 | 多種加密方式支持 | 多種加密方式支持 | 支持 |
| 緩存支持 | 需要自行集成Spring Cache | 內(nèi)置緩存支持 | 支持Redis等 |
| 單點登錄 | 通過Spring Security OAuth2 | 需要額外模塊 | 需要額外模塊 |
| 微服務支持 | 優(yōu)秀,與Spring Cloud GateWay集成 | 一般 | 支持 |
| 監(jiān)控管理 | 與Spring Boot Actuator集成 | 需要自行實現(xiàn) | 簡單監(jiān)控 |
6 如何做出最佳選擇?
面對三個各有優(yōu)劣的框架,如何做出最適合自己項目的選擇?
我總結了一個決策流程圖,幫助你在不同場景下做出明智決策:

6.1 具體場景建議
場景一:大型電商平臺(選擇Spring Security)
- 理由:需要完善的OAuth2社交登錄、支付安全、風控系統(tǒng)
- 實施要點:
- 使用Spring Security OAuth2 Client集成第三方登錄
- 自定義安全過濾器實現(xiàn)風控邏輯
- 與Spring Cloud Gateway整合實現(xiàn)統(tǒng)一認證
- 使用Method Security注解實現(xiàn)細粒度權限控制
場景二:企業(yè)內(nèi)部管理系統(tǒng)(選擇Apache Shiro)
- 理由:權限模型相對固定,需要快速開發(fā),團隊熟悉Shiro
- 實施要點:
- 使用INI配置文件快速定義URL權限規(guī)則
- 集成Ehcache緩存權限數(shù)據(jù)提升性能
- 自定義Realm連接企業(yè)LDAP/AD域
- 利用Shiro標簽在頁面上控制元素顯示
場景三:創(chuàng)業(yè)公司MVP產(chǎn)品(選擇Sa-Token)
- 理由:需要快速上線驗證想法,團隊規(guī)模小,追求開發(fā)效率
- 實施要點:
- 利用Sa-Token的零配置特性快速搭建
- 使用注解方式實現(xiàn)基本權限控制
- 集成Redis實現(xiàn)分布式會話
- 利用Sa-Token的踢人功能實現(xiàn)基礎管理
場景四:微服務架構系統(tǒng)(混合方案)
- 理由:不同服務有不同的安全需求
- 實施要點:
- 網(wǎng)關層:Spring Security + OAuth2(統(tǒng)一認證)
- 核心業(yè)務服務:Spring Security(細粒度控制)
- 內(nèi)部管理服務:Apache Shiro(簡單權限)
- 工具類微服務:Sa-Token(快速開發(fā))
6.2 如果選錯了怎么辦?
有些小伙伴可能會遇到這樣的情況:項目初期選型不合適,隨著業(yè)務發(fā)展需要遷移到其他框架。
這里提供一些遷移建議:
- 漸進式遷移:新舊框架并行,逐步替換
- 抽象隔離層:創(chuàng)建統(tǒng)一的安全接口,底層實現(xiàn)可替換
- 分模塊遷移:按業(yè)務模塊逐個遷移,降低風險
- 充分測試:特別是邊緣案例和權限組合場景
// 抽象安全接口示例
public interface SecurityService {
// 認證相關
boolean login(String username, String password);
void logout();
boolean isAuthenticated();
// 授權相關
boolean hasPermission(String permission);
boolean hasRole(String role);
// 用戶信息
Object getCurrentUser();
Long getCurrentUserId();
}
// Spring Security實現(xiàn)
@Service
public class SpringSecurityServiceImpl implements SecurityService {
// 實現(xiàn)基于Spring Security的接口
}
// 需要遷移時,只需實現(xiàn)新的實現(xiàn)類
@Service
public class SaTokenServiceImpl implements SecurityService {
// 實現(xiàn)基于Sa-Token的接口
// 業(yè)務代碼無需修改,只需切換實現(xiàn)
}總結
經(jīng)過深入分析,我們可以得出以下結論:
- Spring Security是企業(yè)級重型武器,功能全面但復雜,適合大型項目和有經(jīng)驗的團隊。
- Apache Shiro是靈活實用的輕騎兵,平衡了功能與復雜度,適合大多數(shù)中小型項目。
- Sa-Token是快速開發(fā)的利器,API簡潔但生態(tài)相對年輕,適合追求開發(fā)效率的場景。
實際上,沒有完美的框架,只有合適的框架。
到此這篇關于SpringSecurity、Shiro 和 Sa-Token,選哪個更好?的文章就介紹到這了,更多相關SpringSecurity、Shiro 和 Sa-Token,選哪個更好?內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot項目獲取統(tǒng)一前綴配置及獲取非確定名稱配置方法
在SpringBoot項目中,使用@ConfigurationProperties注解可獲取統(tǒng)一前綴的配置,具體做法是創(chuàng)建配置類,使用prefix屬性指定配置的前綴,本文給大家介紹SpringBoot項目獲取統(tǒng)一前綴配置以及獲取非確定名稱配置方法,感興趣的朋友跟隨小編一起看看吧2024-09-09
Java 數(shù)據(jù)結構與算法系列精講之字符串暴力匹配
字符串暴力匹配算法是指在一個長字符串中暴力尋找是否包含某一子串所謂暴力匹配,就是不使用任何其他算法,將兩個字符串中的字符一一進行比對2022-02-02
java8 stream 操作map根據(jù)key或者value排序的實現(xiàn)
這篇文章主要介紹了java8 stream 操作map根據(jù)key或者value排序的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-09-09

