Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring OAuth2:DuplicateKeyException在重载下使用JdbcTokenStore和DefaultTokenServices时_Spring_Spring Security_Spring Boot_Oauth_Spring Security Oauth2 - Fatal编程技术网

Spring OAuth2:DuplicateKeyException在重载下使用JdbcTokenStore和DefaultTokenServices时

Spring OAuth2:DuplicateKeyException在重载下使用JdbcTokenStore和DefaultTokenServices时,spring,spring-security,spring-boot,oauth,spring-security-oauth2,Spring,Spring Security,Spring Boot,Oauth,Spring Security Oauth2,正如标题中提到的,当同一个客户端同时查询令牌端点(两个进程同时为同一个客户端请求令牌)时,我遇到了这个问题 身份验证服务器日志中的消息如下所示: 2016-12-05 19:08:03.313 INFO 31717 --- [nio-9999-exec-5] o.s.s.o.provider.endpoint.TokenEndpoint : Handling error: DuplicateKeyException, PreparedStatementCallback; SQL [inser

正如标题中提到的,当同一个客户端同时查询令牌端点(两个进程同时为同一个客户端请求令牌)时,我遇到了这个问题

身份验证服务器日志中的消息如下所示:

2016-12-05 19:08:03.313  INFO 31717 --- [nio-9999-exec-5] o.s.s.o.provider.endpoint.TokenEndpoint  : Handling error: DuplicateKeyException, PreparedStatementCallback; SQL [insert into oauth_access_token (token_id, token, authentication_id, user_name, client_id, authentication, refresh_token) values (?, ?, ?, ?, ?, ?, ?)]; ERROR: duplicate key value violates unique constraint "oauth_access_token_pkey"
      Detail: Key (authentication_id)=(4148f592d600ab61affc6fa90bcbf16f) already exists.; nested exception is org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "oauth_access_token_pkey"
      Detail: Key (authentication_id)=(4148f592d600ab61affc6fa90bcbf16f) already exists.
CREATE TABLE oauth_access_token
(
  token_id character varying(256),
  token bytea,
  authentication_id character varying(256) NOT NULL,
  user_name character varying(256),
  client_id character varying(256),
  authentication bytea,
  refresh_token character varying(256),
  CONSTRAINT oauth_access_token_pkey PRIMARY KEY (authentication_id)
)
我将PostgreSQL用于如下表:

2016-12-05 19:08:03.313  INFO 31717 --- [nio-9999-exec-5] o.s.s.o.provider.endpoint.TokenEndpoint  : Handling error: DuplicateKeyException, PreparedStatementCallback; SQL [insert into oauth_access_token (token_id, token, authentication_id, user_name, client_id, authentication, refresh_token) values (?, ?, ?, ?, ?, ?, ?)]; ERROR: duplicate key value violates unique constraint "oauth_access_token_pkey"
      Detail: Key (authentication_id)=(4148f592d600ab61affc6fa90bcbf16f) already exists.; nested exception is org.postgresql.util.PSQLException: ERROR: duplicate key value violates unique constraint "oauth_access_token_pkey"
      Detail: Key (authentication_id)=(4148f592d600ab61affc6fa90bcbf16f) already exists.
CREATE TABLE oauth_access_token
(
  token_id character varying(256),
  token bytea,
  authentication_id character varying(256) NOT NULL,
  user_name character varying(256),
  client_id character varying(256),
  authentication bytea,
  refresh_token character varying(256),
  CONSTRAINT oauth_access_token_pkey PRIMARY KEY (authentication_id)
)
我的应用程序如下所示:

@SpringBootApplication
public class OAuthServTest {
   public static void main (String[] args) {
      SpringApplication.run (OAuthServTest.class, args);
   }

   @Configuration
   @EnableAuthorizationServer
   @EnableTransactionManagement
   protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {

      @Autowired
      private AuthenticationManager authenticationManager;

      @Autowired
      private DataSource            dataSource;

      @Bean
      public PasswordEncoder passwordEncoder ( ) {
         return new BCryptPasswordEncoder ( );
      }

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

      @Override
      public void configure (ClientDetailsServiceConfigurer clients) throws Exception {
         clients.jdbc (this.dataSource).passwordEncoder (passwordEncoder ( ));
      }

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

      @Bean
      public TokenStore tokenStore ( ) {
         return new JdbcTokenStore (this.dataSource);
      }

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

   }
}
我的研究总能使我找到答案。但是这个bug很久以前就被修复了,我现在使用的是最新版本的SpringBoot(v1.4.2)


我猜我做错了什么,在事务中没有检索令牌?

问题在于
DefaultTokenServices
上的竞态条件

我找到了一个解决办法。不是说它很华丽,而是说它很管用。其思想是在
令牌端点周围使用AOP建议添加重试逻辑:

@Aspect
@Component
public class TokenEndpointRetryInterceptor {

  private static final int MAX_RETRIES = 4;

  @Around("execution(* org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.*(..))")
  public Object execute (ProceedingJoinPoint aJoinPoint) throws Throwable {
    int tts = 1000;
    for (int i=0; i<MAX_RETRIES; i++) {
      try {
        return aJoinPoint.proceed();
      } catch (DuplicateKeyException e) {
        Thread.sleep(tts);
        tts=tts*2;
      }
    }
    throw new IllegalStateException("Could not execute: " + aJoinPoint.getSignature().getName());
  }

}
@方面
@组成部分
公共类令牌EndpointRetryInterceptor{
私有静态最终整数最大重试次数=4;
@大约(“execution(*org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.*(..)”)
公共对象执行(ProceedingJoinPoint aJoinPoint)抛出可丢弃{
int tts=1000;

对于(int i=0;i)如果您没有Spring并使用EJBs使用纯JEE,则可以考虑为此进行数据库表级别的处理。通过附加时间戳和一个随机字符串,这样它就不会失败并引发异常。这不是理想的修复方法,但可以完成这项工作

DELIMITER $$

CREATE TRIGGER handle_duplicate_authentication_id

BEFORE INSERT ON oauth_access_token
FOR EACH ROW
BEGIN

  declare suffix varchar(20);
  SET suffix = CONCAT(UNIX_TIMESTAMP(),SUBSTRING(MD5(RAND()) FROM 1 FOR 8));

  IF (EXISTS(SELECT 1 FROM oauth_access_token WHERE authentication_id = NEW.authentication_id)) THEN
        SET NEW.authentication_id = CONCAT(NEW.authentication_id, suffix);
  END IF;
  IF (EXISTS(SELECT 1 FROM oauth_access_token WHERE token_id = NEW.token_id)) THEN
        SET NEW.token_id = CONCAT(NEW.token_id, suffix);
  END IF;
END$$
DELIMITER ;


你能详细说明一下吗?我有同样的错误,为什么我需要这个?我的spring boot应用程序中没有:
@Aspect
@Around
ProceedingJoinPoint
。我如何解决同样的问题?