Java 弹簧OAuth2-Can';无法获取客户端令牌

Java 弹簧OAuth2-Can';无法获取客户端令牌,java,spring,spring-mvc,spring-security,oauth-2.0,Java,Spring,Spring Mvc,Spring Security,Oauth 2.0,我不能100%确定我正在执行正确的请求,但我似乎无法为客户端获取令牌。我的解决方案基于本教程 我正在执行邮递员的请求: /oauth/token?授权类型=客户凭据&客户id=mysupplycompany&客户机密=mycompanyk 该请求的响应异常: org.springframework.security.authentication.InsufficientAuthenticationException: 没有客户端身份验证。尝试添加适当的 身份验证筛选器。 org.springfr

我不能100%确定我正在执行正确的请求,但我似乎无法为客户端获取令牌。我的解决方案基于本教程

我正在执行邮递员的请求:

/oauth/token?授权类型=客户凭据&客户id=mysupplycompany&客户机密=mycompanyk

该请求的响应异常:

org.springframework.security.authentication.InsufficientAuthenticationException: 没有客户端身份验证。尝试添加适当的 身份验证筛选器。 org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(TokenEndpoint.java:91)

下面是一些您可能需要帮助我解决任何问题的文件/类

WebInitializer

package com.squirrels.config;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration.Dynamic;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.DispatcherServlet;

public class WebInitializer implements WebApplicationInitializer {

    public void onStartup(ServletContext servletContext) throws ServletException {          
        WebApplicationContext context = getContext();
        servletContext.addListener(new ContextLoaderListener(context));
        servletContext.addListener(new RequestContextListener());    

        Dynamic servlet = servletContext.addServlet("dispatcher", new DispatcherServlet(context));  
        servlet.addMapping("/");  
        servlet.setLoadOnStartup(1);  

        DelegatingFilterProxy filter = new DelegatingFilterProxy("springSecurityFilterChain");
        filter.setContextAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher");
        servletContext.addFilter("springSecurityFilterChain", filter).addMappingForUrlPatterns(null, false, "/*");
    }  

    private AnnotationConfigWebApplicationContext getContext() {
        AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
        context.setConfigLocation("com.squirrels.config");
        return context;
    }

}
package com.squirrels.auth;

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

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;

public class OAuthAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private OAuthProxy proxy;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        boolean result = proxy.isValidUser("1", authentication.getPrincipal().toString(), authentication.getCredentials().toString());

        if (result) {
            List<GrantedAuthority> grantedAuthorities =

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

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

    @Override
    public boolean supports(Class<?> arg0) {
        return true;
    }

}
PersistenceJPAConfig

package com.squirrels.config;

import java.util.Properties;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import liquibase.integration.spring.SpringLiquibase;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@EnableTransactionManagement
@ComponentScan({ "com.squirrels.controller", "com.squirrels.services", "com.squirrels.persistence.dao", "com.squirrels.auth" })
@PropertySource(value = { "classpath:squirrel.properties" })
@ImportResource("classpath:spring-security.xml")
public class PersistenceJPAConfig {

    @Autowired
    private Environment environment;

    @Bean
    public SpringLiquibase liquibase() {
        SpringLiquibase liquibase = new SpringLiquibase();
        liquibase.setDataSource(dataSource());
        liquibase.setDefaultSchema(environment.getRequiredProperty("db_schema"));
        liquibase.setChangeLog("classpath:/db/changelog/db.changelog-master.xml");

        return liquibase;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
        em.setDataSource(dataSource());
        em.setPersistenceUnitName("SquirrelAuth");
        em.setPackagesToScan(new String[] { "com.squirrels.persistence.model" });

        JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        em.setJpaVendorAdapter(vendorAdapter);
        em.setJpaProperties(additionalProperties());

        return em;
    }

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(environment.getRequiredProperty("db_driverClass"));
        dataSource.setUrl(environment.getRequiredProperty("db_jdbcUrl"));
        dataSource.setUsername(environment.getRequiredProperty("db_user"));
        dataSource.setPassword(environment.getRequiredProperty("db_password"));
        return dataSource;
    }

    @Bean
    public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(emf);

        return transactionManager;
    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
        return new PersistenceExceptionTranslationPostProcessor();
    }

    Properties additionalProperties() {
        Properties properties = new Properties();
        properties.setProperty("hibernate.dialect", environment.getRequiredProperty("db_hibernateDialect"));
        return properties;
    }


}
package com.squirrels.config;

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

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.ContentNegotiatingViewResolver;

