【问题标题】:Can access spring oauth2 protected resource without access token无需访问令牌即可访问 spring oauth2 受保护的资源
【发布时间】:2015-06-05 01:37:38
【问题描述】:

使用:

  • spring-security 3.2.5
  • spring-security-oauth 2.0.7 (oauth2)
  • grant_type : authentication_code

获取 authentication_code 和访问令牌没有问题。 我遇到的问题是,如果我调用“受保护”资源,则根本无需令牌即可访问它。这是“未真正受保护”资源的安全配置:

<security:http pattern="/api/user/**" create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
                  access-decision-manager-ref="accessDecisionManager">
  <security:anonymous enabled="false" />
  <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
  <security:custom-filter ref="userResourceServer" before="PRE_AUTH_FILTER" />
  <security:access-denied-handler ref="oauthAccessDeniedHandler" />
</security:http>

Oauth2AuthenticationProcessingFilter 在说

请求中没有令牌,将继续链。

我发现this other post 似乎描述了同样的问题,但提出的解决方案是添加&lt;security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" /&gt;,我已经有了。

另外,强硬可能不相关,对受保护资源的请求接收 Set-cookie 标头,定义 jsessionid。因为我指定了create-session="never",这对我来说似乎不正常。

由于我使用的是 OAuth2AccessDeniedHandler,因此我预计对该资源的未经授权的调用会返回 403。

有人可以帮我解决这个问题吗?

请注意,我很确定此安全配置正在启动,因为在我的受保护资源(spring-mvc 控制器)中,SecurityContextHolder.getContext().getAuthentication() 返回 null。如果我完全禁用上述安全配置,同一行将返回匿名身份验证。

编辑:详细的配置信息。

首先我有令牌 enpoint 配置:

  <security:http pattern="/api/oauth/token" 
               create-session="stateless" 
               authentication-manager-ref="clientAuthenticationManager">
    <security:intercept-url pattern="/api/oauth/token"
                            access="IS_AUTHENTICATED_FULLY" />
    <security:anonymous enabled="false" />
    <security:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
    <security:access-denied-handler ref="oauthAccessDeniedHandler" />
  </security:http>

然后是资源端点配置(如问题开头所示):

   <security:http pattern="/api/user/**" 
                  create-session="never" 
                  entry-point-ref="oauthAuthenticationEntryPoint"
                  access-decision-manager-ref="accessDecisionManager">
     <security:anonymous enabled="false" />
     <security:intercept-url pattern="/api/user/**"
                             access="IS_AUTHENTICATED_FULLY" />
     <security:custom-filter ref="userResourceServer"
                             before="PRE_AUTH_FILTER" />
     <security:access-denied-handler ref="oauthAccessDeniedHandler" />
   </security:http>

然后是“通用” url 配置:

<security:http name="genericSecurityConfiguration" entry-point-ref="customLoginEntrypoint">
    <security:form-login authentication-failure-url="/index.jsp"
                         authentication-success-handler-ref="customAuthenticationSuccessHandler"
                         authentication-failure-handler-ref="customAuthenticationFailureHandler"
                         login-page="/index.jsp"
                         login-processing-url="/solapCore/identification2"
                         username-parameter="username"
                         password-parameter="password"
                         />
    <security:session-management invalid-session-url="/index.jsp?invalidSession=true" session-authentication-strategy-ref="sas" /> 
    <security:custom-filter position="LOGOUT_FILTER" ref="logoutFilter"/>
    <security:custom-filter before="FILTER_SECURITY_INTERCEPTOR" ref="monitoringFilter"/>
    <security:access-denied-handler ref="solapcoreAccessDeniedHandler"/>
  </security:http>

同一文件中的其他 oauth 特定配置:

