我正在尝试创建一个涉及使用 Spotify Web API 的应用程序。为了使用它,我必须让用户登录他们的 Spotify 帐户,这需要身份验证。
我能够让用户访问身份验证页面,但在他们成功同意允许应用程序访问其数据后,我收到错误 403,表示我无权查看该页面。本质上,在我当前的程序中,我有一个登陆页面,其中有一个按钮,上面写着“使用 Spotify 登录”,然后将他们带到身份验证页面,完成后应该转到另一个页面。但相反,我收到了错误消息。我认为这与
getSpotifyUserCode
方法有关。当我批准 Spotify 重定向页面的身份验证后,错误提示我未获得授权。我认为这与访问令牌有关 - 比如我的程序没有正确为用户分配访问令牌。这是处理身份验证的代码:
import java.io.IOException;
import java.net.URI;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletResponse;
import se.michaelthelin.spotify.SpotifyApi;
import se.michaelthelin.spotify.SpotifyHttpManager;
import se.michaelthelin.spotify.exceptions.SpotifyWebApiException;
import se.michaelthelin.spotify.model_objects.credentials.AuthorizationCodeCredentials;
import se.michaelthelin.spotify.requests.authorization.authorization_code.AuthorizationCodeRequest;
import se.michaelthelin.spotify.requests.authorization.authorization_code.AuthorizationCodeUriRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.view.RedirectView;
@RestController
@RequestMapping("/api")
public class AuthController {
private static final URI redirectorUri = SpotifyHttpManager.makeUri("http://localhost:8080/api/get-user-code/");
private String code = "";
private String refreshToken = "";
private static final SpotifyApi spotifyApi = new SpotifyApi.Builder()
.setClientId("13e244917ca64efb96556f753fcd032b")
.setClientSecret("ded93049447347769bcea9b2327c7ba6")
.setRedirectUri(redirectorUri)
.build();
@GetMapping("login")
@ResponseBody
public RedirectView spotifyLogin() {
AuthorizationCodeUriRequest authorizationCodeUriRequest = spotifyApi.authorizationCodeUri()
.scope("playlist-modify-public, user-read-private, user-read-email, user-top-read")
.show_dialog(true)
.build();
final URI uri = authorizationCodeUriRequest.execute();
RedirectView redirectView = new RedirectView();
redirectView.setUrl(uri.toString());
return redirectView;
}
@GetMapping(value = "get-user-code")
public String getSpotifyUserCode(@RequestParam("code") String userCode, HttpServletResponse response) throws IOException {
System.out.println("Received user code: " + userCode); // Debugging output
if (userCode == null || userCode.isEmpty()) {
return "No authorization code provided.";
}
AuthorizationCodeRequest authorizationCodeRequest = spotifyApi.authorizationCode(userCode).build();
try {
// Exchange the authorization code for access and refresh tokens
final AuthorizationCodeCredentials authorizationCodeCredentials = authorizationCodeRequest.execute();
// Set the access and refresh tokens in your SpotifyApi instance
spotifyApi.setAccessToken(authorizationCodeCredentials.getAccessToken());
spotifyApi.setRefreshToken(authorizationCodeCredentials.getRefreshToken());
refreshToken = authorizationCodeCredentials.getRefreshToken(); // Store refresh token
System.out.println("Access Token: " + authorizationCodeCredentials.getAccessToken());
System.out.println("Refresh Token: " + authorizationCodeCredentials.getRefreshToken());
System.out.println("Expires in: " + authorizationCodeCredentials.getExpiresIn());
} catch (IOException | SpotifyWebApiException | org.apache.hc.core5.http.ParseException e) {
System.out.println("Error during token exchange: " + e.getMessage());
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error during token exchange.");
return "Error during token exchange.";
}
response.sendRedirect("http://localhost:8080/success");
return spotifyApi.getAccessToken(); // Send a redirect response
}
}
Maven 3.9.9 和 Java 17
mvn --version
从 Windows CMD
tree /F
C:.
│ pom.xml
│
└───src
└───main
├───java
│ └───com
│ └───example
│ └───spotifyauth
│ AuthController.java
│ SpotifyAuthServerApplication.java
│
└───resources
application.properties
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>spotify-auth-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<properties>
<java.version>17</java.version>
<spring-boot.version>3.0.0</spring-boot.version>
</properties>
<dependencies>
<!-- Spring Boot Starter Web (includes Logback for logging) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${spring-boot.version}</version>
</dependency>
<!-- Spotify API for Java with SLF4J and Logback exclusions -->
<dependency>
<groupId>se.michaelthelin.spotify</groupId>
<artifactId>spotify-web-api-java</artifactId>
<version>7.0.0</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Explicitly add Logback -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.10</version>
</dependency>
<!-- Jakarta Servlet API (for HttpServletResponse) -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring Boot Starter Test (optional, for testing) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>${spring-boot.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Spring Boot Maven Plugin -->
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
AuthController.java
package com.example.spotifyauth;
import java.io.IOException;
import java.net.URI;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import jakarta.servlet.http.HttpServletResponse;
import se.michaelthelin.spotify.SpotifyApi;
import se.michaelthelin.spotify.SpotifyHttpManager;
import se.michaelthelin.spotify.exceptions.SpotifyWebApiException;
import se.michaelthelin.spotify.model_objects.credentials.AuthorizationCodeCredentials;
import se.michaelthelin.spotify.requests.authorization.authorization_code.AuthorizationCodeRequest;
import se.michaelthelin.spotify.requests.authorization.authorization_code.AuthorizationCodeUriRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.view.RedirectView;
import javax.annotation.PostConstruct;
@RestController
@RequestMapping("/api")
public class AuthController {
private static final URI redirectUri = SpotifyHttpManager.makeUri("http://localhost:8080/api/get-user-code");
@Value("${spotify.client-id}")
private String clientId;
@Value("${spotify.client-secret}")
private String clientSecret;
private SpotifyApi spotifyApi;
@PostConstruct
public void init() {
// Initialize SpotifyApi using injected values
this.spotifyApi = new SpotifyApi.Builder()
.setClientId(clientId)
.setClientSecret(clientSecret)
.setRedirectUri(redirectUri)
.build();
}
@GetMapping("login")
@ResponseBody
public RedirectView spotifyLogin() {
AuthorizationCodeUriRequest authorizationCodeUriRequest = spotifyApi.authorizationCodeUri()
.scope("playlist-modify-public, user-read-private, user-read-email, user-top-read")
.show_dialog(true)
.build();
final URI uri = authorizationCodeUriRequest.execute();
RedirectView redirectView = new RedirectView();
redirectView.setUrl(uri.toString());
return redirectView;
}
@GetMapping("get-user-code")
public String getSpotifyUserCode(@RequestParam("code") String userCode, HttpServletResponse response) throws IOException {
if (userCode == null || userCode.isEmpty()) {
return "No authorization code provided.";
}
AuthorizationCodeRequest authorizationCodeRequest = spotifyApi.authorizationCode(userCode).build();
try {
final AuthorizationCodeCredentials authorizationCodeCredentials = authorizationCodeRequest.execute();
spotifyApi.setAccessToken(authorizationCodeCredentials.getAccessToken());
spotifyApi.setRefreshToken(authorizationCodeCredentials.getRefreshToken());
// Display token information
return "Access Token: " + authorizationCodeCredentials.getAccessToken() + "<br>" +
"Refresh Token: " + authorizationCodeCredentials.getRefreshToken() + "<br>" +
"Expires in: " + authorizationCodeCredentials.getExpiresIn();
} catch (IOException | SpotifyWebApiException | org.apache.hc.core5.http.ParseException e) {
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Error during token exchange.");
return "Error during token exchange: " + e.getMessage();
}
}
}
SpotifyAuthServerApplication.java
package com.example.spotifyauth;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpotifyAuthServerApplication {
public static void main(String[] args) {
SpringApplication.run(SpotifyAuthServerApplication.class, args);
}
}
application.properties
server.port=8080
spotify.client-id=your-client_id
spotify.client-secret=your-client_secret
mvn clean compile
mvn clean package
java -jar target/spotify-auth-server-0.0.1-SNAPSHOT.jar
http://localhost:8080/api/login