Spring-OAUTH2.0:调用 /oauth/token 时没有可用资源错误

Posted

技术标签:

【中文标题】Spring-OAUTH2.0:调用 /oauth/token 时没有可用资源错误【英文标题】:Spring-OAUTH2.0: No resource available error on calling /oauth/token 【发布时间】:2014-11-23 14:01:14 【问题描述】:

我们有一组需要使用 OAUTH2.0 保护的 ReST Web 服务。我正在尝试通过参考以下资源来实现 OAUTH2.0:

Spring-security context setup for 2-legged (client credentials) OAuth2 server http://www.e-zest.net/blog/rest-authentication-using-oauth-2-0-resource-owner-password-flow-protocol/

但是,在完成所需的配置后,我试图点击 URL http://localhost:8080/project-name/oauth/token?grant_type=password&client_id=client1&client_secret=client1&username=admin&password=admin

Tomcat 抛出错误 - The requested resource is not available.

当我尝试在ClientDetailsServiceImpl.java 中放置一个调试点时,流程以正确的细节出现。无法理解我在这里做错了什么。任何建议表示赞赏。 TIA。

以下是文件详细信息:Spring 配置文件

<?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:oauth="http://www.springframework.org/schema/security/oauth2"
    xmlns:sec="http://www.springframework.org/schema/security" xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-1.0.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd ">


    <http pattern="/oauth/token" create-session="stateless"
        authentication-manager-ref="authenticationManager"
        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" />
        <custom-filter ref="clientCredentialsTokenEndpointFilter" before="BASIC_AUTH_FILTER" /> 
        <access-denied-handler ref="oauthAccessDeniedHandler" />
    </http>

    <http pattern="/resources/**" create-session="never"
        entry-point-ref="oauthAuthenticationEntryPoint"
        xmlns="http://www.springframework.org/schema/security">
        <anonymous enabled="false" />
        <intercept-url pattern="/resources/**" method="GET" access="IS_AUTHENTICATED_FULLY" />
        <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
        <access-denied-handler ref="oauthAccessDeniedHandler" />
    </http>

    <http pattern="/logout" create-session="never" 
        entry-point-ref="oauthAuthenticationEntryPoint"
        xmlns="http://www.springframework.org/schema/security">
        <anonymous enabled="false" />
        <intercept-url pattern="/logout" method="GET" />
        <sec:logout invalidate-session="true" logout-url="/logout" success-handler-ref="logoutSuccessHandler"   />
        <custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
        <access-denied-handler ref="oauthAccessDeniedHandler" />
    </http>

    <bean id="logoutSuccessHandler" class="in.test.server.security.oauth.LogoutImpl" >
        <property name="tokenstore" ref="tokenStore"></property>
    </bean>

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

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

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

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

    <bean id="clientDetails" class="in.test.server.security.oauth.ClientDetailsServiceImpl"/>

    <authentication-manager id="userAuthenticationManager" 
        xmlns="http://www.springframework.org/schema/security">
        <authentication-provider  ref="customUserAuthenticationProvider">
        </authentication-provider>
    </authentication-manager>

    <bean id="customUserAuthenticationProvider"
        class="in.test.server.security.oauth.CustomUserAuthenticationProvider">
    </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 authentication-manager-ref="userAuthenticationManager"/>
    </oauth:authorization-server>

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

    <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="true" />
        <property name="accessTokenValiditySeconds" value="300000"></property>
        <property name="clientDetailsService" ref="clientDetails" />
    </bean>


    <mvc:annotation-driven />   <!-- Declares explicit support for annotation-driven MVC controllers  @RequestMapping, @Controller -->

    <mvc:default-servlet-handler />

    <bean id="MyResource" class="in.test.server.resource.CommonResource"></bean>

