Apache Shiro 是一款强大、易用的Java安全框架,提供了身份认证、授权、加密、会话管理等安全能力。它以简单易用、可插拔、灵活扩展著称,广泛应用于 Java EE、Spring Boot 等主流技术栈。
Shiro的核心流程分为四大环节:
优点 | 缺点 |
---|---|
API简洁,易用 | 社区活跃度不如Spring Security |
组件解耦,支持灵活扩展 | 默认不支持OAuth2、JWT等新型认证方式 |
支持多种数据源和分布式扩展 | 配置不当易导致安全漏洞 |
性能高,适合企业级高并发场景 | 文档相对零散,学习曲线略高 |
层次/模块 | 作用简述 |
---|---|
Subject | 安全操作主体(用户/服务等) |
SecurityManager | 安全管理器,协调各子模块 |
Realm | 数据源桥梁(认证/授权) |
Authenticator | 认证器 |
Authorizer | 授权器 |
Session | 会话对象 |
SessionManager | 会话管理器 |
SessionDAO | 会话持久化 |
CacheManager | 缓存管理 |
Cryptography | 加密解密 |
Filter | Web安全过滤器 |
EventBus | 事件总线 |
Mgt(管理)模块 | 统一管理接口 |
public void login(AuthenticationToken token) throws AuthenticationException {
if (token == null) throw new IllegalArgumentException("Token不能为空");
SecurityManager securityManager = getSecurityManager();
Subject subject = securityManager.login(this, token);
this.principals = subject.getPrincipals();
this.authenticated = true;
}
速记口诀:有事找Subject,一切皆入口。
public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info = this.authenticator.authenticate(token);
PrincipalCollection principals = info.getPrincipals();
return createSubject(token, info, subject.getSession());
}
速记口诀:安全大总管,调度全局安。
认证流程:
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
User user = userService.findByUsername(username);
if (user == null) throw new UnknownAccountException("用户不存在");
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
授权流程:
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
User user = (User) principals.getPrimaryPrincipal();
Set<String> roles = roleService.findRolesByUserId(user.getId());
Set<String> perms = permService.findPermsByRoles(roles);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.setRoles(roles);
info.setStringPermissions(perms);
return info;
}
速记口诀:认证查用户,授权查权限。
public AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
Collection<Realm> realms = getRealms();
if (realms.size() == 1) {
return doSingleRealmAuthentication(realms.iterator().next(), token);
} else {
return doMultiRealmAuthentication(realms, token);
}
}
速记口诀:认证策略多,成功即通过。
public boolean isPermitted(PrincipalCollection principals, String permission) {
for (Realm realm : getRealms()) {
if (realm instanceof Authorizer) {
if (((Authorizer) realm).isPermitted(principals, permission)) {
return true;
}
}
}
return false;
}
速记口诀:查权限,分角色,表达式支持多。
SimpleSession:
public class SimpleSession implements Session, Serializable {
private Serializable id;
private Date startTimestamp;
private Date lastAccessTime;
private long timeout;
private Map<Object, Object> attributes;
public Object getAttribute(Object key) {
return attributes != null ? attributes.get(key) : null;
}
public void setAttribute(Object key, Object value) {
if (attributes == null) attributes = new HashMap<>();
attributes.put(key, value);
}
}
SessionDAO接口:
public interface SessionDAO {
Serializable create(Session session);
Session readSession(Serializable sessionId);
void update(Session session);
void delete(Session session);
Collection<Session> getActiveSessions();
}
速记口诀:会话分三层,持久化灵活存。
public class EhCacheManager implements CacheManager {
private net.sf.ehcache.CacheManager manager;
public <K, V> Cache<K, V> getCache(String name) throws CacheException {
net.sf.ehcache.Ehcache ehcache = manager.getEhcache(name);
return new EhCache<K, V>(ehcache);
}
}
速记口诀:缓存提性能,失效保一致。
public SimpleHash(String algorithmName, Object source, Object salt, int hashIterations) {
ByteSource saltBytes = ByteSource.Util.bytes(salt);
byte[] input = source.toString().getBytes();
for (int i = 0; i < hashIterations; i++) {
input = MessageDigest.getInstance(algorithmName).digest(input);
if (saltBytes != null) {
input = combine(input, saltBytes.getBytes());
}
}
this.bytes = input;
}
速记口诀:加密全家桶,安全有保障。
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
if (isLoginRequest(request, response)) {
if (isLoginSubmission(request, response)) {
return executeLogin(request, response);
}
return true;
} else {
saveRequestAndRedirectToLogin(request, response);
return false;
}
}
速记口诀:过滤链拦截,规则灵活配。
public void publish(Object event) {
for (Object listener : listeners) {
if (listener.supports(event)) {
listener.onEvent(event);
}
}
}
速记口诀:事件总线通,异步更灵动。
public Session start(SessionContext context) {
Session session = createSession(context);
this.sessionDAO.create(session);
return session;
}
速记口诀:统一管理口,扩展维护优。
function login(username, password):
subject = SecurityUtils.getSubject()
token = UsernamePasswordToken(username, password)
try:
subject.login(token)
return "登录成功"
except AuthenticationException:
return "登录失败"
function checkAccess(resource, action):
subject = SecurityUtils.getSubject()
if subject.isPermitted(resource + ":" + action):
return "允许访问"
else:
return "拒绝访问"
function storeSessionData(key, value):
subject = SecurityUtils.getSubject()
session = subject.getSession()
session.setAttribute(key, value)
Controller注解用法:
@RequiresPermissions("order:view")
public String viewOrder() { ... }
调试与优化技巧:
<dependency>
<groupId>org.apache.shirogroupId>
<artifactId>shiro-spring-boot-starterartifactId>
<version>1.9.1version>
dependency>
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(securityManager);
Map<String, String> filterChain = new LinkedHashMap<>();
filterChain.put("/admin/**", "roles[admin]");
bean.setFilterChainDefinitionMap(filterChain);
return bean;
}
高级算法与实现:
perms[user:add]
,支持Ant风格通配)Shiro作为一款轻量级、可扩展的Java安全框架,以Subject为中心,分层解耦认证、授权、会话、加密等安全功能。可插拔架构、灵活扩展能力使其适用于各类企业级应用和分布式系统。通过自定义Realm、缓存优化、与主流技术栈集成,Shiro能够满足高并发、高安全性场景需求。理解其主流程、源码与架构演进,有助于在实际项目中设计高效、安全的权限管理体系。
速记口诀:
主流程分四步,认证授权会话密;
Subject为核心,分层解耦扩展易;
缓存优化提性能,架构演进应分布。
如需某个模块的全量源码逐行注释,或有具体业务集成问题,欢迎留言交流!