java + spring security oauth token 未返回,找不到 404 页面

Posted

技术标签:

【中文标题】java + spring security oauth token 未返回,找不到 404 页面【英文标题】:java + spring security oauth token not returned with 404 page not found 【发布时间】:2016-01-30 14:53:39 【问题描述】:

大家,我知道已经有类似问题的解决方案,但这个问题是不同的。

我还阅读了link 的存在,但该解决方案不适用于我。

我的问题是我正在尝试使用 oauth2.0 保护我的 Java+Spring+Jersey 网络服务应用程序,并且一直在使用 spring-security-oauth2 库版本。

每当我调用/oauth/token 时,应用程序会验证标题下提供的详细信息(client_secret, client_id and grant_type),客户端已成功通过身份验证,但不会从服务器返回令牌数据,而是返回 404 页面未找到响应显示。

这里是以下配置:

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/javaee"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
        version="2.5">
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>WEB-INF/spring/dispatcher-servlet.xml</param-value>
        </context-param>
    
        <servlet>
            <servlet-name>jersey-servlet</servlet-name>
            <servlet-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</servlet-class>
            <init-param>
                <param-name>com.sun.jersey.config.property.packages</param-name>
                <param-value>com.tprivity.babycenter.ws</param-value>
            </init-param>
            <init-param>
                <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
                <param-value>true</param-value>
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>jersey-servlet</servlet-name>
            <url-pattern>/*</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>
    </web-app>
    

    调度程序-servlet.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:oauth2="http://www.springframework.org/schema/security/oauth2"
        xmlns:p="http://www.springframework.org/schema/p" xmlns:security="http://www.springframework.org/schema/security"
        xmlns:tx="http://www.springframework.org/schema/tx"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
            http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
            http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd
            http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
    
        <security:http pattern="/oauth/token" create-session="stateless"
            authentication-manager-ref="authenticationManager">
            <security:intercept-url pattern="/oauth/token"
                access="IS_AUTHENTICATED_FULLY" />
            <security:anonymous enabled="false" />
            <security:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
            <security:custom-filter ref="clientCredentialsTokenEndpointFilter"
                before="BASIC_AUTH_FILTER" />
            <security:access-denied-handler ref="oauthAccessDeniedHandler" />
        </security:http>
    
        <security:http pattern="/ws/**" create-session="never"
            authentication-manager-ref="authenticationManager" entry-point-ref="oauthAuthenticationEntryPoint">
            <security:anonymous enabled="false" />
            <security:intercept-url pattern="/ws/**"
                method="GET" access="IS_AUTHENTICATED_FULLY" />
            <security:intercept-url pattern="/ws/**"
                method="POST" access="IS_AUTHENTICATED_FULLY" />
            <security:custom-filter ref="resourceServerFilter"
                before="PRE_AUTH_FILTER" />
            <security:access-denied-handler ref="oauthAccessDeniedHandler" />
        </security:http>
    
        <bean id="oauthAuthenticationEntryPoint"
            class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
        </bean>
    
        <bean id="clientAuthenticationEntryPoint"
            class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
            <property name="realmName" value="springsec/client" />
            <property name="typeName" value="Basic" />
        </bean>
    
        <bean id="oauthAccessDeniedHandler"
            class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
    
    
        <bean id="clientCredentialsTokenEndpointFilter"
            class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
            <property name="authenticationManager" ref="authenticationManager" />
        </bean>
    
        <security:authentication-manager alias="authenticationManager">
            <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="clientDetails"
            class="org.springframework.security.oauth2.provider.client.JdbcClientDetailsService">
            <constructor-arg index="0">
                <ref bean="dataSource" />
            </constructor-arg>
        </bean>
    
        <security:authentication-manager id="userAuthenticationManager">
            <security:authentication-provider
                ref="customUserAuthenticationProvider" />
        </security:authentication-manager>
    
        <bean id="customUserAuthenticationProvider"
            class="com.tprivity.babycenter.ws.security.CustomUserAuthenticationProvider">
        </bean>
    
        <!-- Authorization Server Configuration of the server is used to provide 
            implementations of the client details service and token services and to enable 
            or disable certain aspects of the mechanism globally. -->
        <oauth2:authorization-server
            client-details-service-ref="clientDetails" token-services-ref="tokenServices"
            user-approval-handler-ref="userApprovalHandler">
            <oauth2:authorization-code />
            <oauth2:implicit />
            <oauth2:refresh-token />
            <oauth2:client-credentials />
            <oauth2:password authentication-manager-ref="userAuthenticationManager" />
        </oauth2:authorization-server>
    
        <oauth2:resource-server id="resourceServerFilter"
            resource-id="springsec" token-services-ref="tokenServices" />
    
        <bean id="tokenStore"
            class="org.springframework.security.oauth2.provider.token.store.JdbcTokenStore">
            <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
        </bean>
    
        <!-- Configure Authentication manager -->
        <bean id="passwordEncoder"
            class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
            <constructor-arg name="strength" value="11" />
        </bean>
    
        <!-- Grants access if only grant (or abstain) votes were received. We can 
            protect REST resource methods with JSR-250 annotations such as @RolesAllowed -->
        <bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
            <property name="decisionVoters">
                <list>
                    <bean class="org.springframework.security.access.annotation.Jsr250Voter" />
                </list>
            </property>
        </bean>
    
        <bean id="tokenServices"
            class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
            <property name="tokenStore" ref="tokenStore" />
            <property name="supportRefreshToken" value="true" />
            <property name="accessTokenValiditySeconds" value="120"></property>
            <property name="clientDetailsService" ref="clientDetails" />
        </bean>
    
        <!-- A user approval handler that remembers approval decisions by consulting 
            existing tokens -->
        <bean id="oAuth2RequestFactory"
            class="org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory">
            <constructor-arg ref="clientDetails" />
        </bean>
    
        <bean id="userApprovalHandler"
            class="org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler">
            <property name="requestFactory" ref="oAuth2RequestFactory" />
            <property name="tokenStore" ref="tokenStore" />
        </bean>
    </beans>
    

以下是相同的日志。

DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - <Checking match of request : '/oauth/token'; against '/oauth/token'>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 1 of 7 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 2 of 7 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 3 of 7 in additional filter chain; firing Filter: 'ClientCredentialsTokenEndpointFilter'>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 4 of 7 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'>
DEBUG [org.springframework.security.web.authentication.www.BasicAuthenticationFilter] - <Basic Authentication Authorization header found for user 'bccws'>
DEBUG [org.springframework.security.authentication.ProviderManager] - <Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider>
WARN [org.springframework.context.support.ResourceBundleMessageSource] - <ResourceBundle [messages] not found for MessageSource: Can't find bundle for base name messages, locale en_US>
WARN [org.springframework.context.support.ResourceBundleMessageSource] - <ResourceBundle [labels] not found for MessageSource: Can't find bundle for base name labels, locale en_US>
WARN [org.springframework.context.support.ResourceBundleMessageSource] - <ResourceBundle [errors] not found for MessageSource: Can't find bundle for base name errors, locale en_US>
DEBUG [org.springframework.jdbc.core.JdbcTemplate] - <Executing prepared SQL query>
DEBUG [org.springframework.jdbc.core.JdbcTemplate] - <Executing prepared SQL statement [select client_id, client_secret, resource_ids, scope, authorized_grant_types, web_server_redirect_uri, authorities, access_token_validity, refresh_token_validity, additional_information, autoapprove from oauth_client_details where client_id = ?]>
DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Fetching JDBC Connection from DataSource>
DEBUG [org.springframework.jdbc.datasource.DataSourceUtils] - <Returning JDBC Connection to DataSource>
DEBUG [org.springframework.security.web.authentication.www.BasicAuthenticationFilter] - <Authentication success: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@f9d8c511: Principal: org.springframework.security.core.userdetails.User@593829e: Username: bccws; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ADMIN>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 5 of 7 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 6 of 7 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token at position 7 of 7 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'>
DEBUG [org.springframework.security.web.util.matcher.AntPathRequestMatcher] - <Checking match of request : '/oauth/token'; against '/oauth/token'>
DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - <Secure object: FilterInvocation: URL: /oauth/token; Attributes: [IS_AUTHENTICATED_FULLY]>
DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - <Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@f9d8c511: Principal: org.springframework.security.core.userdetails.User@593829e: Username: bccws; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ADMIN; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ADMIN>
DEBUG [org.springframework.security.access.vote.AffirmativeBased] - <Voter: org.springframework.security.access.vote.RoleVoter@6dbd30e2, returned: 0>
DEBUG [org.springframework.security.access.vote.AffirmativeBased] - <Voter: org.springframework.security.access.vote.AuthenticatedVoter@19d7bbb3, returned: 1>
DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - <Authorization successful>
DEBUG [org.springframework.security.web.access.intercept.FilterSecurityInterceptor] - <RunAsManager did not change Authentication object>
DEBUG [org.springframework.security.web.FilterChainProxy] - </oauth/token reached end of additional filter chain; proceeding with original chain>
DEBUG [org.springframework.security.web.access.ExceptionTranslationFilter] - <Chain processed normally>
DEBUG [org.springframework.security.web.context.SecurityContextPersistenceFilter] - <SecurityContextHolder now cleared, as request processing completed>

我一直在寻找问题,但没有找到任何解决方案。任何帮助将不胜感激。

【问题讨论】:

是否可以上传您的 Web 应用程序相关部分的源代码(例如可运行版本)?我对可能出现的问题有一些想法,但如果无法调试就很难确定。 【参考方案1】:

幕后发生的事情是 /oauth/token 请求需要由下面的端点类提供服务

http://docs.spring.io/spring-security/oauth/xref/org/springframework/security/oauth2/provider/endpoint/TokenEndpoint.html

@RequestMapping(value = "/oauth/token")
public ResponseEntity<OAuth2AccessToken> getAccessToken(Principal principal, @RequestParam

并且 TokenEndpoint 实例是由 oauth2:授权服务器 标签。 从日志中,您的客户端和用户凭据已通过您在日志中看到的所有安全过滤器的验证。 之后,请求应该由 MVC Web 框架传递给 TokenEndpoint,但似乎没有。

您需要打开 org.springframework.web 跟踪日志以查看发生了什么。

你可以检查你的 web.xml,你需要配置 /oauth/token 绑定到 Spring MVC Dispatcher Servlet。

 <servlet>
    <servlet-name>spring-mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/webmvc-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
    <servlet-name>spring-mvc</servlet-name>
    <url-pattern>/oauth/*</url-pattern>
</servlet-mapping>

【讨论】:

【参考方案2】:

当您的安全过滤器在其上下文中没有 oauth/token 端点时,就会发生这种情况。注册springSecurityFilterChain时尝试在web.xml中添加上下文属性

<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.dispatcher</param-value>
</init-param>

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

【讨论】:

以上是关于java + spring security oauth token 未返回,找不到 404 页面的主要内容,如果未能解决你的问题,请参考以下文章

Spring Security Java Config Preview--官方

一款基于 Spring Boot 开发的 OA 项目,接私活必备!

一款基于 Spring Boot 开发的 OA 项目,接私活必备!

java.security.Principal - 在 HttpServletRequest 和 Spring Security 中创建

Spring- Security :java.lang.NoClassDefFoundError: org/springframework/security/context/DelegatingApp

spring security 登陆报错java.lang.StackOverflowError: null?