wuyouzhuguli/SpringAll · error · UnknownAccountException
用户名或密码错误!
Error message
用户名或密码错误!
What it means
Apache Shiro raises UnknownAccountException (extends AccountException -> AuthenticationException) when a Realm's doGetAuthenticationInfo cannot resolve the submitted principal to a stored account. Here userMapper.findByUserName(userName) returns null, so the code throws with the deliberately shared message '用户名或密码错误!' to avoid revealing whether the username exists (anti-user-enumeration). It propagates out of Subject.login(token) up to the login controller.
Source
Thrown at 14.Spring-Boot-Shiro-Redis/src/main/java/com/springboot/shiro/ShiroRealm.java:78
permissionSet.add(p.getName());
}
simpleAuthorizationInfo.setStringPermissions(permissionSet);
return simpleAuthorizationInfo;
}
/**
* 登录认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String userName = (String) token.getPrincipal();
String password = new String((char[]) token.getCredentials());
System.out.println("用户" + userName + "认证-----ShiroRealm.doGetAuthenticationInfo");
User user = userMapper.findByUserName(userName);
if (user == null) {
throw new UnknownAccountException("用户名或密码错误!");
}
if (!password.equals(user.getPassword())) {
throw new IncorrectCredentialsException("用户名或密码错误!");
}
if (user.getStatus().equals("0")) {
throw new LockedAccountException("账号已被锁定,请联系管理员!");
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());
return info;
}
}
View on GitHub (pinned to 614d2578d9)
Solutions
- Run the module's init.sql in Oracle so the row exists: it seeds T_USER with 'mrbird' (STATUS 1) and 'test' (STATUS 0).
- Confirm the datasource is Oracle (init.sql uses VARCHAR2/NUMBER/TO_DATE); check application.yml driver/url and that you are not pointing at MySQL.
- Verify UserMapper.xml: findByUserName must read 'select * from t_user where username = #{userName}' (table t_user, column username) and resultMap maps passwd->password, status->status.
- Confirm the login form posts field 'username' (LoginController param 'String username'), so token.getPrincipal() is the intended value.
- Flush the Redis/Ehcache auth cache so a stale deleted-user entry is not served instead of the DB row.
Example fix
// before
User user = userMapper.findByUserName(userName);
if (user == null) {
throw new UnknownAccountException("用户名或密码错误!");
}
// after - make sure the row exists AND the mapper maps it
// UserMapper.xml:
// <resultMap type="com.springboot.pojo.User" id="User">
// <id column="username" property="userName"/>
// <id column="passwd" property="password"/>
// <id column="status" property="status"/>
// </resultMap>
// <select id="findByUserName" resultMap="User">
// select * from t_user where username = #{userName}
// </select>
-- init.sql seed (Oracle):
-- INSERT INTO T_USER VALUES ('1','mrbird','42ee25d1e43e9f57119a00d0a39e5250',TO_DATE('2017-11-19 10:52:48','YYYY-MM-DD HH24:MI:SS'),'1'); Defensive patterns
Strategy: try-catch
Validate before calling
// Cheap input-shape guard before Subject.login (NOT an existence probe,
// to preserve the anti-enumeration message)
if (username == null || username.trim().isEmpty()
|| password == null || password.isEmpty()) {
throw new IllegalArgumentException("用户名和密码不能为空");
} Type guard
static boolean accountResolves(UserMapper mapper, String userName) {
return userName != null && mapper.findByUserName(userName) != null;
} Try / catch
try {
SecurityUtils.getSubject().login(
new UsernamePasswordToken(username, password));
} catch (UnknownAccountException | IncorrectCredentialsException e) {
// generic - do NOT reveal which one failed (anti-enumeration)
return ResponseBo.error("用户名或密码错误!");
} catch (LockedAccountException e) {
return ResponseBo.error("账号已被锁定,请联系管理员!");
} catch (AuthenticationException e) {
return ResponseBo.error("认证失败!");
} Prevention
- Load init.sql (Oracle T_USER seed) before the first login attempt.
- Keep UserMapper.xml column aliases aligned with the User entity (username->userName, passwd->password, status->status).
- Validate non-empty input before building the UsernamePasswordToken.
- Catch UnknownAccountException and IncorrectCredentialsException together and return one shared message to avoid user enumeration.
- Point the datasource at Oracle; init.sql is Oracle dialect and will not run on MySQL as-is.
When it happens
Trigger: POSTing /login with a username that has no row in T_USER (typo, unregistered, or init.sql not loaded) makes findByUserName return null and throws before any password check. Also thrown when running against the wrong DB (init.sql is Oracle dialect: VARCHAR2/NUMBER/TO_DATE) or when UserMapper.xml's table/column names do not match the actual schema. Context: the Redis session/cache module.
Common situations: Redis-backed sessions hold a deserialized principal for a user row that was removed, or Redis connection config (host/port in application.yml) is wrong so the store is unreachable. Also the module's init.sql was never run.
Related errors
AI-assisted analysis of wuyouzhuguli/SpringAll@614d2578d9 (2026-08-14).
Data as JSON: /api/errors/e13a38dfe721161d.
Report an issue: GitHub.