即使端点设置为 permitAll,也会检查承载令牌

Posted

技术标签:

【中文标题】即使端点设置为 permitAll,也会检查承载令牌【英文标题】:Bearer token is checked even if endpoint is set to permitAll 【发布时间】:2017-03-15 19:02:25 【问题描述】:

我正在使用 spring-security-oauth2-provider:3.0.0-RC2 和 Grails 3.2.1。所有资源端点都以/api 开头,使用

"/api/$controller/$action?/$id?(.$format)?" 
    constraints 
    

这是过滤器链图(与文档中给出的相同):

String tokenFilters = "JOINED_FILTERS,-oauth2ProviderFilter,-securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-exceptionTranslationFilter"
String securedResourcesFilter = "JOINED_FILTERS,-securityContextPersistenceFilter,-logoutFilter,-authenticationProcessingFilter,-rememberMeAuthenticationFilter,-oauth2BasicAuthenticationFilter,-exceptionTranslationFilter"
String otherFilters = "JOINED_FILTERS,-statelessSecurityContextPersistenceFilter,-oauth2ProviderFilter,-clientCredentialsTokenEndpointFilter,-oauth2BasicAuthenticationFilter,-oauth2ExceptionTranslationFilter"

grails.plugin.springsecurity.filterChain.chainMap = [
        [pattern: "/api/oauth/token", filters: tokenFilters],
        [pattern: "/api/**", filters: securedResourcesFilter],
        [pattern: "/**", filters: otherFilters]
]

我正在使用密码授予身份验证,只要令牌在浏览器的本地存储中可用,就可以通过传递 Authorization 标头一切正常。

我将不记名令牌存储在浏览器的本地存储中。问题是当令牌过期并且在浏览器的本地存储中仍然可用时。其中一项操作被标记为@Secured(["permitAll"]),因此当我点击该操作时(并且还传递了过期的Authorization 标头),由于令牌已过期,请求被401 拒绝。

这是设计使然,即使端点或控制器/动作设置为permitAll,spring security 仍会检查访问令牌的有效性(如果可用)?

【问题讨论】:

【参考方案1】:

是的,我相信401 响应是设计使然。

您所描述的是OAuth2AuthenticationProcessingFilter 的行为。过滤器attempts to extract the token from the request 找到一个attempts to authenticate it。如果身份验证由于某种原因(如过期令牌)失败,the filter will treat it as an Authentication failure。

因为OAuth2AuthenticationProcessingFilter 在过滤器链中处于较高位置,它会在请求有机会进入较低级别并根据控制器注释做出决定之前终止无效令牌的请求。

基本上,如果您提供访问令牌,应用程序将尝试对其进行身份验证。

解决方法

当您从 spring-security-oauth2-provider 获取访问令牌时,它通常包含一些过期信息,可以在客户端中检查这些过期信息,以防止首先发送过期的 Authorization 标头。您也可以考虑使用Refresh Token Grant。

如果更改客户端不起作用,您可以配置 filterChain.chainMap,以便您尝试允许的控制器操作的 uri 使用 otherFilters,如下所示:

grails.plugin.springsecurity.filterChain.chainMap = [
    [pattern: "/api/oauth/token", filters: tokenFilters],
    [pattern: "/api/foo/myControllerActionThatIsPermitAll", filters: otherFilters],
    [pattern: "/api/**", filters: securedResourcesFilter],
    [pattern: "/**", filters: otherFilters]
]

请注意,a github issue reported on spring-security-oauth 描述了您的问题。

【讨论】:

谢谢@Colin。我只是在寻找这个。如果这是默认实现还是有问题,这是我主要关心的问题。

以上是关于即使端点设置为 permitAll,也会检查承载令牌的主要内容,如果未能解决你的问题,请参考以下文章

引导 2.6 升级后无法访问端点

即使在 asp.net core 5.0 中提供了不记名令牌,也会返回 401 [关闭]

Spring Security permitAll 不适用于某些端点

即使在应用重新启动后 URLSession 也会缓存

即使它是一个端点,它也会抛出 EndpointNotFoundException

ASP.NET Core 2.0 为同一端点结合了 Cookie 和承载授权