【问题标题】:Resteasy / Spring Security + Oauth 2.0 - error 404Resteasy / Spring Security + Oauth 2.0 - 错误 404
【发布时间】:2014-04-06 16:38:18
【问题描述】:

我正在尝试使用 Resteasy 和 Spring 构建 REST 服务器/提供程序,并希望使用 OAuth 2 保护一些 API。据我了解,我应该让 API 公开一个 URI 以生成 OAuth 令牌(例如 /oauth/token),然后使用它来访问安全部分。

下面是我使用 Spring Security 及其 OAuth2 支持的代码,我尝试在保护 /ws/v1/oauth/** 的同时公开单个 /oauth/token URI。当我尝试在不发送凭据的情况下访问任何这些 URI 时,我会收到安全“错误凭据请求”(如我所料),但是当我尝试在 /oauth/token URI 上实际输入正确的凭据时(通过 POST 方法) 我遇到了 HTTP 404 错误。

我的 web.xml 代码。

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        classpath:spring-context.xml
        classpath:database-context.xml
        classpath:security-context.xml
    </param-value>
</context-param>

<!-- RestEasy Bootstrap -->
<listener>
    <listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>

<!-- Spring Bootstrap -->
<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

<listener>
    <listener-class>org.jboss.resteasy.plugins.spring.SpringContextLoaderListener</listener-class>
</listener>

<!-- RestEasy Servlet -->
<servlet>
    <servlet-name>Resteasy</servlet-name>
    <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Resteasy</servlet-name>
    <url-pattern>/ws/*</url-pattern>
</servlet-mapping>

<!-- OAuth2 / Spring Security -->
<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>

还有我的安全上下文。 (我在 stackoverflow 的一个示例中找到并稍作调整)

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

<sec:authentication-manager alias="clientAuthenticationManager">
    <sec:authentication-provider user-service-ref="clientDetailsUserService" />
</sec:authentication-manager>

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

    <!-- include this only if you need to authenticate clients via request parameters -->
    <custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>

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

<oauth:client-details-service id="clientDetails">
    <oauth:client client-id="the_client" authorized-grant-types="client_credentials" 
            authorities="ROLE_READ" secret="1234567890" />
    <oauth:client client-id="password_client" authorized-grant-types="password" 
            authorities="ROLE_READ" secret="1234567890" />
</oauth:client-details-service>


<http pattern="/**" create-session="never"
        entry-point-ref="oauthAuthenticationEntryPoint"
        access-decision-manager-ref="accessDecisionManager"
        xmlns="http://www.springframework.org/schema/security">
    <anonymous enabled="false" />

    <intercept-url pattern="/ws/v1/oauth/**" access="ROLE_READ" method="GET" />
    <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
    <access-denied-handler ref="oauthAccessDeniedHandler" />
</http>

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

<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
    <property name="tokenStore" ref="tokenStore" />
    <property name="supportRefreshToken" value="false" />
    <property name="clientDetailsService" ref="clientDetails" />
    <property name="accessTokenValiditySeconds" value="400000" />
    <property name="refreshTokenValiditySeconds" value="0" />
</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>


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

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

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


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


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

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

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

我看到了一些类似的问题,其中 Spring Security 无法将 http 路径注册到上下文,因为它没有被传递,但我不知道如何在我的 Web.xml 中执行此操作,因为我使用 SpringContextLoaderListener 而不是 ContextLoaderListener (这似乎存在于我发现的所有示例/问题中)。

有关如何消除此 404 错误的任何提示?

编辑 - 澄清一下,我用 POST 和 GET 测试了 /oauth/token URL

获取示例:

http://127.0.0.1:9999/oauth/token?client_id=the_client&client_secret=1234567890&grant_type=client_credentials

在这两种情况下,我都会收到错误的凭据/错误 404

【问题讨论】:

    标签: java spring oauth spring-security resteasy


    【解决方案1】:

    TokenEndpoint 是 Spring MVC @Controller,因此您需要 DispatcherServlet 来处理请求。这可能意味着您需要完全放弃ContextLoaderListener(但我不知道SpringContextLoaderListener 正在做什么)并将您的配置移动到servlet(例如here)。幸运的是,默认的 servlet 映射“/”似乎是打开的,所以如果你安装了 servlet 并加载了配置文件,一切都应该正常工作。

    【讨论】:

    • 谢谢戴夫!问题在于缺少 servlet 来获取 /oauth/token 映射。还必须将 spring webmvc 注释添加到我的上下文中,以便 OAuth2 处理程序能够正确处理令牌请求。
    猜你喜欢
    • 2015-12-19
    • 1970-01-01
    • 2015-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-31
    • 2018-01-24
    • 2017-05-10
    相关资源
    最近更新 更多