{"record":{"id":"5180d3ee791cccd1","repo":"dromara/Sa-Token","slug":"30161","errorCode":"30161","errorMessage":"登录失败","messagePattern":"登录失败","errorType":"exception","errorClass":"SaOAuth2Exception","httpStatus":null,"severity":"error","filePath":"sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/granttype/handler/PasswordGrantTypeHandler.java","lineNumber":56,"sourceCode":"public class PasswordGrantTypeHandler implements SaOAuth2GrantTypeHandlerInterface {\n\n    @Override\n    public String getHandlerGrantType() {\n        return GrantType.password;\n    }\n\n    @Override\n    public AccessTokenModel getAccessToken(SaRequest req, String clientId, List<String> scopes) {\n\n        // 1、获取请求参数\n        String username = req.getParamNotNull(SaOAuth2Consts.Param.username);\n        String password = req.getParamNotNull(SaOAuth2Consts.Param.password);\n\n        // 2、调用API 开始登录，如果没能成功登录，则直接退出\n        PasswordAuthResult passwordAuthResult = loginByUsernamePassword(username, password);\n        Object loginId = passwordAuthResult.getLoginId();\n        if(loginId == null) {\n            throw new SaOAuth2Exception(\"登录失败\").setCode(SaOAuth2ErrorCode.CODE_30161);\n        }\n\n        // 3、构建 ra 对象\n        RequestAuthModel ra = new RequestAuthModel();\n        ra.clientId = clientId;\n        ra.loginId = loginId;\n        ra.scopes = scopes;\n\n        // 4、生成 Access-Token\n        AccessTokenModel at = SaOAuth2Manager.getDataGenerate().generateAccessToken(ra, true, atm -> atm.grantType = GrantType.password);\n        return at;\n    }\n\n    /**\n     * 根据 username、password 进行登录，如果登录失败请直接抛出异常或返回 loginId = null\n     * @param username /\n     * @param password /\n     */","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/granttype/handler/PasswordGrantTypeHandler.java#L38-L74","documentation":"Thrown by PasswordGrantTypeHandler when password-mode login produces no loginId. The handler reads username/password, delegates to the configured password login function, and if the returned PasswordAuthResult has a null loginId the grant is aborted. Error code 30161.","triggerScenarios":"POST /oauth2/token with grant_type=password where the username or password is wrong, the custom doLogin function returns null/throws silently, or password auth (SaOAuth2Handle) was wired to a function that never sets loginId.","commonSituations":"Developer overrode SaOAuth2Strategy or config passwordLoginFunction but returned null on bad credentials; user account disabled or password hash mismatch in the underlying user store; the integration test uses a non-existent user.","solutions":["Verify the username/password against your user store independently of OAuth2 (e.g. direct login endpoint)","If you customized the password login function (SaOAuth2ServerConfig / strategy), make it return a PasswordAuthResult with a real loginId on success and a clear exception on failure","Enable sa-token logging to see whether your login function was invoked and what it returned"],"exampleFix":"// before\nconfig.setPasswordLoginFunction((username, password) -> {\n    return null; // bad credentials silently become 30161\n});\n\n// after\nconfig.setPasswordLoginFunction((username, password) -> {\n    Object loginId = userService.checkLogin(username, password);\n    if(loginId == null) { throw new SaOAuth2Exception(\"Invalid username or password\"); }\n    return new PasswordAuthResult(loginId);\n});","handlingStrategy":"try-catch","validationCode":"// validate credentials against your store before requesting the token\nif(userService.findIdByUsernamePassword(username, password) == null) {\n    return ResponseEntity.status(401).body(\"invalid credentials\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    token = oauth2Client.passwordToken(username, password);\n} catch(SaOAuth2Exception e) {\n    if(\"30161\".equals(e.getCode())) return 401 with 'login failed' message;\n    throw e;\n}","preventionTips":["Make the custom password login function throw a specific exception on bad credentials instead of returning null","Integration-test the password login function independently of the OAuth2 layer"],"tags":["oauth2","password-grant","authentication","sa-token"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}