【问题标题】:spring security oauth2 ClassCastException configuring DefaultTokenServicesspring security oauth2 ClassCastException 配置 DefaultTokenServices
【发布时间】:2015-07-02 21:53:09
【问题描述】:

我正在尝试使用带有配置的 JdbcTokenStore 和具有无限生命周期访问令牌的 DefaultTokenServices 的 spring boot 和 spring security oauth 运行示例应用程序。

使用 gradle bootRun 运行这个应用程序,应用程序无法启动并抛出“Caused by: java.lang.ClassCastException: com.sun.proxy.$Proxy51 cannot be cast to org.springframework.security.oauth2.provider .token.DefaultTokenServices"

为什么在 DefaultTokenServices bean 周围有一个代理?

奇怪的是 - 使用 InMemoryTokenStore 运行应用程序...一切正常(参见内存分支)。

源码https://github.com/grafjo/oauth_demo/blob/master/src/main/java/demo/AuthorizationServerConfiguration.java

完整跟踪:http://pastebin.com/SUcwz4S5

【问题讨论】:

  • 我在为 JPA 启用事务支持时遇到了这个问题。您的@SpringBootApplication 可能正在自动配置事务数据源,是吗?我肯定在我的非 spring-boot 项目中将其追踪到 <tx:annotation-driven order="10"/>。一旦我将其注释掉,我的授权服务就配置得很好。不确定确切的冲突是什么,但我相当肯定这里存在系统性错误。尝试禁用交易只是为了验证。
  • 您确定要无限的终身访问令牌吗?!这几乎违背了拥有 oauth 的目的。刷新令牌的生命周期可能是无限的。

标签: spring spring-security spring-security-oauth2


【解决方案1】:

添加

<aop:config proxy-target-class="true"/> 

关于你的 spring 配置。

【讨论】:

    【解决方案2】:

    我在以下组合中使用 2.0.9.RELEASE 时遇到了同样的问题:

    pom.xml:

    ...    
    <spring.version>4.1.4.RELEASE</spring.version>       
    <spring-security.version>3.2.5.RELEASE</spring-security.version>
    <spring-security-oauth2.version>2.0.9.RELEASE</spring-security-oauth2.version>
    ...
    

    并且有相同的异常。

    降级到

    ...
    <spring-security-oauth2.version>2.0.3.RELEASE</spring-security-oauth2.version>
    ...
    

    为我解决了问题。

    【讨论】:

      【解决方案3】:

      这适用于版本 2.0.7.RELEASE

       @Primary
       @Bean
       protected AuthorizationServerTokenServices tokenServices() throws Exception{
      

      将DefaultTokenServices改为AuthorizationServerTokenServices后,Spring会报错:

      没有符合条件的 bean 类型 [org.springframework.security.oauth2.provider.token.ResourceServerTokenServices] 已定义:预期单个匹配 bean 但找到 3: defaultAuthorizationServerTokenServices,consumerTokenServices,tokenServices"}}

      【讨论】:

        【解决方案4】:

        快速浏览一下 DefaultTokenService 会发现它带有 @Transactional 注释。 Spring 会将其包装在代理中以服务事务 - 因此您需要通过其接口与类进行交互。

        对于您的 tokenService bean:

        @Bean
        public DefaultTokenServices tokenServices() {
            final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
            defaultTokenServices.setAccessTokenValiditySeconds(-1);
            defaultTokenServices.setTokenStore(tokenStore());
            return defaultTokenServices;
        }
        

        尝试将其更改为:

        @Bean
        public AuthorizationServerTokenServices tokenServices() {
            final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
            defaultTokenServices.setAccessTokenValiditySeconds(-1);
            defaultTokenServices.setTokenStore(tokenStore());
            return defaultTokenServices;
        }
        

        【讨论】:

        • 是的,这行得通。但是这个 bean 是如何在寻找 ResourceServerTokenServices 接口的 ResourceServerConfiguration 中自动装配的呢?当然 DefaultTokenServices 也实现了该接口,但是当我们将其公开为仅返回 AuthorizationServerTokenServices 的 bean 时,它不应该只在寻找 AuthorizationServerTokenServices 实现的类中自动装配吗?
        • 好的,我自己找到了之前评论的答案。在 spring 参考文档中它提到“如果要代理的目标对象至少实现一个接口,那么将使用 JDK 动态代理。目标类型实现的所有接口都将被代理。如果目标对象没有实现任何接口,然后将创建一个 CGLIB 代理。”因此,bean 实际上被注入到需要其任何接口的任何类中,而不仅仅是返回的那个。假设这不是真的,在您发布之前我什至没有尝试过您的解决方案:)
        【解决方案5】:

        我的应用程序中也有类似的异常,当将 spring oauth 版本从 2.0.7.RELEASE 更改为 2.0.3.RELEASE 时,它起作用了。也许这是最新版本的错误?

        编辑: 从错误看来,问题与 spring 创建的代理有关。当我将代理类型更改为 CGLIB 而不是默认动态代理时,它也适用于 2.0.7 版本。这个设置可以通过proxyTargetClass属性@EnableTransactionManagement(proxyTargetClass = true)来设置

        但是这个解决方案对我没有吸引力,因为我更喜欢默认代理方法而不是 CGLIB。这里还有一篇解释代理方法的文章http://thecafetechno.com/tutorials/spring/spring-proxying-mechanisms/

        【讨论】:

          猜你喜欢
          • 2018-01-20
          • 2014-04-06
          • 2018-10-02
          • 2023-03-26
          • 2019-12-04
          • 2016-03-14
          • 2015-05-08
          • 1970-01-01
          • 2019-09-25
          相关资源
          最近更新 更多