我正在尝试为我的Spring安全性受保护的servlet实现一个AccessDecisionManager,并且需要检查“Authorization”标头的内容。我有以下代码,但是标头(我确定100%确定发送了该标头)正在返回null:

public class MyAccessDecisionManager implements AccessDecisionManager {
    public void decide(Authentication arg0, Object arg1, Collection<ConfigAttribute> arg2) throws AccessDeniedException, InsufficientAuthenticationException {
        HttpServletRequest req = ((FilterInvocation) arg1).getHttpRequest();
        String authHeader = req.getHeader("Authorization"); //this is null
        //Do stuff
    }
}

在调试器中查看req,我可以深入研究有趣的外观,以查看以下结构:
SecurityContextHolderAwareRequestWrapper req
|-SavedRequestAwareWrapper request
  |-DefaultSavedRequest savedRequest
    |-TreeMap headers
  |-HttpSessionSecurityContextRepository$Servlet3SaveToSessionRequestWrapper request
    |-RequestWrapper request
      |-RequestFacade request
        |-Request request
          |-Request coyoteRequest
            |-MimeHeaders headers
MimeHeaders headers包含我的“Authorization”标头,并且具有正确的值,因此我知道标头正将其发送到我的服务器。但是,TreeMap headers缺少我的Authorization标头,并且(我假设)是getHeaders()正在查看的内容。

我尝试在客户端添加“foo”标头以检查问题是否专门与“Authorization”有关,但我看到的是完全相同的行为。我只能访问的标头是“accept-encoding”,“connection”,“host”和“user-agent”。

配置为:
<bean id="myAccessDecisionManager" class="com.example.MyAccessDecisionManager" />
<security:http pattern="/api/**"
    access-decision-manager-ref="myAccessDecisionManager"
    entry-point-ref="myAccessDeniedHandler">
  <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
  <security:anonymous enabled="true"/>
  <security:access-denied-handler ref="myAccessDeniedHandler"/>
</security:http>

谁能解释这是怎么回事或标题为何丢失?有什么方法可以访问decide()函数中的值? (或者是否有更好的方法可以根据标头值做出决定?)

最佳答案

我无法确定AccessDecisionManager中的问题是什么或如何获得对其他请求标头的访问。相反,我通过在api路径上禁用Spring Security来解决此问题:

<security:http pattern="/api/**" security="none"/>

...并使用Spring MVC拦截器代替:
<mvc:interceptors>
  <mvc:interceptor>
    <mvc:mapping path="/api/**"/>
    <bean class="com.example.MyInterceptor"/>
  </mvc:interceptor>
</mvc:interceptors>

我必须将我的AccessDecisionManagerAuthenticationEntryPoint的逻辑都包含在拦截器的preHandle()方法中,这并不理想,但可以工作。

07-24 18:09