Shiro用法详解:别怕,这篇带你从入门到装X(内附实战踩坑记录)
嘿,朋友们!今天咱们来聊聊Shiro这个“老古董”但依然坚挺的安全框架,说实话,我第一次接触Shiro的时候,那叫一个头大,什么Subject、SecurityManager、Realm,听着就像在念魔法咒语,但用久了你会发现,这家伙其实就是个“门卫大爷”,逻辑简单得很!来,我带你捋一捋,保证你读完会“啊哈,原来就这么回事!”

Shiro是什么?我为什么要用它?
先别急着敲代码,咱得先搞清楚它解决啥问题,简单说,Shiro就是帮你管“登录验证”和“权限控制”的,你想想,要是每个项目都得自己写Session管理、密码加密、角色判断,那不得累死?而且写得还不一定安全,Shiro就像个贴心的管家,你告诉它“谁能进哪个房间,能碰哪些东西”,剩下的事它全包了。
它的核心三板斧:
- Subject(当前用户):代表“正在操作的人”,管他是登录了还是游客。
- SecurityManager(安全管家):核心大脑,负责协调所有模块。
- Realm(数据源):相当于“户口本”,告诉Shiro用户信息去哪儿查(数据库、LDAP都行)。
是不是感觉有点像MVC?对味了,它就是这种分层思维。
快速上手:十分钟跑通认证功能
来来来,光说不练假把式,咱们用Spring Boot整合Shiro,三步走:
第一步:引入依赖(Maven坐标别搞错)
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.9.1</version>
</dependency>
第二步:写个Realm(最关键的!)
这里我栽过跟头,大家注意:Realm里doGetAuthenticationInfo负责验证登录,doGetAuthorizationInfo负责授权,千万别把逻辑写反了,不然你会哭的。
public class MyRealm extends AuthorizingRealm {
// 授权:查询当前用户的角色和权限
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole("admin"); // 实际开发中,这里从数据库查
info.addStringPermission("user:delete");
return info;
}
// 认证:验证用户名密码
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
// 从数据库查用户,密码要加密存储!
String passwordFromDB = getPasswordByUsername(username);
if (passwordFromDB == null) {
throw new UnknownAccountException("兄弟,你账号不存在啊!");
}
return new SimpleAuthenticationInfo(username, passwordFromDB, getName());
}
}
第三步:配置SecurityManager + 过滤器链 这一步最容易被忽略,尤其是过滤器链顺序,真是一失足成千古恨,记住这句口诀:“匿名在前,认证在后,权限最后”。
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
// 拦截路径配置
Map<String, String> filterChain = new LinkedHashMap<>();
filterChain.put("/login", "anon"); // 登录页放行
filterChain.put("/logout", "logout"); // 退出
filterChain.put("/admin/**", "authc, roles[admin]"); // 需要登录且是管理员
filterChain.put("/**", "authc"); // 其余都要登录
bean.setFilterChainDefinitionMap(filterChain);
bean.setLoginUrl("/login"); // 没登录就跳这儿
bean.setUnauthorizedUrl("/403"); // 没权限跳这儿
return bean;
}
你看,核心就这些,是不是没那么玄乎?
进阶玩法:注解权限(装X必备)
有时候你想在方法级别控制权限,只有VIP才能调用这个接口”,这时候就得上@RequiresPermissions注解了。
@RestController
public class UserController {
@GetMapping("/deleteUser")
@RequiresPermissions("user:delete")
public String deleteUser() {
return "删除成功!";
}
}
但注意啦!如果你在Spring Boot里用注解,必须在配置类上加上@EnableShiroAnnotations,不然控制器方法上的注解就是空摆设,我当时没加这个注解,还纳闷为啥权限没生效,排查了半天,气死我了!
密码加密:别再用明文了,求你了!
很多新手直接存明文密码,看得我心惊肉跳,Shiro支持MD5加盐加密,咱们用HashedCredentialsMatcher配合Realm使用。
@Bean
public HashedCredentialsMatcher matcher() {
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("MD5");
matcher.setHashIterations(1024); // 加密次数,越多越安全
return matcher;
}
然后在Realm里设置:
setCredentialsMatcher(matcher); // 在构造器或setter里
存密码的时候记住:新密码 = MD5(原密码 + 用户名盐值),这样就算数据库泄露,黑客拿到也是密文,一辈子都解不开。
实战避坑指南(血泪经验)
- Session超时问题:Shiro默认把Session存在内存里,重启就丢,你要是做集群部署,得用Redis缓存Session,不然用户登录状态一会儿就没,体验极差!
- 过滤器顺序:
shiroFilter里的Map一定要用LinkedHashMap,别用HashMap,否则顺序乱了,拦截规则全乱套。 - 跨域问题:前后端分离时,Shiro的Session机制会拦着OPTIONS请求,你得在过滤器链里放行
/api/**的OPTIONS请求,不然前端哭死。 - 记住我功能:如果你设置
user过滤器,记得同时创建rememberMeManager,不然“记住我”功能就失效了,用户每次打开浏览器都得重新登录。
Shiro是淘汰了吗?
很多人说Spring Security更强大,但我个人觉得Shiro轻量、学习曲线平缓,对于中小型项目真的够用了,而且Shiro的社区资料多啊,出个Bug你随便一搜就有解决方案,不像新框架踩坑只能自己摸黑,如果你做的是大型金融项目,那还是老老实实上Spring Security吧。
说真的,写代码这事儿,没有绝对的好与坏,只有合不合适,Shiro就像一把瑞士军刀,小巧但够用,你把它玩明白了,面试的时候还能跟面试官聊聊权限设计的门道,岂不美哉?
好啦,今天的Shiro用法就唠到这儿,如果你在配置过程中遇到什么奇葩报错,评论区留言,咱们一起吐槽一起解决!下期见!