Integracja Spring Boot i Salesforce

Integracja Spring Boot i Salesforce

Spring boot jest jednym z najpopularniejszych frameworków w świecie javowym. Tak samo Salesforce jest jednym z najczęściej używanych CRMów. Na pierwszy rzut oka integracja pomiędzy obydwoma powinna być dosyć prosta. Niestety nie wszystko jest tak proste jak się wydaje.

Problemy

Pierwszym problemem jest bardzo rozbudowana dokumentacja Salesforca. Wiele rzeczy jest poukrywanych i trudno je odnaleźć od samego początku. Drugą bolączką jest wiele różnych API, które Salesforce udostępnia oraz kilka razy do roku je aktualizuje. Niestety to również wiąże się z brakiem aktualnego sdk, które byłoby pomocne przy integracji. Innym problemem z którym się spotkałem, jest to, że wiele przykładów w sieci wymaga jednak ingerencji użytkownika przy autoryzacji do Salesforca. Jako, że spring boot działa na backendzie to chciałem tego uniknąć i stworzyć tą integrację w sposób nie wymagający działań użytkownika.

JWT

Pierwszą myślą jaka mi przyszła do głowy, to że może Salesforce działa również na tokenie jwt. Trochę czasu musiałem spędzić zanim odkryłem w przykładach i dokumentacji stronę która to opisuje. Na szczęście integracja Spring boot i Salesforce przy użycia JWT jest możliwa. Więc teraz już było łatwiej. Na sam początek należy wygenerować klucz prywatny i publiczny np poprzez komendę

openssl req -newkey rsa:2048 -nodes -keyout key.pem -x509 -days 365 -out certificate.pem

Salesforce

Integrację należy zacząć od Salesforca. Jeśli nie masz do niego dostępu, załóż sobie darmowe konto dla developera. Po rejestracji i zalogowaniu się do systemu wejdź w APP Manager i kliknij “Create new connected app”

Strona główna Salesforce
Strona główna Salesforce

Uzupełnij podstawowe dane. Przy API zaznacz enable OAuth Settings. Niestety musisz podać callback url chociaż w tym przypadku nie będzie on używany. Musisz zaznaczyć “use digital signature” i dodać utworzony wcześniej klucz publiczny – certificate.pem. W końcu możesz zapisać wprowadzone zmiany. Skopiuj consumer key, bo z niego będziesz korzystał. Jeśli skończysz konfigurację w tym momencie to niestety będziesz się musiał zalogować do aplikacji. Jednak jeśli wejdziesz w manage utworzonej aplikacji to będziesz mógł edytować oauth policy.

Ważne aby edytować Permitted users na admin approved users are pre authorized. Spring boot salesforce integration
Ważne aby edytować Permitted users na admin approved users are pre authorized

Ważne jest aby wybrać dla pola “Permitted users” opcję “Admin approved users are pre-authorized”. Dodatkowo kilka sekcji niżej ustaw profiles lub permission set na użytkownika/użytkowników którzy będą mieć dostęp poprzez API. Dzięki temu nie musisz się ręcznie autoryzować.

Spring boot i Salesforce

Pierwszą rzeczą jaką należy zrobić aby dostać access_token jest utworzenie tokena JWT.

    private String createJwtToken() {
        LocalDateTime localDateTime = LocalDateTime.now().plusMinutes(salesforceConfiguration.getExpirationInMinutes());
        return Jwts.builder()
                .setIssuer(salesforceConfiguration.getClientId())
                .setAudience(salesforceConfiguration.getAudience())
                .setSubject(salesforceConfiguration.getSubject())
                .setExpiration(Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()))
                .signWith(keyRetriever.getKey())
                .compact();
    }


  • issuer – to jest consumer key, który skopiowałeś z salesforca
  • audience – url gdzie możesz się zalogować w tym przypadku “https://login.salesforce.com”
  • subject – nazwa użytkownika w Salesforcie, uprawiona do korzystania z tej connected app
  • signWith – tutaj zwracasz klucz prywatny, który wcześniej wygenerowałeś

Kolejnym krokiem jest wysłanie requestu z wygenerowanym tokenem

private SalesforceToken sentRequest(String jwt) {
        String url = UriComponentsBuilder.fromUriString(salesforceConfiguration.getAudience()).path("/services/oauth2/token")
                .queryParam("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer")
                .queryParam("assertion", jwt)
                .toUriString();

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        return restTemplate.postForObject(url, new HttpEntity<>(null, headers), SalesforceToken.class);
    }

Jest to post z content typem application/x-www-form-urlencoded. A jako query paramsy są przekazane grant type oraz assertion, które przyjmuje wartość tokena jwt. Oczywiście wszyskie stałe możesz zastąpić enumami. W responsie są informacje o access tokenie

{"access_token":"00Dxx0000001gPL!AR8AQJXg5oj8jXSgxJfA0lBog.
39AsX.LVpxezPwuX5VAIrrbbHMuol7GQxnMeYMN7cj8EoWr78nt1u44zU31
IbYNNJguseu","scope":"web openid api id","instance_url":"
https://yourInstance.salesforce.com","id":"
https://yourInstance.salesforce.com
/id/00Dxx0000001gPLEAY/005xx000001SwiUAAS","token_type":"Bearer"}
  • access_token – będziesz używał później jako Authorization Bearer
  • instance_url – jest bazowym urlem do wszystkich requestów.

Później już integrujesz się bezpośrednio z resourcami których potrzebujesz.

Podsumowanie

Spring boot i Salesforce integrują się łatwo przy użyciu JWT. Integracja wymaga wykonania kilku kroków po stronie Salesforca i standardowych rzeczy w spring boocie. Cała ta wiedza jest mocno rozproszona i mam nadzieję, że dzięki temu wpisowi wszystko co niezbędne znajdziesz w jednym miejscu. Może masz jakieś inne doświadczenia z taką integracją?

Kod dostępny na githubie.