放弃Shiro的N个理由: Spring Security 让安全开发 “零门槛”

一、你还在为 Shiro 手动造轮子吗?

作为 Spring Boot 开发者,搭建项目安全层时,你是否遇到过这些场景:

  • 想快速实现表单登录,却要为 Shiro 写一堆过滤器、配置跳转页面;
  • 需要 "记住我" 功能,查了半天文档,发现 Shiro 得自己写 Cookie 存储、会话关联;
  • 对接 OAuth2(比如微信登录),Shiro 要手动集成第三方依赖,而同事用 Spring Security 几行配置就搞定了;
  • 上线前要做密码加密,Shiro 得自己写盐值处理,Security 早已内置强哈希算法自动适配。

其实,在 Spring Boot 生态中,Spring Security 不是 "备选",而是 "标配" ------ 它的 "开箱即用" 特性,恰恰击中了开发者最核心的需求:少写重复代码,多聚焦业务逻辑。而 Shiro 虽轻量,但在 Spring Boot 环境下,太多基础功能需要手动实现,反而成了 "效率绊脚石"。

二、这些 "默认实现",让 Security 甩 Shiro 几条街

1. 表单登录:Security 零配置,Shiro 再用过滤器也需手动折腾

作为 Web 应用的基础功能,表单登录的实现差异,直接体现框架的便捷性。很多人误以为 Shiro 的 FormAuthenticationFilter 能像 Security 一样 "一键生效",但实际使用中仍需多步手动配置:

(1)Shiro + FormAuthenticationFilter:需 3 步手动配置才生效

FormAuthenticationFilter 虽能替代 "手动写登录接口",但必须完成以下配置,少一步都无法工作:

java 复制代码
@Configuration
public class ShiroConfig {
   // 第一步:配置自定义Realm(认证逻辑仍需自己写)
   @Bean
   public Realm myRealm() {
       SimpleAccountRealm realm = new SimpleAccountRealm();
       realm.addAccount("admin", "123456", "ADMIN"); // 模拟用户(实际需从数据库查询)
       return realm;
   }
   // 第二步:配置SecurityManager,注入Realm
   @Bean
   public SecurityManager securityManager(Realm myRealm) {
       DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
       manager.setRealm(myRealm);
       return manager;
   }
   // 第三步:配置FormAuthenticationFilter,指定表单参数名、登录URL等
   @Bean
   public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
       ShiroFilterFactoryBean factory = new ShiroFilterFactoryBean();
       factory.setSecurityManager(securityManager);
       // 手动指定登录页(必须配置,否则过滤器不知道跳哪)
       factory.setLoginUrl("/login");
       // 手动指定登录成功页
       factory.setSuccessUrl("/index");
       // 手动指定登录失败页
       factory.setUnauthorizedUrl("/login?error");
       // 手动配置过滤器链:将FormAuthenticationFilter应用到登录请求
       Map<String, String> filterMap = new HashMap<>();
       filterMap.put("/login", "authc"); // 登录请求交给authc过滤器(即FormAuthenticationFilter)
       filterMap.put("/**", "authc"); // 其余请求需认证
       factory.setFilterChainDefinitionMap(filterMap);
       // (可选)手动自定义表单参数名(默认是username/password,若前端参数名不同需配置)
       Map<String, Filter> filters = new HashMap<>();
       FormAuthenticationFilter authcFilter = new FormAuthenticationFilter();
       authcFilter.setUsernameParam("userName"); // 手动指定用户名参数名
       authcFilter.setPasswordParam("passWord"); // 手动指定密码参数名
       filters.put("authc", authcFilter);
       factory.setFilters(filters);
       return factory;
   }
}
  • 关键注意点:
  1. 仍需手动写 Realm 的认证逻辑(从数据库查用户、校验密码);
  2. 必须手动指定 loginUrlsuccessUrl 等路径,否则过滤器无法工作;
  3. 若前端登录表单的参数名不是默认的 username/password,需手动配置参数映射;
  4. 登录页面仍需自己开发(HTML/Thymeleaf 模板),Shiro 不会自动生成。
