使用 Java Spring Boot 的 Spotify Oauth2 身份验证

问题描述 投票:0回答:1

我正在尝试创建一个涉及使用 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
    }
    
}
java spring-boot spotify
1个回答
0
投票

要求

Maven 3.9.9 和 Java 17

mvn --version

enter image description here

文件树

从 Windows CMD

tree /F
C:.
│   pom.xml
│
└───src
    └───main
        ├───java
        │   └───com
        │       └───example
        │           └───spotifyauth
        │                   AuthController.java
        │                   SpotifyAuthServerApplication.java
        │
        └───resources
                application.properties

Java源代码

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

enter image description here

mvn clean package

enter image description here

java -jar target/spotify-auth-server-0.0.1-SNAPSHOT.jar

enter image description here

通过浏览器登录

http://localhost:8080/api/login

enter image description here

结果

将显示访问令牌和刷新令牌。 enter image description here

© www.soinside.com 2019 - 2024. All rights reserved.