使用 @PreAuthorize 时从 Spring 控制器返回 405 与 403
Posted
技术标签:
【中文标题】使用 @PreAuthorize 时从 Spring 控制器返回 405 与 403【英文标题】:405 vs 403 returned from Spring Controllers when using @PreAuthorize 【发布时间】:2014-07-30 01:09:29 【问题描述】:我们最近开始将 @PreAuthorize
注释与我们的 REST 端点一起使用。它工作得很好,但是,我确实对发出 GET 与 POST 或 PUT 时返回的 HTTP 代码有疑问。
当用户无权访问控制器的 REST 端点时,GET 和 PUT/POST 返回的 HTTP 状态似乎不同。
例如,如果我有一个 GET 端点并且有一个 @PreAuthorize
注释并且用户没有访问权限,则返回 403 Forbidden。这是我所期望的。
如果随后将相同的注释放置在 POST 或 PUT 的控制器方法上,则 HTTP 响应为 405 Method Not Allowed(请注意,正确授权后,POST/PUT 方法按预期返回 200)。
单步执行代码时,您可以看到底层安全过滤器返回 403,但在 POST/PUT 场景中,状态代码被丢弃/忽略并替换为 405,就像发生 NullPointerExcpetion
时一样在您的控制器代码中。
这是预期的行为还是应该始终为无权访问端点的用户返回 403 Forbidden?
【问题讨论】:
在我看来,web security layer 抛出了 405,而不是 @PreAuthorize 注释的访问控制层。尝试为包 org.springframework.security 启用调试级别,看看那里到底发生了什么 我认为您的请求方法类型不正确 【参考方案1】:对我来说,问题在于SecurityConfiguration
。
通过删除.and().exceptionHandling().accessDeniedPage("/access-denied")
行,我得到了403 Forbidden
而不是405 Method not allowed
,这很可能是您所期望的。
【讨论】:
你知道为什么指定自定义访问被拒绝页面会改变行为吗? 我没有对此进行调查,抱歉【参考方案2】:有可能在请求之间的某处被内部重定向并最终到达一个期望不同 HTTP 请求类型的端点,因此您得到一个 HTTP 405。 我已经看到这在身份验证的情况下是最常见的原因
【讨论】:
【参考方案3】:我通过在我的错误控制器中允许额外的 HTTP 方法解决了这个问题,而不是只允许 GET 请求:
public class MyErrorController implements ErrorController
@RequestMapping(method =
RequestMethod.GET,
RequestMethod.HEAD,
RequestMethod.POST,
RequestMethod.PUT,
RequestMethod.DELETE,
RequestMethod.OPTIONS,
RequestMethod.TRACE,
RequestMethod.PATCH)
public String displayError()
// display error
我的解释:
-
请求的资源允许使用 POST 方法,但 SpringSecurity 由于身份验证或授权无效而拒绝该请求。
SpringSecurity 在内部重定向到错误控制器以显示 HTTP 403 的错误页面。此处使用初始请求中的 HTTP 方法,即 POST。
错误控制器只允许 GET 请求,这就是返回 HTTP 405 的原因。
【讨论】:
以上是关于使用 @PreAuthorize 时从 Spring 控制器返回 405 与 403的主要内容,如果未能解决你的问题,请参考以下文章