Buduję serwis Spring Boot przy użyciu Spotify Web API i chciałem przetestować metody kontrolera. Za pomocą przeglądarki mogłem sprawdzić żądanie GET i wszystko działało poprawnie - otrzymałem oczekiwane odpowiedzi. Problem wystąpił, gdy chciałem sprawdzić żądania POST za pomocą Postmana. Pomimo skonfigurowania autoryzacji poprzez OAuth 2.0 w Postmanie i otrzymania tokenów dostępu, przy każdej próbie złożenia żądania zwracany był kod źródłowy strony logowania Spotify, niezależnie od tego, czy było to żądanie POST, czy GET.
Tak wygląda moja konfiguracja Spotify w pliku application.properties:
spring.security.oauth2.client.registration.spotify.client-id=${SPOTIFY_CLIENT_ID}
spring.security.oauth2.client.registration.spotify.client-secret=${SPOTIFY_CLIENT_SECRET}
spring.security.oauth2.client.registration.spotify.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.spotify.redirect-uri=http://localhost:8080/login/oauth2/code/spotify
spring.security.oauth2.client.registration.spotify.scope=user-read-email,user-read-private
spring.security.oauth2.client.provider.spotify.authorization-uri=https://accounts.spotify.com/authorize
spring.security.oauth2.client.provider.spotify.token-uri=https://accounts.spotify.com/api/token
spring.security.oauth2.client.registration.spotify.provider=spotify
spring.security.oauth2.client.provider.spotify.user-info-uri=https://api.spotify.com/v1/me
spring.security.oauth2.client.provider.spotify.user-name-attribute=id
Mam ten sam identyfikator przekierowania URI ustawiony w ustawieniach aplikacji na stronie Spotify.
Serwis, w której znajduje się przykładowa metoda, którą chciałem przetestować, wygląda następująco:
@Service
@RequiredArgsConstructor
public class SpotifyService {
private final RestTemplate restTemplate;
private final String BASE_URL = "https://api.spotify.com/v1/";
private final ObjectMapper objectMapper;
public <T> T fetchData(String id, String endpoint, String accessToken, Class<T> responseType) {
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(accessToken);
HttpEntity<String> entity = new HttpEntity<>("parameters", headers);
ResponseEntity<String> response = restTemplate.exchange(
BASE_URL + endpoint + "/" + id,
HttpMethod.GET,
entity,
String.class
);
try {
return objectMapper.readValue(response.getBody(), responseType);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public ArtistDto getArtist(String artistId, String accessToken) {
return fetchData(
artistId,
"artists",
accessToken,
ArtistDto.class
);
}
}
I kontroler do tego:
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/spotify")
public class SpotifyController {
private final SpotifyService spotifyService;
private final TokenService tokenService;
@GetMapping("/artists/{id}")
public ResponseEntity<ArtistDto> getArtist(@PathVariable String id) {
String accessToken = tokenService.getAccessToken();
ArtistDto artistDto = spotifyService.getArtist(id, accessToken);
return ResponseEntity.ok(artistDto);
}
}
mam również ten TokenService, który zapewnia mi token dostępu:
@Service
@RequiredArgsConstructor
public class TokenService {
private final OAuth2AuthorizedClientService authorizedClientService;
public String getAccessToken() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthenticationToken oauthToken = (OAuth2AuthenticationToken) authentication;
OAuth2AuthorizedClient client = authorizedClientService.loadAuthorizedClient(
oauthToken.getAuthorizedClientRegistrationId(),
oauthToken.getName()
);
return client.getAccessToken().getTokenValue();
}
}
Tak jak mówiłem, gdy sprawdzam działanie tej metody w przeglądarce, zwraca mi poprawne dane w formacie JSON, natomiast gdy robię to w Postmanie, otrzymuję kod źródłowy strony logowania Spotify.
Tak wygląda moja konfiguracja OAuth 2.0 w Postman:

Nie używam zakresów, ponieważ chcę dostać się do danych publicznych. Próbowałem także zmienić Typ przyznania na Client Credentials, ale wynik jest taki sam - token jest wygenerowany poprawnie i zawarty w nagłówkach, ale odpowiedzią nadal jest strona logowania.
Próbowałem także utworzyć endpoint, który zwraca bieżący token dostępu za pośrednictwem przeglądarki i wklejać ten token do Postmana przy użyciu autoryzacji Bearer Token, ale nadal bezskutecznie.
Naprawdę mam nadzieję, że ktoś pomoże mi rozwiązać ten problem.