共计 2210 个字符,预计需要花费 6 分钟才能阅读完成。
背景介绍
Apache Shiro 是一个强大且易用的 Java 安全框架,主要负责认证、授权、加密和会话管理。其核心认证流程分为三个步骤:

- 用户提交认证信息(如用户名和密码)
- 框架创建 AuthenticationToken
- Realm 验证 token 并返回认证结果
在这个流程中,authentication failed for token submission 是常见的错误提示,通常发生在 token 验证阶段。这个错误表明 Shiro 无法验证提交的 token,可能是由于配置错误、数据不匹配或流程异常导致的。
错误分析
出现这个错误的主要原因包括:
- Token 格式问题
- 使用了不匹配的 Token 类型(如需要 UsernamePasswordToken 却提交了其他类型)
-
Token 中包含非法或空值
-
Realm 配置错误
- 未正确配置 Realm 或配置了多个 Realm 导致冲突
-
Realm 的 credentialsMatcher 设置不正确
-
密码匹配失败
- 数据库存储的密码与提交的密码不一致
-
加密方式不匹配(如数据库是 MD5 加密但提交的是明文)
-
其他可能原因
- 用户账户被锁定或禁用
- 认证流程被自定义过滤器干扰
- 缓存配置问题
解决方案
1. 检查 Token 创建
// 正确的 UsernamePasswordToken 创建方式
UsernamePasswordToken token = new UsernamePasswordToken(
username, // 不能为 null 或空字符串
password, // 不能为 null
rememberMe // 可选参数
);
2. 配置 Realm
public class MyRealm extends AuthorizingRealm {
// 必须实现的认证方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException {UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
// 1. 查询用户信息(示例使用 JdbcTemplate)User user = jdbcTemplate.queryForObject(
"SELECT * FROM users WHERE username = ?",
new UserRowMapper(),
username
);
if(user == null) {throw new UnknownAccountException();
}
// 2. 返回认证信息
return new SimpleAuthenticationInfo(user.getUsername(), // principal
user.getPassword(), // credentials
getName() // realmName);
}
}
3. 配置 SecurityManager
@Bean
public SecurityManager securityManager() {DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 配置 Realm
MyRealm myRealm = new MyRealm();
// 配置密码匹配器
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("SHA-256");
matcher.setHashIterations(1024);
myRealm.setCredentialsMatcher(matcher);
securityManager.setRealm(myRealm);
return securityManager;
}
最佳实践
- 密码处理规范
- 始终使用相同的加密算法和盐值策略
-
避免在日志中打印敏感信息
-
Realm 实现建议
- 为每个数据源使用单独的 Realm
-
实现适当的缓存策略
-
异常处理
- 区分不同类型的认证失败(未知账户、密码错误等)
-
提供有意义的错误信息但避免泄露安全细节
-
性能考虑
- 为频繁认证的场景实现缓存
- 避免在认证过程中执行复杂查询
调试技巧
- 启用详细日志
# 在 log4j.properties 中增加 Shiro 日志
log4j.logger.org.apache.shiro=DEBUG
- 常见日志分析
- 检查 token 创建时的参数值
- 跟踪 Realm 的 doGetAuthenticationInfo 方法执行
-
观察 CredentialsMatcher 的匹配过程
-
断点调试位置
- UsernamePasswordToken 构造函数
- ModularRealmAuthenticator 的 doAuthenticate 方法
- 自定义 Realm 的认证逻辑
总结与思考
通过本文的分析,我们了解到 Shiro 认证失败可能由多种因素引起。在实际项目中,建议开发者:
- 建立标准的认证流程文档
- 实现统一的错误处理机制
- 定期审计安全配置
思考题:
– 如何在微服务架构中优化 Shiro 的认证性能?
– 现有系统如何平滑迁移到更安全的加密方案?
– 如何设计多因素认证与 Shiro 集成?
希望本指南能帮助开发者快速解决认证问题,同时也鼓励大家深入理解 Shiro 的安全机制,构建更可靠的认证系统。
正文完
