2016-10-28 3 views
4

Я создаю систему, которая регулярно экспортирует данные от имени многих пользователей во внешнюю систему с HTTP-запросами, аутентифицированными OAuth2.Использование OAuth2RestTemplate от имени нескольких пользователей

Я успешно был в состоянии общаться с внешним обслуживанием с использованием Spring Security oauth2, с OAuth2RestTemplate настроен так:

@Configuration 
@EnableOAuth2Client 
public class ExternalServiceConfiguration { 

    @Autowired 
    private OAuth2ClientContext oauth2Context; 

    @Bean 
    public OAuth2ProtectedResourceDetails credentials() { 

     ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails(); 
     details.setAccessTokenUri("https://external-service.example.com/OAuth/Token"); 
     details.setClientId("abcdefghijklmnopq"); 
     details.setClientSecret("123456789123456789123456789"); 
     details.setGrantType("client_credentials"); 

     return details; 
    } 

    @Bean 
    public OAuth2RestTemplate externalServiceRestTemplate() { 
     return new OAuth2RestTemplate(credentials(), oauth2Context); 
    } 
} 

Это хорошо работает, и я могу привнести OAuth2RestTemplate боб в мой услуги:

@Autowired 
@Qualifier("externalServiceRestTemplate") 
private OAuth2RestTemplate restTemplate; 

Однако в моем приложении у меня есть несколько пользователей, которым необходимо настроить собственные клиентские ключи. В случае, если это имеет значение, я делаю это пакетное задание, то есть оно выполняется за пределами обычного HTTP-запроса, а иногда и в том же контексте потока.

Это означает, что мне нужно будет иметь несколько OAuth2ProtectedResourceDetails и, предположим, несколько экземпляров OAuth2RestTemplate. Поскольку это то, что каждый пользователь будет настраивать самостоятельно, он должен выполняться динамически, на основе учетных данных клиента, сохраненных в базе данных.

Есть ли у кого-нибудь советы по настройке динамического числа экземпляров OAuth2RestTemplate эффективным, но потокобезопасным способом?

ответ

2

Поскольку никто еще не ответил, я попытаюсь ответить на собственный вопрос.

Я создал репозиторий боб, который кэширует и возвращает RestTemplate на основе секретного ключа клиента:

@Repository 
public class ExternalServiceRepository { 

    private static ConcurrentHashMap<String, OAuth2RestTemplate> restTemplates = new ConcurrentHashMap<>(); 

    /** 
    * Get a RestTemplate for a specific client based on it's client secret id. 
    * Create one if it hasn't been initialized yet. 
    */ 
    public OAuth2RestTemplate restTemplate(String clientKey) { 

     synchronized (restTemplates) { 
      OAuth2RestTemplate restTemplate = restTemplates.get(clientKey); 

      if (restTemplate == null) { 
       ClientCredentialsResourceDetails details = new ClientCredentialsResourceDetails(); 
       details.setAccessTokenUri("https://external-service.example.com/OAuth/Token"); 
       details.setClientId("abcdefghijklmnopq"); 
       details.setClientSecret(clientKey); 
       details.setGrantType("client_credentials"); 

       restTemplate = new OAuth2RestTemplate(details, new DefaultOAuth2ClientContext()); 
       restTemplates.put(clientKey, restTemplate); 
      } 

      return restTemplate; 
     } 
    } 
} 

Вместо использование @ EnableOAuth2Client аннотации, который устанавливает контекст клиента OAuth2 для каждого HTTP-сессии, Я создаю свой собственный DefaultOAuth2ClientContext. Поскольку я использую только учетные данные клиента, я считаю, что этот код является потокобезопасным (пожалуйста, докажите, что я ошибаюсь, если вы думаете иначе).

Наконец, вместо инъекции RestTemplate, я инъекционный и с помощью моего хранилища, чтобы получить доступ к restTemplate для данного клиента секрета:

RestTemplate restTemplate = 
    externalServiceRepository.restTemplate("123456789123456789123456789"); 
+1

Интересно, есть ли какая-либо сборка в решениях используя OAuth2RestTemplate/Spring, который может выполнить то, что вы описываете, без создания экземпляра и кеширования произвольного количества OAuth2RestTemplates. Может быть, пользовательский AccessTokenProvider и другая реализация OAuth2RestTemplate? Мне бы хотелось услышать, что думают другие. – Vladimir