0

在尝试在 spring security oauth2 中获取访问令牌之前,我收到 401 未经授权的错误。

我有服务器(授权和资源服务器)和客户端应用程序。那些使用 sparklr2 和 tonr2 应用程序创建的应用程序。

我在两个应用程序中都绕过了登录表单。这意味着它在开始或两个应用程序时都不会询问用户名和密码,我使用自定义类并将用户角色设置为两个应用程序的“ROLE_USER”。

这是我的错误堆栈跟踪:

 SEVERE: Servlet.service() for servlet [mvc-dispatcher] in context with path [/Client] threw exception [Request processing failed; nested exception is error="access_denied", error_description="Error requesting access token."] with root cause org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:88)
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport$AccessTokenErrorHandler.handleError(OAuth2AccessTokenSupport.java:243)
at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:556)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:514)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:479)
at org.springframework.security.oauth2.client.token.OAuth2AccessTokenSupport.retrieveToken(OAuth2AccessTokenSupport.java:136)
at org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider.obtainAccessToken(AuthorizationCodeAccessTokenProvider.java:198)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainNewAccessTokenInternal(AccessTokenProviderChain.java:142)
at org.springframework.security.oauth2.client.token.AccessTokenProviderChain.obtainAccessToken(AccessTokenProviderChain.java:118)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:221)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.createRequest(OAuth2RestTemplate.java:105)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:505)
at org.springframework.security.oauth2.client.OAuth2RestTemplate.doExecute(OAuth2RestTemplate.java:128)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:472)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:237)
at com.sebit.security.client.oauth2.controller.HelloController.welcomePage(HelloController.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:215)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:132)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:745)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:686)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:953)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:844)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:829)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter.doFilter(OAuth2ClientContextFilter.java:57)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilter(BasicAuthenticationFilter.java:150)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter.doFilter(AbstractPreAuthenticatedProcessingFilter.java:94)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:343)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:260)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

这是我的服务器应用程序中的 web.xml:

  <servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-servlet.xml</param-value>
</context-param>

<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  <init-param>
    <param-name>contextAttribute</param-name>
    <param-value>org.springframework.web.servlet.FrameworkServlet.CONTEXT.spring</param-value>
  </init-param>
</filter>

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

这是我在服务器端的 spring-servlet.xml:

<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="clientAuthenticationManager"
    entry-point-ref="preAuthenticatedProcessingFilterEntryPoint" 
    xmlns="http://www.springframework.org/schema/security">
    <custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter" />
    <intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
    <anonymous enabled="false" />
    <http-basic entry-point-ref="preAuthenticatedProcessingFilterEntryPoint" />

    <custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>



<http pattern="/index/**" create-session="never" 
    entry-point-ref="preAuthenticatedProcessingFilterEntryPoint" access-decision-manager-ref="accessDecisionManager"
    xmlns="http://www.springframework.org/schema/security">
    <custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter" />
    <anonymous enabled="false" />
    <intercept-url pattern="/index" access="ROLE_USER, SCOPE_READ" />

    <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>


<http auto-config="false" xmlns="http://www.springframework.org/schema/security"
    >
    <custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter" />
    <intercept-url pattern="/oauth/**" access="ROLE_USER" />
    <!--intercept-url pattern="/index/**" access="ROLE_USER" /-->
    <intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <http-basic entry-point-ref="preAuthenticatedProcessingFilterEntryPoint" />
    <anonymous />
</http>

<beans:bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />

<beans:bean id="userDetailsServiceImpl"
    class="com.sebit.security.server.oauth2.controller.UserDetailsServiceImpl" />


<beans:bean id="preAuthenticatedProcessingFilterEntryPoint"
    class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint"> 
        <beans:property name="realmName" value="Authorization" />
    </beans:bean>

<beans:bean id="preAuthenticationProvider"
    class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <beans:property name="preAuthenticatedUserDetailsService"
        ref="userDetailsServiceImpl" />
</beans:bean>

<beans:bean id="preAuthFilter"
    class="com.sebit.security.server.oauth2.controller.PreAuthentication">
    <beans:property name="authenticationManager" ref="appControlAuthenticationManager" />
</beans:bean>

<beans:bean id="clientCredentialsTokenEndpointFilter" class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
    <beans:property name="authenticationManager" ref="clientAuthenticationManager" />
</beans:bean>

<bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased" xmlns="http://www.springframework.org/schema/beans">
    <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>

<authentication-manager id="clientAuthenticationManager" xmlns="http://www.springframework.org/schema/security">
    <authentication-provider user-service-ref="clientDetailsUserService" />
</authentication-manager>

<authentication-manager alias="appControlAuthenticationManager">
    <authentication-provider ref="preAuthenticationProvider" />
