无需访问令牌即可访问 spring oauth2 保护的资源

Can access spring oauth2 protected resource without access token

使用:

我获取 authentication_code 和访问令牌没有问题。 我遇到的问题是,如果我调用 "protected" 资源,我根本不需要令牌就可以访问它。这是 "not-really-protected" 资源的安全配置:

<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 说

No token in request, will continue chain.

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

另外,tough可能不相关,对受保护资源的请求接收àSet-cookieheader,定义一个jsessionid。这对我来说似乎不正常,因为我指定 create-session="never".

自从我使用 OAuth2AccessDeniedHandler 以来,我预计会对该资源进行未经授权的调用 return 403。

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

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

编辑:详细配置信息。

首先我有令牌点配置:

  <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>

然后 "generic" 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>

我相信你错过了 "Authorization" header。 您需要在 header 值中具有 "Bearer" 的值。

参考:

https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/authentication/OAuth2AuthenticationProcessingFilter.java

https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/authentication/BearerTokenExtractor.java

https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/common/OAuth2AccessToken.java

您的配置中有问题的部分是 <security:http pattern="/api/user/**" ...>

由于"pattern"属性设置为/api/user/**,你的拦截-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>

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

在配置的其他地方,我们覆盖了内置的 FilterInvocationSecurityMetadataSource(使用一个邪恶的 bean post-处理器)来添加一个自定义的。这具有禁用配置文件中所有 <intercept-url> 的效果。我们这样做是因为我们将遗留的自定义安全框架迁移到 spring-security 并希望在我们现有的文件中保持 url 安全。

感谢所有提供帮助的人。