使用Postman测试Spring Boot Spotify API接口的授权异常问题
问题分析与解决方案
你的核心问题是Spring Security的默认拦截规则导致Postman请求被重定向到Spotify登录页面:
- 浏览器请求正常,是因为你已经通过OAuth2授权码流程完成了应用的登录,Spring Security会话中保存了你的认证信息,
TokenService能从SecurityContext中拿到关联的Spotify令牌。 - Postman请求时,没有经过应用的登录流程,
SecurityContext为空,Spring Security会将未认证的请求重定向到Spotify授权页面,因此返回登录页源码。 - 你在Postman中获取的Spotify令牌是给Spotify API用的,并非用于你的Spring Boot应用自身的认证,所以无法绕过应用的登录拦截。
下面提供两种针对性解决方案:
方案一:放开API端点的认证拦截(快速测试用)
适合测试阶段,直接允许/api/spotify/**路径无需认证即可访问,同时修改控制器支持外部传入Spotify令牌:
1. 添加Spring Security配置类
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/api/spotify/**").permitAll() // 放开API路径的认证要求 .anyRequest().authenticated() // 其他路径仍保持认证要求 ) .oauth2Login(); // 保留原有的OAuth2登录功能(供浏览器使用) return http.build(); } }
2. 修改控制器,从请求头接收Spotify令牌
@RestController @RequiredArgsConstructor @RequestMapping("/api/spotify") public class SpotifyController { private final SpotifyService spotifyService; @GetMapping("/artists/{id}") public ResponseEntity<ArtistDto> getArtist( @PathVariable String id, @RequestHeader("Authorization") String authHeader) { // 提取Bearer Token(格式为 "Bearer xxxxxx") String accessToken = authHeader.replace("Bearer ", ""); ArtistDto artistDto = spotifyService.getArtist(id, accessToken); return ResponseEntity.ok(artistDto); } }
使用方式
Postman请求时,在请求头中添加Authorization: Bearer {你的Spotify令牌},即可正常获取数据。
方案二:使用Client Credentials模式自动获取令牌(生产推荐)
如果只需访问Spotify公开数据,无需用户授权,改用Client Credentials授权模式,让应用自动获取并维护Spotify令牌,无需依赖用户登录:
1. 修改application.properties
添加Client Credentials类型的客户端配置:
# 原有授权码模式配置保留(供浏览器使用) 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.provider.spotify.user-info-uri=https://api.spotify.com/v1/me spring.security.oauth2.client.provider.spotify.user-name-attribute=id # 添加Client Credentials模式配置 spring.security.oauth2.client.registration.spotify-cc.client-id=${SPOTIFY_CLIENT_ID} spring.security.oauth2.client.registration.spotify-cc.client-secret=${SPOTIFY_CLIENT_SECRET} spring.security.oauth2.client.registration.spotify-cc.authorization-grant-type=client_credentials spring.security.oauth2.client.provider.spotify-cc.token-uri=https://accounts.spotify.com/api/token
2. 修改TokenService,支持Client Credentials模式
@Service @RequiredArgsConstructor public class TokenService { private final OAuth2AuthorizedClientManager authorizedClientManager; public String getClientCredentialsAccessToken() { OAuth2AuthorizeRequest request = OAuth2AuthorizeRequest .withClientRegistrationId("spotify-cc") .principal("client") .build(); OAuth2AuthorizedClient client = authorizedClientManager.authorize(request); return client.getAccessToken().getTokenValue(); } }
3. 在SecurityConfig中添加OAuth2AuthorizedClientManager Bean
@Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/api/spotify/**").permitAll() .anyRequest().authenticated() ) .oauth2Login(); return http.build(); } @Bean public OAuth2AuthorizedClientManager authorizedClientManager( ClientRegistrationRepository clientRegistrationRepository, OAuth2AuthorizedClientService authorizedClientService) { // 配置支持Client Credentials模式的客户端提供者 OAuth2AuthorizedClientProvider provider = OAuth2AuthorizedClientProviderBuilder.builder() .clientCredentials() .build(); DefaultOAuth2AuthorizedClientManager manager = new DefaultOAuth2AuthorizedClientManager( clientRegistrationRepository, authorizedClientService); manager.setAuthorizedClientProvider(provider); return manager; } }
4. 修改控制器,使用自动获取的令牌
@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) { // 自动获取Client Credentials模式的令牌 String accessToken = tokenService.getClientCredentialsAccessToken(); ArtistDto artistDto = spotifyService.getArtist(id, accessToken); return ResponseEntity.ok(artistDto); } }
使用方式
Postman直接发起GET请求http://localhost:8080/api/spotify/artists/{艺人ID}即可,无需手动添加令牌,应用会自动处理。
内容的提问来源于stack exchange,提问作者MCoffee
相关产品推荐
相关产品推荐

