#30 Spring Boot – Resource Server

W poprzednim wpisie przygotowaliśmy rozwiązanie korzystające z Single Sign-On. Teraz korzystając z tego mechanizmu chcielibyśmy zabezpieczyć inne moduły naszej aplikacji. Aby to osiągnąć, nasze moduły muszą stać się serwerami zasobów (ang. Resource Server). Jak to zrobić wykorzystując Spring Boot’a? Zapraszamy do wpisu!

Maven

Zaczynamy od dodania zależności do Maven’a:

<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

Włączamy Resource Server

Aby ustawić nasz moduł jako Resource Server, musimy dodać adnotację @EnableResourceServer:

@SpringBootApplication
@EnableResourceServer
public class ResourceServerApplication {

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

Controller

Dodajmy teraz prosty kontroler, który będzie naszym “chronionym” zasobem:

@RestController
class CodeCoupleController {

    @GetMapping("/not-for-all")
    String showCodeCouple(){
        return "Code Couple!";
    }

}

Properties

W pliku application.properties musimy wskazać URI, pod którym dostępne będą informacje o użytkowniku (korzystamy z API GitHub’a):

#User info endpoint
security.oauth2.resource.user-info-uri=https://api.github.com/user
#Prefer user info
security.oauth2.resource.prefer-token-info=false

Testujemy

Spróbujmy udać się pod adres /not-for-all, w odpowiedzi dostaniemy:

<oauth>
    <error_description>
        Full authentication is required to access this resource
    </error_description>
    <error>unauthorized</error>
</oauth>

Od teraz każdy nasz request do usługi /not-for-all wymaga tokenu typu Bearer. Token ten możemy zdobyć od naszego dostawcy, czyli GitHub’a. Należy udać się pod adres:

https://github.com/login/oauth/authorize?client_id=your-client_id&response_type=code&state=yz1Bhx

Ustawiając dane:

  • client_id – wygenerowane w serwisie unikalne ID
  • response_type – typ odpowiedzi, w naszym przypadku oczekujemy typu code
  • state – unikalny ciąg znaków dla bezpieczeństwa

Następnie zostaniemy przekierowani na adres strony, który ustawiliśmy w GitHub’ie (czyli callback URL) wraz z wartością code:

http://localhost:9191/?code=69b25b069e9e5ae21000&state=yz1Bhx

Teraz korzystając z dowolnego klienta HTTP (polecam Postman’a) wysyłamy żądanie POST:

https://github.com/login/oauth/access_token?code=69b25b069e9e5ae21000&client_id=your-client-id&state=yz1Bhx&client_secret=your-client-secret

Ustawiając dane:

  • client_id – wygenerowane w serwisie unikalne ID
  • client_secret – wygenerowany w serwisie kod secret
  • code – wygenerowany kod w poprzednim kroku
  • state – unikalny ciąg znaków dla bezpieczeństwa (ten sam co wcześniej)

W odpowiedzi otrzymujemy Bearer token:

access_token=6f80ecc3602ea730982545a6707b35ff83061000&scope=&token_type=bearer

Możemy teraz użyć ten token korzystając po raz kolejny z klienta HTTP. Ustawiamy nagłówek Authorization wraz z wartością Bearer 6f80ecc3602ea730982545a6707b35ff83061000, w odpowiedzi powinien pokazać się napis “Code Couple!“.

Wcześniejsza aplikacja

Możemy także wykorzystać aplikację z poprzedniego wpisu, aby otrzymać Bearer token (bez potrzeby przygotowywania parametrów URI). Wystarczy dodać nowy endpoint, wraz z odczytaną wartością z OAuth2ClientContext:

@Autowired
private OAuth2ClientContext clientContext;
@GetMapping("/token")
String showToken() {
 return clientContext.getAccessToken().getValue();
}

Pod endpointem /token otrzymamy Bearer token, który możemy używać do odpytywania “chronionych” zasobów.

GitHub

Całość jak zawsze na GitHub’ie.