Shiro入门案例详解:从零构建你的首个权限管理系统

目录导读
- Shiro是什么?为什么需要它?
- 环境准备与核心依赖配置
- 第一个Shiro入门案例:身份认证(登录)实战
- 授权(权限控制)案例:基于角色的访问控制
- Shiro与Spring Boot整合的完整示例
- 常见问题与面试高频问答(FAQ)
- 总结与进阶学习路线
Shiro是什么?为什么需要它?
Apache Shiro是一个强大且易用的Java安全框架,提供认证(Authentication)、授权(Authorization)、会话管理(Session Management) 和加密(Cryptography) 四大核心功能,相比Spring Security,Shiro的API更加直观,配置更轻量,特别适合快速搭建中小型项目的权限模块。
核心关键词:Subject(当前用户)、SecurityManager(安全管理器)、Realm(数据源桥接)。
为什么不用Spring Security? 对于刚入门的新手,Shiro的学习曲线更平缓,其设计哲学是“让简单的事情变得简单”,且不强制与Spring容器耦合。
环境准备与核心依赖配置
基础环境:JDK 8+,Maven 3.6+,IDEA。
创建一个普通Maven项目,在pom.xml中引入Shiro核心依赖:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.11.0</version>
</dependency>
核心组件说明:
Subject:当前操作用户,是代码中直接交互的入口。SecurityManager:核心调度器,负责协调Realm完成认证授权。Realm:连接Shiro与数据源(数据库、配置文件)的桥梁。
第一个Shiro入门案例:身份认证(登录)实战
场景:使用shiro.ini配置文件模拟用户数据,实现登录验证。
步骤1:创建shiro.ini文件
[users] admin = 123456 user = 123456
步骤2:编写认证代码
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
public class AuthenticationDemo {
public static void main(String[] args) {
// 1. 加载配置文件,创建SecurityManager
Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
// 2. 获取当前Subject
Subject subject = SecurityUtils.getSubject();
// 3. 封装用户名密码
UsernamePasswordToken token = new UsernamePasswordToken("admin", "123456");
// 4. 执行登录
try {
subject.login(token);
System.out.println("✅ 登录成功!用户:" + subject.getPrincipal());
} catch (UnknownAccountException e) {
System.out.println("❌ 用户名不存在!");
} catch (IncorrectCredentialsException e) {
System.out.println("❌ 密码错误!");
} catch (LockedAccountException e) {
System.out.println("❌ 账户被锁定!");
}
// 5. 退出登录
subject.logout();
}
}
运行结果:控制台输出“✅ 登录成功!用户:admin”。
关键点:Shiro的认证流程本质上是
Subject.login()触发SecurityManager,最终由Realm进行数据比对。
授权(权限控制)案例:基于角色的访问控制
场景:验证当前用户是否拥有指定角色或权限。
扩展shiro.ini配置:
[users] admin = 123456, adminRole, managerRole user = 123456, userRole [roles] adminRole = user:create, user:delete userRole = user:view
授权代码演示:
// 认证成功后,判断角色
if (subject.hasRole("adminRole")) {
System.out.println("用户拥有管理员角色,可以执行删除操作");
}
// 判断权限(细粒度)
if (subject.isPermitted("user:delete")) {
System.out.println("用户拥有删除权限");
} else {
System.out.println("权限不足,拒绝访问");
}
执行效果:admin用户可执行删除,user用户提示权限不足。
理解:角色是权限的集合,Shiro支持
hasRole()和isPermitted()两种粒度检查,后者更灵活。
Shiro与Spring Boot整合的完整示例
在实际开发中,90%的案例都是与Spring Boot整合,以下为精简的配置方式:
依赖引入:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.11.0</version>
</dependency>
自定义Realm(核心) :
@Component
public class CustomRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
// 认证逻辑
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
String username = (String) token.getPrincipal();
User user = userService.findByUsername(username);
if (user == null) {
return null; // 返回null,Shiro抛出UnknownAccountException
}
return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
}
// 授权逻辑
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
Set<String> roles = userService.findRolesByUsername(username);
Set<String> perms = userService.findPermissionsByUsername(username);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);
info.setStringPermissions(perms);
return info;
}
}
ShiroConfig配置:
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);
factoryBean.setLoginUrl("/login");
factoryBean.setUnauthorizedUrl("/unauthorized");
Map<String, String> filterChainMap = new LinkedHashMap<>();
filterChainMap.put("/login", "anon"); // 匿名访问
filterChainMap.put("/logout", "logout");
filterChainMap.put("/admin/**", "authc, roles[admin]"); // 需要管理员角色
filterChainMap.put("/**", "authc"); // 其他页面需要登录
factoryBean.setFilterChainDefinitionMap(filterChainMap);
return factoryBean;
}
}
注意:URL拦截规则使用
LinkedHashMap保证顺序,anon表示匿名可访问,authc表示需要登录,roles[]表示角色限制。
常见问题与面试高频问答(FAQ)
Q1:Shiro的认证流程中,密码是明文传输的吗?
A:不是,生产环境必须加密,Shiro提供Md5Hash和SimpleHash工具类,常用做法是加盐MD5或BCrypt,并在CustomRealm的doGetAuthenticationInfo中返回带盐的AuthenticationInfo。
Q2:ShiroFilterFactoryBean中authc和user过滤器有什么区别?
A:authc强制要求用户必须登录,否则跳转登录页;user则允许“记住我”用户访问,如果你启用了rememberMe,访问受保护页面时,authc会拦截,而user不会。
Q3:如何在Shiro中实现“记住我”功能?
A:在认证成功后,调用subject.getSession().setTimeout()设置过期时间,或者使用UsernamePasswordToken的setRememberMe(true)方法,同时在配置中设置cookie的maxAge。
Q4:一个用户被多个角色限制怎么办?
A:使用roles["admin,user"]表示需同时拥有两个角色;使用roles["admin,user"]加filterChain中分隔符,或通过权限符号user:view, user:edit实现“或”逻辑。
总结与进阶学习路线
本案例已经带你完成了:
- ✅ 理解了Shiro的四大核心架构
- ✅ 通过
shiro.ini完成了基础认证和授权 - ✅ 掌握了Spring Boot整合的完整配置
- ✅ 梳理了常见面试题与坑点
进阶建议:
- 学习缓存机制(整合Redis缓存角色权限)
- 学习并发会话控制(单用户多点登录限制)
- 学习分布式Session共享
- 阅读官方文档《Shiro Reference》以及核心源码(
DefaultSecurityManager和ModularRealmAuthenticator)
想快速掌握? 在实际项目中模仿本案例搭一个后台管理模块,实战体验权限校验带来的安全感。
记住:权限系统的本质是“信任最小化”——只给你需要的权限,不多给一个,Shiro正是帮助你优雅实现这一哲学的最佳编程工具之一。