<bean id="oauthAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <property name="realmName" value="oauth" />
  </bean>

  <bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
    <property name="realmName" value="oauth/client" />
    <property name="typeName" value="Basic" />
  </bean>

  <bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
    <constructor-arg>
     <list>
      <bean class="org.springframework.security.oauth2.provider.vote.ScopeVoter" />
      <bean class="org.springframework.security.access.vote.RoleVoter" />
      <bean class="org.springframework.security.access.vote.AuthenticatedVoter" />
     </list>
    </constructor-arg>
  </bean>

  <security:authentication-manager id="clientAuthenticationManager">
    <security:authentication-provider user-service-ref="clientDetailsUserService" />
  </security:authentication-manager>

  <bean id="clientDetailsUserService" class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
    <constructor-arg ref="clientDetails" />
  </bean>
  <bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />

  <oauth:authorization-server  
    client-details-service-ref="clientDetails" 
    token-services-ref="tokenServices" 
    user-approval-handler-ref="userApprovalHandler">
    <oauth:authorization-code />
  </oauth:authorization-server>

  <oauth:resource-server id="userResourceServer" 
                         resource-id="oauth2/user"  
                         token-services-ref="tokenServices" />

  <oauth:client-details-service id="clientDetails">
    <oauth:client client-id="someClientID" 
                  authorized-grant-types="authorization_code"
                  authorities="SOME_AUTHORITY" scope="read" secret="secret" />
  </oauth:client-details-service>

 <security:global-method-security pre-post-annotations="enabled" proxy-target-class="true">
   <security:expression-handler ref="oauthExpressionHandler" />
 </security:global-method-security>

 <oauth:expression-handler id="oauthExpressionHandler" />
 <oauth:web-expression-handler id="oauthWebExpressionHandler" />

 <bean id="tokenStore" class="org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore" />

 <bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
    <property name="tokenStore" ref="tokenStore" />
    <property name="supportRefreshToken" value="true" />
    <property name="clientDetailsService" ref="clientDetails" />
 </bean>

最后,我在 web.xml 中的调度程序 servlet 和 filterChain 配置:

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>
    org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/api/*</url-pattern>
</servlet-mapping>
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
  <filter-name>springSecurityFilterChain</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

【问题讨论】:

    标签: java spring spring-security spring-security-oauth2


    【解决方案1】:

    【讨论】:

    • 它与访问令牌(授权标头)完美配合。问题是即使没有令牌,我的资源也会被调用。
    • 您的 web.xml 中的 url 模式是 /api/*。也许您需要从安全配置中删除 /api 前缀。
    • 我有其他不同的 servlet 映射,所以我需要缩小调度程序 servlet 的 url-pattern。但是调度程序 servlet 正在处理请求,所以 servlet 的 url 模式应该是正确的,否则我会看到 404。
    【解决方案2】:

    您的配置中有问题的部分是&lt;security:http pattern="/api/user/**" ...&gt;

    由于“pattern”属性设置为/api/user/**,所以你的intercept-url“pattern”属性

    <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
    

    除非具有相同的前缀 (/api/user/**),否则不会有任何效果。

    如果您尝试将 IS_AUTHENTICATED_FULLY 仅用于 /api/user/** 模式,则拦截 URL 应该是

    <security:http pattern="/api/user/**" ...>
      <security:anonymous enabled="false" />
      <security:intercept-url pattern="/api/user/**" access="IS_AUTHENTICATED_FULLY" />
      <security:custom-filter ref="userResourceServer" before="PRE_AUTH_FILTER" />
      <security:access-denied-handler ref="oauthAccessDeniedHandler" />
    </security:http>
    

    如果您想将该规则应用于完整应用程序,那么这样的事情应该可以工作:

    <security:http create-session="never" entry-point-ref="oauthAuthenticationEntryPoint"
                      access-decision-manager-ref="accessDecisionManager">
      <security:anonymous enabled="false" />
      <security:intercept-url pattern="/api/user/**" access="IS_AUTHENTICATED_FULLY" />
      <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" />
      <security:custom-filter ref="userResourceServer" before="PRE_AUTH_FILTER" />
      <security:access-denied-handler ref="oauthAccessDeniedHandler" />
    </security:http>
    

    【讨论】:

    • 感谢您尝试帮助我 :) 问题是我已将“/**”置于拦截 url 模式中,因为“/api/user/**”不起作用(它是我尝试的第一件事)。另外,我没有在问题中提到它,但我在 /api/user/** 的下面还有一个通用的 元素,以捕获其他 url。起初我认为这可能是问题的一部分,但即使没有通用 元素,问题仍然存在:我可以在没有任何令牌的情况下访问资源(也无需以任何其他方式进行身份验证)。不过,感谢您的帮助,非常感谢。
    • 您能分享您的完整安全配置文件吗?很难弄清楚问题的原因是什么。
    【解决方案3】:

    我找到了问题的原因,并且它对我们的应用程序非常具体。

    在配置的其他地方,我们覆盖了内置的 FilterInvocationSecurityMetadataSource(使用邪恶的 bean 后处理器)来添加自定义的。这会禁用配置文件中的所有&lt;intercept-url&gt;。我们这样做是因为我们将传统的自定义安全框架迁移到 spring-security 并希望在我们现有的文件中保留 url 安全性。

    感谢所有试图提供帮助的人。

    【讨论】:

      猜你喜欢
      • 2015-10-11
      • 1970-01-01
      • 2019-03-13
      • 2013-10-22
      • 2017-09-01
      • 2015-09-21
      • 1970-01-01
      • 2014-08-27
      • 2020-12-29
      相关资源
      最近更新 更多