我设法获得授权代码,但一旦我尝试将其交换为访问令牌,我总是收到 400 错误请求。我正在遵循 Spotify 授权指南的 PKCE 流程中的授权代码。我正在使用 React 和 Vite,这是我的第一个 API 项目
这是我的 authWithPKCE.jsx:
export async function redirectToAuthCodeFlow(clientId) {
const verifier = generateCodeVerifier(128);
const challenge = await generateCodeChallenge(verifier);
localStorage.setItem("verifier", verifier);
const params = new URLSearchParams();
params.append("client_id", clientId);
params.append("response_type", "code");
params.append("redirect_uri", "http://localhost:5173/home");
params.append("scope", "user-read-private user-read-email");
params.append("code_challenge_method", "S256");
params.append("code_challenge", challenge);
document.location = `https://accounts.spotify.com/authorize?${params.toString()}`;
}
export async function getAccessToken(clientId, code) {
const verifier = localStorage.getItem("verifier");
const params = new URLSearchParams();
params.append("client_id", clientId);
params.append("grant_type", "authorization_code");
params.append("code", code);
params.append("redirect_uri", "http://localhost:5173/home");
params.append("code_verifier", verifier);
const result = await fetch("https://accounts.spotify.com/api/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: params,
});
}
function generateCodeVerifier(length) {
let text = "";
let possible =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < length; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
async function generateCodeChallenge(codeVerifier) {
const data = new TextEncoder().encode(codeVerifier);
const digest = await window.crypto.subtle.digest("SHA-256", data);
return btoa(String.fromCharCode.apply(null, [...new Uint8Array(digest)]))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=+$/, "");
}
如您所见,这与他们在教程中使用的代码流程几乎相同。
从我的 App.jsx 中,一旦用户单击登录按钮,它就会重定向到 Spotify 的授权页面并获取正确的重定向 uri,即我的 Home.jsx
这是我的 Home.jsx
import React, { useEffect, useState } from "react";
import { getAccessToken } from "../config/authWithPKCE";
const clientId = "";
export const Home = () => {
const urlParams = new URLSearchParams(window.location.search);
let code = urlParams.get("code");
console.log("Code: " + code.toString());
const [accessToken, setAccessToken] = useState(null);
const fetchAccessToken = async () => {
const token = await getAccessToken(clientId, code);
setAccessToken(token);
};
fetchAccessToken();
return (
<>
<h1>Logged In</h1>
{accessToken ? (
<p>Access Token: {accessToken}</p>
) : (
<p>Fetching access token...</p>
)}
</>
);
};
如有任何帮助,我们将不胜感激。谢谢!
我已经尝试使用教程和代码流中找到的获取令牌的两个不同的代码块,但两者似乎都不起作用。老实说我傻眼了。我还遵循了文档上的教程并设法使其工作,但似乎无法使其在这个上工作。
所以看起来我am能够获取访问令牌,但由于React的StrictMode执行组件两次的性质,getAccessToken的第二次调用会导致错误的请求,因为当授权代码为1时使用相同的授权代码- 仅限时间使用。我可以使用以下代码找到这一点,该代码在 html 本身中显示我的访问令牌:
<h1>
{localStorage.getItem("access_token") ? (
localStorage.getItem("access_token")
) : (
<p>No token</p>
)}
</h1>
这显示了我的令牌而不是错误的 p 标签,因此我能够验证我确实获得了访问令牌。
TLDR:React StrictMode 是罪魁祸首(渲染组件两次)。