(2)对比 Spring Security:零配置 + 自动生成,无需手动干预

同样是表单登录,Spring Security 无需手动指定过滤器、无需手动配置参数名、甚至无需自己开发登录页:

java 复制代码
@Configuration
@EnableWebSecurity
public class SecurityConfig {
   // 只需配置用户信息(实际项目对接数据库即可)
   @Bean
   public UserDetailsService userDetailsService() {
       UserDetails user = User.withUsername("admin")
               .password(passwordEncoder().encode("123456"))
               .roles("ADMIN")
               .build();
       return new InMemoryUserDetailsManager(user);
   }
   @Bean
   public PasswordEncoder passwordEncoder() {
       return new BCryptPasswordEncoder();
   }
   // 核心配置:一行开启表单登录,其余全自动化
   @Bean
   public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
       http
           .authorizeHttpRequests(auth -> auth.anyRequest().authenticated())
           .formLogin(); // 仅这一行,自动实现所有功能
       return http.build();
   }
}
  • Spring Security 自动帮你做了这些事(Shiro 需手动配置):
  1. 自动生成登录页面(含用户名 / 密码输入框、提交按钮),无需自己写 HTML;
  2. 自动处理登录请求(默认 /login 接口),无需手动配置过滤器;
  3. 自动适配表单参数名(默认 username/password,可通过 formLogin().usernameParameter("userName") 一行修改,无需手动创建过滤器对象);
  4. 自动处理登录成功 / 失败的跳转、异常信息返回(如用户名不存在、密码错误);
  5. 自动集成密码加密,无需手动在 Realm 中处理。
(3)核心差异对比表
对比维度 Shiro + FormAuthenticationFilter Spring Security 表单登录
是否需要手动配置过滤器 是(需手动将 authc 过滤器绑定到登录路径) 否(自动注册过滤器,无需手动配置)
是否需要手动开发登录页 是(必须自己写 HTML / 模板) 否(自动生成标准登录页,可直接使用)
是否需要手动配置路径 是(必须指定 loginUrl、successUrl、unauthorizedUrl) 否(默认路径 /login,可通过配置快速修改)
是否需要手动处理参数映射 是(参数名不同时,需手动创建 FormAuthenticationFilter 对象) 否(通过 formLogin().usernameParameter("userName") 一行修改)
是否自动集成密码加密 否(需手动配置 HashedCredentialsMatcher) 是(内置 PasswordEncoder,自动加密验证)

2. 密码加密:Security 自动适配,Shiro 手动编码

密码明文存储是高危漏洞,而加密功能的实现门槛,Security 几乎为零:

  • Spring Security :内置 PasswordEncoder 接口,提供 BCryptPbkdf2 等强哈希算法,自动处理密码加密与验证。只需定义密码编码器 Bean,用户创建时自动加密,登录时自动匹配 ------ 无需手动写一行加密代码:
java 复制代码
// Security 密码加密零编码
@Bean
public PasswordEncoder passwordEncoder() {
   return new BCryptPasswordEncoder(); // 配置强哈希算法
}
// 创建用户时自动加密
@Bean
public UserDetailsService userDetailsService() {
   UserDetails user = User.withUsername("admin")
           .password(passwordEncoder().encode("123456")) // 自动加密
           .roles("ADMIN")
           .build();
   return new InMemoryUserDetailsManager(user);
}
  • Shiro :虽然支持加密,但需要手动实现 CredentialsMatcher 接口,或在 Realm 中手动处理盐值和哈希计算,步骤繁琐且容易出错:
