{"record":{"id":"aa3f3cef9e196c7a","repo":"Tencent/APIJSON","slug":"error-aa3f3c","errorCode":null,"errorMessage":"未登录或登录过期，请登录后再操作！","messagePattern":"未登录或登录过期，请登录后再操作！","errorType":"exception","errorClass":"NotLoggedInException","httpStatus":401,"severity":"error","filePath":"APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java","lineNumber":473,"sourceCode":"\t\t\tbreak;\n\t\tcase ADMIN://这里不好做，在特定接口内部判。 可以是  /get/admin + 固定秘钥  Parser#needVerify，之后全局跳过验证\n\t\t\tverifyAdmin();\n\t\t\tbreak;\n\t\tdefault://unknown，verifyRole通过就行\n\t\t\tbreak;\n\t\t}\n\n\t\t//验证角色，假定真实强制匹配>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\t}\n\n\n\t/**登录校验\n\t */\n\t@Override\n\tpublic void verifyLogin() throws Exception {\n\t\t//未登录没有权限操作\n\t\tif (visitorId == null) {\n\t\t\tthrow new NotLoggedInException(\"未登录或登录过期，请登录后再操作！\");\n\t\t}\n\n\t\tif (visitorId instanceof Number) {\n\t\t\tif (((Number) visitorId).longValue() <= 0) {\n\t\t\t\tthrow new NotLoggedInException(\"未登录或登录过期，请登录后再操作！\");\n\t\t\t}\n\t\t}\n\t\telse if (visitorId instanceof String) {\n\t\t\tif (StringUtil.isEmpty(visitorId, true)) {\n\t\t\t\tthrow new NotLoggedInException(\"未登录或登录过期，请登录后再操作！\");\n\t\t\t}\n\t\t}\n\t\telse {\n\t\t\tthrow new UnsupportedDataTypeException(\"visitorId 只能是 Long 或 String 类型！\");\n\t\t}\n\n\t}\n","sourceCodeStart":455,"sourceCodeEnd":491,"githubUrl":"https://github.com/Tencent/APIJSON/blob/5284052872898eddc449a58f629e5c8d588b8e22/APIJSONORM/src/main/java/apijson/orm/AbstractVerifier.java#L455-L491","documentation":"verifyLogin() throws NotLoggedInException when visitorId is null — the first of three login checks. verifyLogin is reached whenever a request's role is anything other than UNKNOWN (see verifyAccess) or via explicit login-requiring paths. A null visitorId means the request executed with no authenticated visitor at all (no session/auth resolved to a visitor id).","triggerScenarios":"A request with a logged-in role (\"role\":\"LOGIN\"/OWNER/CONTACT/...) arrives with no or invalid credentials, so the framework never set visitorId; verifyLogin()'s first branch throws.","commonSituations":"Missing/expired session cookie or auth token; auth filter not wired (visitor never attached to the request context); testing in a fresh environment with no login performed; token parsing silently failing so visitorId stays null.","solutions":["Authenticate first (login endpoint) and send the session cookie / credential header with the request.","Check the server-side auth chain: the Parser/Verifier visitor must be populated from the session before role verification runs.","If the endpoint should be public, send the request without a logged-in role (role UNKNOWN / omit role) so verifyLogin is not required.","Handle NotLoggedInException in the client to redirect to login instead of retrying."],"exampleFix":"// before\nGET /get { \"User\": { \"id\": 1 }, \"@role\": \"LOGIN\" }  // no cookie\n\n// after\nPOST /login { ... }  // obtain session\nGET /get { \"User\": { \"id\": 1 }, \"@role\": \"LOGIN\" }  // with session cookie","handlingStrategy":"try-catch","validationCode":"if (verifier.visitorId == null) { redirect to login instead of issuing the role-protected request; }","typeGuard":"boolean isLoggedIn(Object visitorId) { return visitorId != null; }","tryCatchPattern":"catch (NotLoggedInException e) { respond 401; client clears stale credentials and routes to login; never retry the same request.","preventionTips":["Attach session/credential to every role-protected call via a request interceptor.","Treat 401 globally: purge cached auth state and re-authenticate once, then replay."],"tags":["apijson","authentication","session","login"],"backgroundTag":null,"analyzedSha":"5284052872898eddc449a58f629e5c8d588b8e22","analyzedAt":"2026-08-14T15:15:29.577Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}