</authentication-manager>

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

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

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


<oauth:authorization-server client-details-service-ref="clientDetails" token-services-ref="tokenServices"
    >
    <oauth:authorization-code />
    <oauth:implicit />
    <oauth:refresh-token />
    <oauth:client-credentials />
    <oauth:password />
</oauth:authorization-server>

<oauth:resource-server id="resourceServerFilter" resource-id="Authorization" token-services-ref="tokenServices" />

<oauth:client-details-service id="clientDetails">
    <oauth:client client-id="myClient" resource-ids="Authorization" authorized-grant-types="authorization_code"
        authorities="ROLE_CLIENT" scope="read,write" secret="secret"/>
</oauth:client-details-service>

<beans:bean id="accessConfirmationController" class="com.sebit.security.server.oauth2.controller.AccessConfirmationController">
    <beans:property name="clientDetailsService" ref="clientDetails" />
</beans:bean>

<mvc:default-servlet-handler />

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

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

这是我在客户端的 web.xml:

  <servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
    </listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml, /WEB-INF/spring-security.xml</param-value>
</context-param>
<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>

这是我在客户端的 spring-security.xml:

    <http auto-config="false" xmlns="http://www.springframework.org/schema/security"
>
    <intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
    <intercept-url pattern="/index/**" access="ROLE_USER" />
    <custom-filter position="PRE_AUTH_FILTER" ref="preAuthFilter" />
    <http-basic entry-point-ref="preAuthenticatedProcessingFilterEntryPoint" />
    <anonymous/>
    <custom-filter ref="oauth2ClientFilter" after="EXCEPTION_TRANSLATION_FILTER" />
</http>   

<oauth:client id="oauth2ClientFilter" />

<beans:bean id="userDetailsServiceImpl"
    class="com.sebit.security.client.oauth2.controller.UserDetailsServiceImpl" />

<beans:bean id="preAuthenticatedProcessingFilterEntryPoint"
    class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint"> 
        <beans:property name="realmName" value="messages" />
    </beans:bean>

<beans:bean id="preAuthenticationProvider"
    class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
    <beans:property name="preAuthenticatedUserDetailsService"
        ref="userDetailsServiceImpl" />
</beans:bean>

<beans:bean id="preAuthFilter"
    class="com.sebit.security.client.oauth2.controller.PreAuthentication">
    <beans:property name="authenticationManager" ref="appControlAuthenticationManager" />
</beans:bean>

<authentication-manager alias="appControlAuthenticationManager">
    <authentication-provider ref="preAuthenticationProvider" />
</authentication-manager>

<oauth:resource id="Authorization" type="authorization_code"
    client-id="myClient" client-secret="secret" access-token-uri="http://localhost/Authorization/oauth/token"
    user-authorization-uri="http://localhost/Authorization/oauth/authorize" scope="read,write" />    

<mvc:default-servlet-handler />

<mvc:annotation-driven>
    <mvc:message-converters>
        <beans:bean class="org.springframework.http.converter.BufferedImageHttpMessageConverter" />
    </mvc:message-converters>
</mvc:annotation-driven>

<beans:bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
    <beans:property name="converters">
        <beans:set>
            <beans:bean class="com.sebit.security.client.oauth2.controller.AccessTokenRequestConverter" />
        </beans:set>
    </beans:property>
</beans:bean>

<beans:bean id="helloController" class="com.sebit.security.client.oauth2.controller.HelloController">
    <beans:property name="restTemplate">
        <oauth:rest-template resource="Authorization" />
    </beans:property>
</beans:bean>

这是我在客户端的 mvc-dispatcher-servlet:

<bean
  class="org.springframework.web.servlet.view.InternalResourceViewResolver">
  <property name="suffix">
    <value>.jsp</value>
  </property>
</bean>

我打电话后

“/客户/索引”

它成功绕过登录表单(在服务器和客户端)并成功调用

“/授权/oauth/授权”

它成功添加了 client_id、response_type、scope、redirect_uri 和 state 参数。

访问被确认并进入批准页面。单击“授权”按钮后,我收到 401 未经授权的错误。

非常感谢任何帮助,谢谢。

4

1 回答 1

0

我想由您决定如何进行身份验证。但请注意,/token 端点不是(无论如何在标准身份验证代码流中)被用户使用。它应该具有适合其消费者(客户端应用程序)的安全性,所以如果我是你,我会首先删除“preAuthFilter”(它如何能够验证客户端?)。如果您认为客户不应该拥有秘密,那么您可能不是在编写企业级或 Web 级产品,但您可以自由地以任何您喜欢的方式保护 /token 端点。请注意,它将从客户端获取基本身份验证标头(如果客户端是标准的 tonr 样式的 Spring Security 应用程序)。

于 2014-07-18T16:30:53.183 回答