java 复制代码
// Shiro 需手动配置密码匹配器
@Bean
public HashedCredentialsMatcher credentialsMatcher() {
   HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
   matcher.setHashAlgorithmName("MD5"); // 手动指定算法
   matcher.setHashIterations(1024); // 手动指定迭代次数
   return matcher;
}
// 在 Realm 中手动处理加密验证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
   String username = (String) token.getPrincipal();
   String dbPassword = "加密后的密码"; // 从数据库查询
   String salt = "用户盐值"; // 需手动存储盐值
   // 手动封装认证信息,指定盐值
   return new SimpleAuthenticationInfo(username, dbPassword, ByteSource.Util.bytes(salt), getName());
}

3. "记住我" 功能:Security 一键开启,Shiro 手动造轮子

"记住我" 看似简单,实则涉及 Cookie 存储、会话关联、安全校验,而 Security 直接一键支持:

  • Spring Security :只需在配置中添加 rememberMe(),自动生成安全 Cookie、存储用户信息、有效期配置,甚至支持自定义 Cookie 名称和失效时间 ------ 零额外代码:
java 复制代码
// Security 一键开启"记住我"
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
   http.rememberMe()
       .rememberMeParameter("remember-me") // 自定义参数名
       .tokenValiditySeconds(86400) // 有效期1天,默认2周
       .and().authorizeHttpRequests().anyRequest().authenticated();
   return http.build();
}
  • Shiro :需要手动配置 RememberMeManagerCookieManager,甚至要自己处理 Cookie 的创建、加密和解码,步骤繁琐且容易出现安全隐患:
java 复制代码
// Shiro 手动配置"记住我"
@Bean
public CookieRememberMeManager rememberMeManager() {
   CookieRememberMeManager manager = new CookieRememberMeManager();
   SimpleCookie cookie = new SimpleCookie("rememberMe");
   cookie.setMaxAge(86400); // 手动设置有效期
   manager.setCookie(cookie);
   // 手动设置加密密钥(需自己保管,否则有安全风险)
   manager.setCipherKey(Base64.decode("d3d3LnNoaXJvLmNvbS9jaGFyc2V0LTEyMzQ1Ng=="));
   return manager;
}
// 还要在 SecurityManager 中手动注入
@Bean
public SecurityManager securityManager(Realm myRealm, CookieRememberMeManager rememberMeManager) {
   DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
   manager.setRealm(myRealm);
   manager.setRememberMeManager(rememberMeManager); // 手动关联
   return manager;
}

4. OAuth2 / 第三方登录:Security 内置支持,Shiro 手动集成

如今微服务、跨平台应用普遍需要 OAuth2(如微信、GitHub 登录),而这正是 Security 的 "强项":

  • Spring Security :通过 spring-security-oauth2-client 依赖,内置 OAuth2 客户端 / 资源服务器实现,对接微信、GitHub 等第三方登录只需配置客户端 ID、密钥和授权地址,无需手动处理令牌交互、用户信息获取:
yaml 复制代码
# Spring Security 配置 OAuth2 微信登录(application.yml)
spring:
  security:
    oauth2:
      client:
        registration:
          weixin:
            client-id: 你的微信APPID
            client-secret: 你的微信密钥
            authorization-grant-type: authorization_code
            redirect-uri: http://localhost:8080/login/oauth2/code/weixin
        provider:
          weixin:
            authorization-uri: https://open.weixin.qq.com/connect/oauth2/authorize
            token-uri: https://api.weixin.qq.com/sns/oauth2/access_token
            user-info-uri: https://api.weixin.qq.com/sns/userinfo
  • Shiro :本身不支持 OAuth2,需要手动集成 shiro-oauth2 第三方依赖,自己实现 OAuth2 过滤器、令牌解析、用户信息映射,甚至要处理令牌刷新、过期等细节 ------ 相当于从零开发一套 OAuth2 集成方案,成本极高。

5. 方法级授权:Security 注解即生效,Shiro 需额外配置

细粒度权限控制(如 "只有管理员能删除用户"),Security 用注解就能实现:

  • Spring Security :开启 @EnableMethodSecurity 后,直接在方法上用 @PreAuthorize 配合 SpEL 表达式,支持角色、权限、数据级别的细粒度控制,无需额外配置过滤器:
