【问题标题】:Spring Security OAuth2 InvalidGrantExceptionSpring Security OAuth2 InvalidGrantException
【发布时间】:2016-04-11 12:34:09
【问题描述】:

我已经使用spring-boot 框架成功创建了一个网络服务。现在我想用 OAuth2(使用 spring)来保护我的网络服务,并且对此有几个问题:

根据我的研究,spring 提供了某种默认 URL 来请求访问令牌 (baseURL/oauth/token)。我已经使用邮递员测试了 URL,并返回了有效的访问令牌(使用 client_credentials 授权类型),但没有刷新令牌。但是此方法不适用于grant_type=password,并导致以下错误响应:

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

我的spring应用日志InvalidGrantException

我用来测试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'

我没有使用邮递员进行测试,因为它不支持grant_type=password

如何让 spring 使用 grant_type=password 同时返回 accessToken 和 refreshToken

我的配置有什么问题吗?

我的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/**")
        }
    }

}

【问题讨论】:

    标签: java spring spring-boot spring-security-oauth2


    【解决方案1】:

    RFC 6749(OAuth 2.0 授权框架)中的“4.3.2. Access Token Request”如下所述。

    客户端通过添加 以下参数使用 "application/x-www-form-urlencoded" 符合附录 B 的格式,HTTP 中的字符编码为 UTF-8 请求实体主体:

    所以,-H "Content-Type: application/json" 是错误的。另外,你的 curl 命令行是错误的。使用 -d 选项为 POST 指定表单参数。

    【讨论】:

      【解决方案2】:

      关于刷新令牌的支持。默认情况下,spring oauth 使用 DefaultTokenServices 类并默认禁用刷新令牌支持。您应该在 OAuth2Config.class 中覆盖其初始化。

      例子:

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

      【讨论】:

        【解决方案3】:

        DefaultTokenServices.class

        没有设置TokenStore

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

        【讨论】:

          【解决方案4】:

          pom.xml 添加

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

          添加配置

          @Configuration
          public class RedisTokenStoreConfig {
          
              @Autowired
              private RedisConnectionFactory redisConnectionFactory;
          
              @Bean
              public TokenStore redisTokenStore (){
                  return new RedisTokenStore(redisConnectionFactory);
              }
          }
          

          在您的 OAuth2Config 中

          @Autowired
          @Qualifier("redisTokenStore")
          private TokenStore tokenStore;
          
          @Override
          public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
              endpoints.authenticationManager(authenticationManager)
                      .userDetailsService(userService)
                      .tokenStore(tokenStore);//set tokenStore
          }
          

          【讨论】:

            猜你喜欢
            • 2019-09-25
            • 2019-04-29
            • 2017-09-11
            • 2019-04-28
            • 2015-11-14
            • 2016-07-12
            • 2017-01-18
            • 2012-12-19
            • 1970-01-01
            相关资源
            最近更新 更多