@Configuration
@EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {


    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    };

    /*
     * Configure ContentNegotiatingViewResolver
     */
    @Bean
    public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager manager) {
        ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
        resolver.setContentNegotiationManager(manager);

        // Define all possible view resolvers
        List<ViewResolver> resolvers = new ArrayList<ViewResolver>();
        resolvers.add(jsonViewResolver());         
        resolver.setViewResolvers(resolvers);
        return resolver;
    }

    /*
     * Configure View resolver to provide JSON output using JACKSON library to
     * convert object in JSON format.
     */
    @Bean
    public ViewResolver jsonViewResolver() {
        return new JsonViewResolver();
    }

}
security spring.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: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/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-4.1.xsd 
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd">


    <sec:http pattern="/oauth/token" create-session="stateless"
        authentication-manager-ref="authenticationManager">
        <sec:intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY" />
        <sec:anonymous enabled="false" />
        <sec:http-basic entry-point-ref="clientAuthenticationEntryPoint" />
        <sec:custom-filter ref="clientCredentialsTokenEndpointFilter"
            before="BASIC_AUTH_FILTER" />
        <sec:access-denied-handler ref="oauthAccessDeniedHandler" />
    </sec:http>

    <sec:http pattern="/api/**" create-session="never"
        entry-point-ref="oauthAuthenticationEntryPoint">
        <sec:anonymous enabled="false" />
        <sec:intercept-url pattern="/api/**" method="GET"
            access="IS_AUTHENTICATED_FULLY" />
        <sec:custom-filter ref="resourceServerFilter"
            before="PRE_AUTH_FILTER" />
        <sec:access-denied-handler ref="oauthAccessDeniedHandler" />
    </sec: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>

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

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

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

    <bean id="clientDetails" class="com.squirrels.auth.OAuthClientDetailsImpl">
        <property name="id" value="mysupplycompany" />
        <property name="secretKey" value="mycompanykey" />
    </bean>

    <sec:authentication-manager id="userAuthenticationManager">
        <sec:authentication-provider ref="customUserAuthenticationProvider" />
    </sec:authentication-manager>

    <bean id="customUserAuthenticationProvider" class="com.squirrels.auth.OAuthAuthenticationProvider">
    </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.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="accessTokenValiditySeconds" value="120"></property>
        <property name="clientDetailsService" ref="clientDetails" />
    </bean>

    <mvc:annotation-driven />
</beans>
package com.squirrels.auth;

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

import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.NoSuchClientException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;

public class OAuthClientDetailsImpl implements ClientDetailsService {

    private String id;
    private String secretKey;

    @Override
    public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
        if (clientId.equals(id))
        {
            List<String> authorizedGrantTypes = new ArrayList<String>();
            authorizedGrantTypes.add("password");
            authorizedGrantTypes.add("refresh_token");
            authorizedGrantTypes.add("client_credentials");

            BaseClientDetails clientDetails = new BaseClientDetails();
            clientDetails.setClientId(id);
            clientDetails.setClientSecret(secretKey);
            clientDetails.setAuthorizedGrantTypes(authorizedGrantTypes);

            return clientDetails;
        }
        else {
            throw new NoSuchClientException("No client recognized with id: " + clientId);
        }
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getSecretKey() {
        return secretKey;
    }

    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }

}
我也有同样的问题。 在我的例子中,是因为我映射了DispatcherServlet,如下所示:

<servlet-mapping>
  <servlet-name>dispatcher</servlet-name>
  <url-pattern>/dispatcher/*</url-pattern>
</servlet-mapping>
所以我不得不做:

<security:http pattern="/dispatcher/oauth/token" 
如果使用java config而不是web.xml,则扩展类
org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer

将对其进行配置。

不确定这是否是您的问题,但您发送到令牌端点的参数不应是URL的一部分。它们应该是POST请求的一部分。@LukeTaylor我也有同样的问题,但我正在发布请求。目前还没有解决方案,正在搜索…现在尝试一下,这实际上是有意义的。我已将调度程序映射到/api/*。我还将编辑我的问题并包括我的JavaConfig文件类。我所有的spring工具都是通过java配置的,除了spring安全工具。谢谢!这个答案和将我的调度程序从/api/*切换到/*一样有效。我终于运行了一个完全可操作的oauth2 Provider(很高兴提供帮助:)如果您想保留“/api/*”,也许可以帮助您。它说,如果覆盖默认的oauth端点URL,则可能必须配置另一个DelegatingFilterProxy。
<servlet-mapping>
  <servlet-name>dispatcher</servlet-name>
  <url-pattern>/dispatcher/*</url-pattern>
</servlet-mapping>
<security:http pattern="/oauth/token" ...
<security:http pattern="/dispatcher/oauth/token" 
<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>