我已经使用 PKCE 实现了 Auth0 React SDK 以及授权代码流,以在我的 React 单页应用程序 (SPA) 中获取访问令牌,以便对受保护的后端路由进行 API 调用。
我选择使用 PKCE 的授权代码流程,因为 SPA 被视为公共应用程序,而不是机密应用程序。因此,我们无法使用标准授权代码流程获取访问令牌。
当我使用loginWithRedirect()函数时,用户通过身份验证后一切都会顺利进行。但是,在使用 PKCE 实现授权代码流程(涉及生成用于使用代码验证程序和代码质询进行用户身份验证和授权的链接)后,用户会被重复重定向到重定向 URL。此外,重定向的链接每次都包含不同的代码查询参数值。
下面是我的代码和演示问题的屏幕截图。
Auth0Provider 设置
import { Auth0Provider } from "@auth0/auth0-react";
import React from "react";
export const Auth0ProviderComponent = ({
children,
}: {
children: React.ReactNode;
}) => {
// const navigate = useNavigate();
const domain = import.meta.env.VITE_AUTH0_ISSUER_BASE_URL;
const clientId = import.meta.env.VITE_AUTH0_CLIENT_ID;
const redirectUri = import.meta.env.VITE_BASE_FRONTEND_URL;
if (!(domain && clientId && redirectUri)) {
return null;
}
return (
<Auth0Provider
domain={domain}
clientId={clientId}
authorizationParams={{
redirect_uri: redirectUri,
}}
>
{children}
</Auth0Provider>
);
};
main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./index.css";
import { Auth0ProviderComponent } from "./components/Auth0ProviderComponent.tsx";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<Auth0ProviderComponent>
<App />
</Auth0ProviderComponent>
</React.StrictMode>
);
App.tsx
import { useEffect, useState } from "react";
import "./App.css";
import { useAuth0 } from "@auth0/auth0-react";
import CryptoJS from "crypto-js";
function App() {
const { isAuthenticated, isLoading, user } = useAuth0();
function base64URLEncode(input: any) {
const words = CryptoJS.enc.Utf8.parse(input);
const base64 = CryptoJS.enc.Base64.stringify(words);
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}
function sha256(input: any) {
const words = CryptoJS.enc.Utf8.parse(input);
const hash = CryptoJS.SHA256(words);
return hash.toString(CryptoJS.enc.Base64);
}
useEffect(() => {
if (!isLoading && !isAuthenticated && !user) {
//Create verifier
const randomBytes = CryptoJS.lib.WordArray.random(32); // 32 bytes
const verifier = base64URLEncode(
randomBytes.toString(CryptoJS.enc.Base64)
);
// Use the previously generated verifier to create the challenge code
const challenge = base64URLEncode(sha256(verifier));
//Generate link to authenticate and authorize users
const config = {
response_type: "code",
client_id: import.meta.env.VITE_AUTH0_CLIENT_ID,
code_challenge: challenge,
code_challenge_method: "S256",
redirect_uri: import.meta.env.VITE_BASE_FRONTEND_URL,
audience: import.meta.env.VITE_AUTH0_CLIENT_AUDIENCE,
scope: "read:user-resources",
};
const generatedLink = `https://${
import.meta.env.VITE_AUTH0_ISSUER_BASE_URL
}/authorize?${new URLSearchParams(config).toString()}`;
//Use the link
window.location.href = generatedLink;
}
if (!isLoading && isAuthenticated && user) {
alert("successfully log in");
}
}, [isAuthenticated, isLoading, user]);
return (
<>
<h1>Home page</h1>
</>
);
}
export default App;
无限循环,其中用户使用不同的代码查询值重定向到此重定向 uri。
当我记录 isAuthenticated 和用户状态时,它们总是分别为 false 和未定义。
我非常感谢您的帮助。我已经被这个 bug 困住了很长一段时间了。非常感谢。
我认为它会在无限循环中不断进行身份验证,因为您将 isloading 和 isAuthenticated 添加到 useEffect 依赖项数组中。这只是意味着每次您尝试登录时,它将开始加载,然后 useEffect 将再次工作并生成另一个链接