{"record":{"id":"8ff0abe232666d32","repo":"wuyouzhuguli/SpringAll","slug":"error-8ff0ab","errorCode":null,"errorMessage":"用户名或密码错误！","messagePattern":"用户名或密码错误！","errorType":"exception","errorClass":"UnknownAccountException","httpStatus":null,"severity":"error","filePath":"17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/shiro/ShiroRealm.java","lineNumber":78,"sourceCode":"\t\t\tpermissionSet.add(p.getName());\n\t\t}\n\t\tsimpleAuthorizationInfo.setStringPermissions(permissionSet);\n\t\treturn simpleAuthorizationInfo;\n\t}\n\n\t/**\n\t * 登录认证\n\t */\n\t@Override\n\tprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {\n\t\tString userName = (String) token.getPrincipal();\n\t\tString password = new String((char[]) token.getCredentials());\n\n\t\tSystem.out.println(\"用户\" + userName + \"认证-----ShiroRealm.doGetAuthenticationInfo\");\n\t\tUser user = userMapper.findByUserName(userName);\n\n\t\tif (user == null) {\n\t\t\tthrow new UnknownAccountException(\"用户名或密码错误！\");\n\t\t}\n\t\tif (!password.equals(user.getPassword())) {\n\t\t\tthrow new IncorrectCredentialsException(\"用户名或密码错误！\");\n\t\t}\n\t\tif (user.getStatus().equals(\"0\")) {\n\t\t\tthrow new LockedAccountException(\"账号已被锁定,请联系管理员！\");\n\t\t}\n\t\tSimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName());\n\t\treturn info;\n\t}\n\n}\n","sourceCodeStart":60,"sourceCodeEnd":91,"githubUrl":"https://github.com/wuyouzhuguli/SpringAll/blob/614d2578d9495acf53cc02f2dee9c6131cc5e51a/17.Spring-Boot-Shiro-Session/src/main/java/com/springboot/shiro/ShiroRealm.java#L60-L91","documentation":"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.","triggerScenarios":"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 session-management module.","commonSituations":"Session-management module: account deleted mid-session, or T_USER not seeded for this module; the SessionManager is configured but no matching user row exists.","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."],"exampleFix":"// before\nUser user = userMapper.findByUserName(userName);\nif (user == null) {\n    throw new UnknownAccountException(\"用户名或密码错误！\");\n}\n// after - make sure the row exists AND the mapper maps it\n// UserMapper.xml:\n//   <resultMap type=\"com.springboot.pojo.User\" id=\"User\">\n//     <id column=\"username\" property=\"userName\"/>\n//     <id column=\"passwd\"   property=\"password\"/>\n//     <id column=\"status\"   property=\"status\"/>\n//   </resultMap>\n//   <select id=\"findByUserName\" resultMap=\"User\">\n//     select * from t_user where username = #{userName}\n//   </select>\n-- init.sql seed (Oracle):\n-- INSERT INTO T_USER VALUES ('1','mrbird','42ee25d1e43e9f57119a00d0a39e5250',TO_DATE('2017-11-19 10:52:48','YYYY-MM-DD HH24:MI:SS'),'1');","handlingStrategy":"try-catch","validationCode":"// Cheap input-shape guard before Subject.login (NOT an existence probe,\n// to preserve the anti-enumeration message)\nif (username == null || username.trim().isEmpty()\n        || password == null || password.isEmpty()) {\n    throw new IllegalArgumentException(\"用户名和密码不能为空\");\n}","typeGuard":"static boolean accountResolves(UserMapper mapper, String userName) {\n    return userName != null && mapper.findByUserName(userName) != null;\n}","tryCatchPattern":"try {\n    SecurityUtils.getSubject().login(\n        new UsernamePasswordToken(username, password));\n} catch (UnknownAccountException | IncorrectCredentialsException e) {\n    // generic - do NOT reveal which one failed (anti-enumeration)\n    return ResponseBo.error(\"用户名或密码错误！\");\n} catch (LockedAccountException e) {\n    return ResponseBo.error(\"账号已被锁定,请联系管理员！\");\n} catch (AuthenticationException e) {\n    return ResponseBo.error(\"认证失败！\");\n}","preventionTips":["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."],"tags":["shiro","authentication","unknown-account","java","spring-boot","mybatis","oracle","session"],"backgroundTag":null,"analyzedSha":"614d2578d9495acf53cc02f2dee9c6131cc5e51a","analyzedAt":"2026-08-14T04:40:03.488Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}