简体   繁体   English

Spring Security OAuth2 InvalidGrantException

[英]Spring Security OAuth2 InvalidGrantException

I have successfully create a web-service using the spring-boot framework.我已经使用spring-boot框架成功创建了一个 web 服务。 Now I want to secure my web-service with OAuth2 (using spring) and have a few questions regarding that:现在我想用 OAuth2(使用 spring)保护我的网络服务,并有一些关于此的问题:

According to my research, spring provides some kind of default-url to request an access token ( baseURL/oauth/token ).根据我的研究,spring 提供了某种默认 URL 来请求访问令牌( baseURL/oauth/token )。 I have tested the URL using postman, and a valid access token was returned (using client_credentials grant type), but no refresh token.我已经使用邮递员测试了 URL,并返回了一个有效的访问令牌(使用 client_credentials 授权类型),但没有刷新令牌。 However this method does not work with grant_type=password and results in the following error response:但是,此方法不适用于grant_type=password并导致以下错误响应:

{"error":"invalid_grant","error_description":"Bad credentials"}

My spring application logs InvalidGrantException .我的 spring 应用程序记录InvalidGrantException

The curl I used to test grant_type=password is the following:我用来测试grant_type=password的 curl 如下:

curl -v -X POST -H "Content-Type: application/json" -H "Authorization: Basic base64encodedclientidandsecret" 'http://localhost:8888/oauth/token?grant_type=password&username=user&password=1234'

I did not test using postman because it does not support grant_type=password .我没有使用邮递员进行测试,因为它不支持grant_type=password

How can I get spring to return both accessToken and refreshToken using grant_type=password ?如何让 spring使用grant_type=password返回 accessToken 和 refreshToken

Is there anything wrong with my configuration?我的配置有问题吗?

My spring application (configuration) looks as follows:我的 spring 应用程序(配置)如下所示:

@Configuration
@ComponentScan
@EnableAutoConfiguration(exclude = { MongoAutoConfiguration.class, MongoDataAutoConfiguration.class })
@SpringBootApplication
public class CsWebServerApplication {

    public static final String RESOURCE_ID = "myresource";

    public static final String CLIENT_ID = "myapplication";
    public static final String CLIENT_SECRET = "application_secret";

    public static void main(String[] args) {

        SpringApplication.run(MyWebServerApplication.class, args);
    }

    @Configuration
    @EnableAuthorizationServer
    protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

        @Inject
        private AuthenticationManager authenticationManager;

        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.authenticationManager(authenticationManager);
        }

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

            clients.inMemory().withClient(CLIENT_ID)
            .authorizedGrantTypes("client_credentials", "password", "refresh_token")
            .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
            .scopes("read", "write", "trust")
            .secret(CLIENT_SECRET);
        }

        @Override
        public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
            super.configure(oauthServer);
        }
    }

    @Configuration
    @EnableResourceServer
    protected static class ResourceConfig extends ResourceServerConfigurerAdapter {

        @Override 
        public void configure(HttpSecurity http) throws Exception {

            http.requestMatchers().antMatchers("/*", "/admin/beans").and().authorizeRequests().anyRequest()
                .access("#oauth2.hasScope('read')"); 
        }

        @Override
        public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
            resources.resourceId(RESOURCE_ID);
        }
    }

    @Configuration
    @EnableWebSecurity
    protected static class WebConfigurer extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            super.configure(http);
        }

        @Override
        public void configure(WebSecurity webSecurity) throws Exception {
            webSecurity.ignoring()
                    // All of Spring Security will ignore the requests
                    .antMatchers("/accessibleservices/**")
        }
    }

}

" 4.3.2. Access Token Request " in RFC 6749 (The OAuth 2.0 Authorization Framework) says as follows. RFC 6749 (OAuth 2.0 授权框架)中的“ 4.3.2. 访问令牌请求”如下所述。

The client makes a request to the token endpoint by adding the following parameters using the "application/x-www-form-urlencoded" format per Appendix B with a character encoding of UTF-8 in the HTTP request entity-body:客户端通过使用附录 B 中的“application/x-www-form-urlencoded”格式添加以下参数向令牌端点发出请求,并在 HTTP 请求实体正文中使用 UTF-8 字符编码:

So, -H "Content-Type: application/json" is wrong.所以, -H "Content-Type: application/json"是错误的。 In addition, your curl command line is wrong.此外,您的 curl 命令行是错误的。 Use -d option to specify a form parameter for POST.使用-d选项为 POST 指定表单参数。

About supporting of refresh tokens.关于刷新令牌的支持。 By default spring oauth using DefaultTokenServices class and support of refresh tokens disabled by default.默认情况下,spring oauth 使用 DefaultTokenServices 类并默认禁用对刷新令牌的支持。 You should override its initialization in your OAuth2Config.class.您应该在 OAuth2Config.class 中覆盖其初始化。

Example:示例:

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setSupportRefreshToken(true);
        return tokenServices;
    } 

DefaultTokenServices.class DefaultTokenServices.class

not set TokenStore未设置 TokenStore

OAuth2RefreshToken refreshToken = tokenStore.readRefreshToken(refreshTokenValue);
    if (refreshToken == null) {
        throw new InvalidGrantException("Invalid refresh token: " + refreshTokenValue);
    }

pom.xml add pom.xml 添加

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

add config添加配置

@Configuration
public class RedisTokenStoreConfig {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    public TokenStore redisTokenStore (){
        return new RedisTokenStore(redisConnectionFactory);
    }
}

in your OAuth2Config在您的 OAuth2Config 中

@Autowired
@Qualifier("redisTokenStore")
private TokenStore tokenStore;

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
    endpoints.authenticationManager(authenticationManager)
            .userDetailsService(userService)
            .tokenStore(tokenStore);//set tokenStore
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM