{"record":{"id":"7158064c54a78a2d","repo":"dromara/Sa-Token","slug":"10312","errorCode":"10312","errorMessage":"no http digest auth","messagePattern":"no http digest auth","errorType":"http","errorClass":"NotHttpDigestAuthException","httpStatus":401,"severity":"error","filePath":"sa-token-core/src/main/java/cn/dev33/satoken/httpauth/digest/SaHttpDigestTemplate.java","lineNumber":82,"sourceCode":"    /**\n     * 在校验失败时，设置响应头，并抛出异常\n     * @param model Digest 参数对象\n     */\n    public void throwNotHttpDigestAuthException(SaHttpDigestModel model) {\n        // 补全一些必须的参数\n        model.realm = (model.realm != null) ? model.realm : SaHttpDigestModel.DEFAULT_REALM;\n        model.qop = (model.qop != null) ? model.qop : SaHttpDigestModel.DEFAULT_QOP;\n        model.nonce = (model.nonce != null) ? model.nonce : SaFoxUtil.getRandomString(32);\n        model.opaque = (model.opaque != null) ? model.opaque : SaFoxUtil.getRandomString(32);\n        model.nc = (model.nc != null) ? model.nc : \"00000001\";\n\n        // 设置响应头\n        SaHolder.getResponse()\n                .setStatus(401)\n                .setHeader(\"WWW-Authenticate\", buildResponseHeaderValue(model));\n\n        // 抛异常\n        throw new NotHttpDigestAuthException().setCode(SaErrorCode.CODE_10312);\n    }\n\n    /**\n     * 获取浏览器提交的 Digest 参数 （裁剪掉前缀）\n     * @return 值\n     */\n    public String getAuthorizationValue() {\n\n        // 获取前端提交的请求头 Authorization 参数\n        String authorization = SaHolder.getRequest().getHeader(\"Authorization\");\n\n        // 如果不是以 Digest 作为前缀，则视为无效\n        if(authorization == null || ! authorization.startsWith(\"Digest \")) {\n            return null;\n        }\n\n        // 裁剪前缀并解码\n        return authorization.substring(7);","sourceCodeStart":64,"sourceCodeEnd":100,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-core/src/main/java/cn/dev33/satoken/httpauth/digest/SaHttpDigestTemplate.java#L64-L100","documentation":"Thrown as NotHttpDigestAuthException (code 10312) by SaHttpDigestTemplate when a request does not carry a valid HTTP Digest 'Authorization' header. Before throwing, the template fills in default challenge parameters (realm, qop, random nonce/opaque, nc=00000001) and writes a 401 status plus a 'WWW-Authenticate' header so the browser can re-respond with Digest credentials. This is the standard Digest authentication failure / challenge flow, not a framework misconfiguration.","triggerScenarios":"Calling saTokenHttpDigestTemplate.check(model) (directly or via the @SaCheckHttpDigest annotation interceptor) on a request whose Authorization header is missing or does not start with the 'Digest ' prefix. The method getAuthorizationValue() returns null/invalid, so check() populates the challenge model, sets the 401 + WWW-Authenticate response, and throws.","commonSituations":"First request from a browser or API client with no credentials (expected challenge); calling a Digest-protected API from curl/Postman/HttpClient without an Authorization header; a client that sends Basic auth instead of Digest; proxies stripping the Authorization header; test cases that forget to compute a Digest response.","solutions":["Have the client answer the 401 challenge: read the WWW-Authenticate header, compute the Digest response (username, realm, nonce, uri, HA1/HA2 with qop), and resend with 'Authorization: Digest ...'","If calling programmatically, use an HTTP client with built-in Digest support (e.g. Apache HttpClient's DigestScheme, OkHttp authenticator, curl --digest)","If this endpoint should not require Digest auth, remove the @SaCheckHttpDigest annotation / skip the check() call","In a global exception handler, catch NotHttpDigestAuthException and return the 401 response unchanged so the challenge header reaches the client"],"exampleFix":"// before (client sends nothing)\ncurl http://api.example.com/admin/data   // -> 401 + exception code 10312\n\n// after (client responds to the Digest challenge)\ncurl --digest -u username:password http://api.example.com/admin/data","handlingStrategy":"try-catch","validationCode":"String auth = SaHolder.getRequest().getHeader(\"Authorization\");\nboolean hasDigest = auth != null && auth.startsWith(\"Digest \");\nif (!hasDigest) {\n    // respond 401 with WWW-Authenticate instead of invoking check()\n}","typeGuard":null,"tryCatchPattern":"try {\n    saTokenHttpDigestTemplate.check(model);\n} catch (NotHttpDigestAuthException e) {\n    // response already carries 401 + WWW-Authenticate; return it as-is so the client can retry with Digest credentials\n    return;\n}","preventionTips":["Configure API clients with Digest-aware authentication (curl --digest, HttpClient DigestScheme) rather than sending raw requests","In a global exception handler, treat NotHttpDigestAuthException as a 401 challenge, not a 500 error","Never swallow the 401 status the template already set before throwing"],"tags":["http-digest","authentication","http-401","sa-token"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}