{"record":{"id":"ff3cfaddb214a35b","repo":"dromara/Sa-Token","slug":"30151","errorCode":"30151","errorMessage":"无效请求方式：","messagePattern":"无效请求方式：","errorType":"exception","errorClass":"SaOAuth2Exception","httpStatus":null,"severity":"error","filePath":"sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/processor/SaOAuth2ServerProcessor.java","lineNumber":250,"sourceCode":"\t}\n\n\t/**\n\t * doConfirm 确认授权接口\n\t * @return 处理结果\n\t */\n\tpublic Object doConfirm() {\n\t\t// 获取变量\n\t\tSaRequest req = SaHolder.getRequest();\n\t\tString clientId = req.getParamNotNull(Param.client_id);\n\t\tObject loginId = SaOAuth2Manager.getStpLogic().getLoginId();\n\t\tString scope = req.getParamNotNull(Param.scope);\n\t\tList<String> scopes = SaOAuth2Manager.getDataConverter().convertScopeStringToList(scope);\n\t\tSaOAuth2DataGenerate dataGenerate = SaOAuth2Manager.getDataGenerate();\n\t\tSaOAuth2Template oauth2Template = SaOAuth2Manager.getTemplate();\n\n\t\t// 此请求只允许 POST 方式\n\t\tif(!req.isMethod(SaHttpMethod.POST)) {\n\t\t\tthrow new SaOAuth2Exception(\"无效请求方式：\" + req.getMethod()).setCode(SaOAuth2ErrorCode.CODE_30151);\n\t\t}\n\n\t\t// 确认授权\n\t\toauth2Template.saveGrantScope(clientId, loginId, scopes);\n\n\t\t// 判断所需的返回结果模式\n\t\tboolean buildRedirectUri = req.isParam(Param.build_redirect_uri, \"true\");\n\n\t\t// -------- 情况1：只返回确认结果即可\n\t\tif( ! buildRedirectUri ) {\n\t\t\toauth2Template.saveGrantScope(clientId, loginId, scopes);\n\t\t\treturn SaResult.ok();\n\t\t}\n\n\t\t// -------- 情况2：需要返回最终的 redirect_uri 地址\n\n\t\t// 构建请求 Model\n\t\tRequestAuthModel ra = SaOAuth2Manager.getDataResolver().readRequestAuthModel(req, loginId);","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-oauth2/src/main/java/cn/dev33/satoken/oauth2/processor/SaOAuth2ServerProcessor.java#L232-L268","documentation":"Thrown by SaOAuth2ServerProcessor.doConfirm: the authorization-confirm endpoint accepts POST only. A GET request (e.g. a browser navigation or a form defaulting to GET) hits this guard before any confirmation logic runs. Error code 30151.","triggerScenarios":"Submitting the consent/confirm page as a GET request, or a custom front-end sending an AJAX GET to /oauth2/doConfirm. Form without method=\"post\" is the classic case.","commonSituations":"Hand-written consent HTML page using a plain link or default GET form; curl examples in documentation using GET; a redirect from the login page turning the confirm submit into a GET.","solutions":["Change the confirm form to method=\"POST\" with client_id and scope fields","For AJAX confirm, use fetch/axios with method POST","Keep required params (client_id, scope, build_redirect_uri) in the POST body"],"exampleFix":"<!-- before -->\n<form action=\"/oauth2/doConfirm\">\n  ...\n</form>\n\n<!-- after -->\n<form action=\"/oauth2/doConfirm\" method=\"post\">\n  <input name=\"client_id\" value=\"1001\">\n  <input name=\"scope\" value=\"getuserinfo\">\n</form>","handlingStrategy":"validation","validationCode":"// front-end: always submit confirm via POST\n<form method=\"post\" action=\"/oauth2/doConfirm\">...</form>\n// or: await fetch('/oauth2/doConfirm', { method: 'POST', body: new FormData(form) });","typeGuard":null,"tryCatchPattern":"catch(SaOAuth2Exception e) { if(\"30151\".equals(e.getCode())) res.setStatus(405).setBody(\"POST required\"); }","preventionTips":["Never use links (GET) for state-changing OAuth2 confirmations","Add an HTTP-method integration test for the confirm endpoint"],"tags":["oauth2","http-method","consent","sa-token"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}