Shiro
Apache Shiro 是 Apache 开源的安全框架,提供身份验证、授权、加密和会话管理功能。
核心组件
| 组件 | 说明 |
|---|---|
| Subject | 当前操作用户或实体,代表与软件交互的任何东西 |
| SecurityManager | 核心控制器,管理所有安全操作和认证 |
| Realm | 安全数据桥梁,从数据源获取用户、角色、权限信息 |
Subject
Subject 表示当前与系统交互的用户或实体,可以是人、第三方进程、后台账户等。
import org.apache.shiro.subject.Subject;
import org.apache.shiro.SecurityUtils;
// 获取当前 Subject
Subject currentUser = SecurityUtils.getSubject();
// 判断是否已认证
if (currentUser.isAuthenticated()) {
// 已登录
}
// 获取用户名
String username = currentUser.getPrincipal().toString();SecurityManager
SecurityManager 是 Shiro 的核心,充当"保护伞",管理所有 Subject 的安全操作。
DefaultSecurityManager securityManager = new DefaultSecurityManager();
securityManager.setRealm(myRealm);
SecurityUtils.setSecurityManager(securityManager);Realm
Realm 是 Shiro 与应用安全数据之间的桥梁,封装了数据源的连接细节。
public class MyRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(userService.getRoles(username));
info.setStringPermissions(userService.getPermissions(username));
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
User user = userService.findByUsername(upToken.getUsername());
if (user == null) {
throw new UnknownAccountException();
}
return new SimpleAuthenticationInfo(
user.getUsername(),
user.getPassword(),
getName()
);
}
}认证流程
快速开始
Maven 依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.13.0</version>
</dependency>Shiro 配置类
@Configuration
public class ShiroConfig {
@Bean
public SecurityManager securityManager(Realm realm) {
DefaultSecurityManager manager = new DefaultSecurityManager();
manager.setRealm(realm);
return manager;
}
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chainDefinition =
new DefaultShiroFilterChainDefinition();
chainDefinition.addPathDefinition("/login", "anon");
chainDefinition.addPathDefinition("/**", "authc");
return chainDefinition;
}
}授权方式
基于角色授权
if (currentUser.hasRole("admin")) {
// 有管理员角色
}
if (currentUser.hasAllRoles(Arrays.asList("admin", "user"))) {
// 同时拥有管理员和用户角色
}基于权限授权
if (currentUser.isPermitted("user:create")) {
// 有创建用户权限
}注解方式
@RequiresAuthentication
public void updateUser(User user) { }
@RequiresRoles("admin")
public void deleteUser(Long id) { }
@RequiresPermissions("user:delete")
public void delete(Long id) { }Session 管理
Session session = currentUser.getSession();
session.setAttribute("key", "value");
session.setTimeout(1800000); // 30分钟RememberMe
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(true);
currentUser.login(token);Spring Boot 集成
shiro:
loginUrl: /login
successUrl: /index
unauthorizedUrl: /unauthorized自定义过滤器
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(
SecurityManager securityManager) {
ShiroFilterFactoryBean factory = new ShiroFilterFactoryBean();
factory.setSecurityManager(securityManager);
factory.setLoginUrl("/login");
factory.setSuccessUrl("/index");
factory.setUnauthorizedUrl("/unauthorized");
Map<String, String> chains = new LinkedHashMap<>();
chains.put("/login", "anon");
chains.put("/static/**", "anon");
chains.put("/**", "authc,roles[admin]");
factory.setFilterChainDefinitionMap(chains);
return factory;
}与 Spring Security 对比
| 特性 | Shiro | SpringSecurity |
|---|---|---|
| 配置复杂度 | 简单 | 复杂 |
| 学习曲线 | 平缓 | 陡峭 |
| 社区活跃度 | 一般 | 活跃 |
| 与 Spring 集成 | 需要额外配置 | 原生支持 |
| 适用场景 | 小型项目 | 企业级项目 |
小型项目、简单权限需求选择 Shiro;Spring 全家桶项目、需要细粒度控制选择 SpringSecurity。配合 JWT 使用时,Shiro 负责认证授权,JWT 负责无状态 Token 传递。
密码加密
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("MD5");
matcher.setHashIterations(2);
realm.setCredentialsMatcher(matcher);异常处理
| 异常 | 说明 |
|---|---|
| UnknownAccountException | 用户名不存在 |
| IncorrectCredentialsException | 密码错误 |
| LockedAccountException | 账户被锁定 |
| AuthenticationException | 其他认证异常 |
| UnauthorizedException | 未授权访问 |