</beans>

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"
    id="WebApp_ID" version="2.5">

    <display-name>in-test-gcp-server</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            classpath:applicationContext.xml
            classpath:security-config.xml
        </param-value>
    </context-param>

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

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

    <servlet>
        <servlet-name>jersey-serlvet</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>in.test.server.resource.TestRSApplication</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>


    <servlet-mapping>
        <servlet-name>jersey-serlvet</servlet-name>
        <url-pattern>/rest/*</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>CorsFilter</filter-name>
        <filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CorsFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- Added for 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>
</web-app>

ClientDetailsS​​erviceImpl.java

package in.test.server.security.oauth;

import java.util.ArrayList;
import java.util.List;

import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.BaseClientDetails;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.NoSuchClientException;
import org.springframework.stereotype.Service;

@Service
public class ClientDetailsServiceImpl implements ClientDetailsService 

    public ClientDetails loadClientByClientId(String clientId)
            throws OAuth2Exception 
if (clientId.equals("client1")) 

            List<String> authorizedGrantTypes=new ArrayList();
            authorizedGrantTypes.add("password");
            authorizedGrantTypes.add("refresh_token");
            authorizedGrantTypes.add("client_credentials");

            BaseClientDetails clientDetails = new BaseClientDetails();
            clientDetails.setClientId("client1");
            clientDetails.setClientSecret("client1");
            clientDetails.setAuthorizedGrantTypes(authorizedGrantTypes);

            return clientDetails;

         else if(clientId.equals("client2"))

            List<String> authorizedGrantTypes=new ArrayList();
            authorizedGrantTypes.add("password");
            authorizedGrantTypes.add("refresh_token");
            authorizedGrantTypes.add("client_credentials");


            BaseClientDetails clientDetails = new BaseClientDetails();
            clientDetails.setClientId("client2");
            clientDetails.setClientSecret("client2");
            clientDetails.setAuthorizedGrantTypes(authorizedGrantTypes);

            return clientDetails;
        


        else
            throw new NoSuchClientException("No client with requested id: "
                    + clientId);
        
    





CustomUserAuthenticationProvider.java

package in.test.server.security.oauth;

import java.util.ArrayList;
import java.util.List;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;

public class CustomUserAuthenticationProvider implements AuthenticationProvider

    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException 
        if(authentication.getPrincipal().equals("user")&& authentication.getCredentials().equals("user"))
        

            List<GrantedAuthority> grantedAuthorities = new ArrayList();
            UsernamePasswordAuthenticationToken auth=new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(),grantedAuthorities);


            return auth;

        
        else if(authentication.getPrincipal().equals("admin")&& authentication.getCredentials().equals("admin"))
        
            List<GrantedAuthority> grantedAuthorities = new ArrayList();
            UsernamePasswordAuthenticationToken auth=new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(),grantedAuthorities);

            return auth;
        
        else if(authentication.getPrincipal().equals("user1")&& authentication.getCredentials().equals("user1"))
        
            List<GrantedAuthority> grantedAuthorities = new ArrayList();
            UsernamePasswordAuthenticationToken auth=new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), authentication.getCredentials(),grantedAuthorities);

            return auth;
        
        else
                throw new BadCredentialsException("Bad User Credentials.");
        
    

    public boolean supports(Class<?> arg0) 
        // TODO Auto-generated method stub
        return true;
    







【问题讨论】:

你成功了吗? 【参考方案1】:

在您的 web.xml 中,您需要一个带有指向 /oauth/token 的 url-pattern 属性的 servlet-mapping 标记

类似:

<servlet-mapping>
    <servlet-name>spring <!-- Or whatever your dispatch servlet is called --></servlet-name>
    <url-pattern>/oauth/token</url-pattern>
</servlet-mapping>

【讨论】:

以上是关于Spring-OAUTH2.0:调用 /oauth/token 时没有可用资源错误的主要内容,如果未能解决你的问题,请参考以下文章

如何集成 AngularJS 和 Spring-OAuth2?

为啥没有spring-oauth2的starter pom?

如何将 Angular 2 应用程序与 spring-oauth2 服务器连接?

认证功能实现(spring-oauth2)

Spring - oauth 2 - 无法将访问令牌转换为 JSON

Spring - OAuth2AccessTokenSupport 覆盖其余模板自定义 SSLSocketFactory