Spring Security vs Shiro:权限江湖的剑宗与气宗

107 阅读2分钟

一、门派之争:Spring Security 与 Shiro 的江湖地位

1. 设计哲学

  • Spring Security
    名门正派,深度融入 Spring 生态,招式复杂但体系完整,适合大型宗门(企业级应用)。
  • Shiro
    逍遥散修,轻量灵活,招式简单直接,适合独行侠客(小型项目或非 Spring 应用)。

2. 核心差异

// Spring Security 的配置像一本武功秘籍  
@Configuration  
@EnableWebSecurity  
public class SecurityConfig extends WebSecurityConfigurerAdapter {  
    // 需打通任督二脉(理解过滤器链)  
}  

// Shiro 的配置像一把瑞士军刀  
@Bean  
public ShiroFilterFactoryBean shiroFilter() {  
    // 即插即用,但拓展性有限  
}  

二、Spring Security 的「独孤九剑」:方法级权限

1. 起手式:开启招式开关

@Configuration  
@EnableGlobalMethodSecurity(prePostEnabled = true)  
public class MethodSecurityConfig {  
    // 解锁 @PreAuthorize 等剑招  
}  

2. 破剑式:精准拦截

// 招式1:剑气外放(表达式控制)  
@PreAuthorize("hasRole('ADMIN') || #userId == principal.id")  
public void deleteUser(Long userId) {  
    // 管理员或本尊可出招  
}  

// 招式2:以气御剑(自定义逻辑)  
@Component("perm")  
public class PermissionChecker {  
    public boolean isOwner(Long docId) {  
        // 乾坤大挪移:自定义权限规则  
    }  
}  

@PreAuthorize("@perm.isOwner(#docId)")  
public Document getDoc(Long docId) { ... }  

3. 御剑式:多剑齐发

// 招式组合:先验剑气(@Secured)  
@Secured("ROLE_DEV")  
public void deploy() { ... }  

// 后发制人(@PostAuthorize)  
@PostAuthorize("returnObject.status != 'SECRET'")  
public Report getReport() { ... }  

三、实战过招:权限控制的三种境界

1. 第一层:以名制敌(角色控制)

@PreAuthorize("hasRole('BOSS')")  
public void raiseSalary() {  
    // 只有掌门可调用  
}  

2. 第二层:人剑合一(动态逻辑)

@PreAuthorize("#user.level > 5 && @perm.isVIP(#user)")  
public void accessVIPArea(User user) {  
    // 内力(业务规则)与剑招结合  
}  

3. 第三层:无招胜有招(元注解)

@Target(METHOD)  
@Retention(RUNTIME)  
@PreAuthorize("hasPermission(#id, 'READ')")  
public @interface CanRead { }  

@CanRead  
public File getFile(Long id) { ... }  

四、避坑指南:江湖险恶

  1. 剑气反噬

    • 避免在注解中写复杂业务逻辑
    • 自定义表达式建议封装为 Bean
  2. 招式冲突

    • 多个拦截器顺序用 @Order 控制

    • 禁用 CSRF 时需显式配置:

    http.csrf().disable();  
    
  3. 心法不匹配

    • 测试时用 @WithMockUser 模拟对手:

    @Test  
    @WithMockUser(roles = "GUEST")  
    void testAccessDenied() { ... }