java 复制代码
@EnableMethodSecurity // 开启方法级授权
@RestController
public class UserController {
   // 只有 ADMIN 角色且有 user:delete 权限才能调用
   @PreAuthorize("hasRole('ADMIN') and hasPermission('user:delete')")
   @DeleteMapping("/user/{id}")
   public void deleteUser(@PathVariable Long id) {
       // 业务逻辑
   }
}
  • Shiro :虽然支持 @RequiresRoles 注解,但需要手动配置 AuthorizationAttributeSourceAdvisor 才能生效,且不支持 SpEL 表达式,细粒度控制需自定义 Permission 实现,灵活性和便捷性远不如 Security:
java 复制代码
// Shiro 需手动配置注解支持
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
   AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
   advisor.setSecurityManager(securityManager);
   return advisor;
}
// 注解仅支持简单角色/权限判断,不支持复杂表达式
@RequiresRoles("ADMIN")
@DeleteMapping("/user/{id}")
public void deleteUser(@PathVariable Long id) {
   // 业务逻辑
}

三、选型结论:Spring Boot 环境下,Security 是 "最优解" 而非 "备选项"

通过以上对比,我们不难发现:在 Spring Boot 生态中,Spring Security 的便捷性是 Shiro 无法替代的 ------ 它将开发者从重复的安全基础开发中解放出来,用 "默认实现" 覆盖 80% 的业务场景,而 Shiro 即便使用 FormAuthenticationFilter 这样的内置组件,仍需要为基础功能编写大量模板代码。

什么时候选 Shiro?

  • 非 Spring 项目(如 Java SE 桌面应用);
  • 对框架体积有极致要求(Shiro 核心包更小);
  • 需要跨 Web / 非 Web 环境的统一会话管理。

什么时候必选 Spring Security?

  • 所有 Spring Boot/Spring Cloud 项目;
  • 需要快速上线、减少重复开发;
  • 涉及 OAuth2/OpenID Connect、微服务安全、细粒度权限控制;
  • 追求 "配置即生效" 的开发体验。

四、最后:技术选型的核心是 "匹配场景 + 提升效率"

Spring Security 并非完美,但在 Spring Boot 环境下,它与生态的深度整合、丰富的默认实现、强大的扩展能力,恰恰解决了开发者最核心的痛点 ------少写代码、少踩坑、多聚焦业务

与其在 Shiro 中手动配置过滤器、开发登录页、处理加密逻辑,不如让 Spring Security 帮你 "一键搞定",把节省下来的时间用在业务创新上 ------ 这才是技术选型的真正价值。

相关推荐
爱吃烤鸡翅的酸菜鱼3 小时前
Spring Boot 注解全栈指南:涵盖 Bean 注册、配置加载、请求映射、事务控制、数据校验等一网打尽
java·开发语言·spring boot·后端·spring
czlczl200209254 小时前
Spring Boot + Redis :如何设计“登出”功能
spring boot·redis·后端
a程序小傲4 小时前
米哈游Java后端面试被问:Spring Boot Starter的制作原理
java·spring boot·后端
后端小张4 小时前
【JAVA 进阶】深入理解Sentinel:分布式系统的流量守卫者
java·开发语言·spring boot·后端·spring·spring cloud·sentinel
2024暴富4 小时前
SpringBoot基于Mybatis拦截器实现数据权限(图文)
spring boot·spring cloud·mybatis
VX:Fegn08955 小时前
计算机毕业设计|基于springboot + vue电影院购票管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
q_19132846955 小时前
基于SpringBoot2+Vue2的企业合作与活动管理平台
java·vue.js·经验分享·spring boot·笔记·mysql·计算机毕业设计
学网安的肆伍5 小时前
【040-安全开发篇】JavaEE应用&SpringBoot框架&JWT身份鉴权&打包部署JAR&WAR
spring boot·安全·java-ee
Han.miracle5 小时前
Spring WebMVC入门实战:从概念到连接建立全解析
java·spring boot·spring·springmvc