我正在本地开发一个 React 应用程序,并使用 Keycloak 来管理身份验证。我使用keycloak.js包和react-keycloak包从react应用程序访问Keycloak服务器。
当用户未登录时,唯一可访问的路由应该是“/”和“/login”。 “/”路由呈现登陆页面,而“/login”路由重定向到 Keycloak 登录页面。这些路由存储在 PublicView 对象中。
如果用户登录,应该可以访问更多路由,例如“/collections”。例如,登录后,用户应重定向到“/”路由,然后重定向到“/collections”页面,而不是呈现登陆页面。
目前,React 应用程序的功能如用户未登录时所述。此外,登录后,用户会正确重定向到“/”路由,然后重定向到“/collections”路由并显示相关内容。
但是,如果我在浏览器中手动输入任何 PrivateView 路由(即重新加载单页应用程序),它只会显示“授权...”加载消息。它应该做的是根据 PrivateView 对象提供 URI。
虽然这表明客户端尚未初始化,但我知道身份验证一定已成功,因为应用程序的 return 语句中的行
{console.log("rendering:", isAuth)}
正确执行:
[<NotFound errorMessage={new Error("404 not found")}/>
组件。这是意外的,因为我重新加载/访问的所有路由都是在 PrivateView 对象中指定的。
有人知道我如何纠正这种行为吗?
以下是所有相关代码:
App.js:
import { Routes, Route, Navigate } from "react-router-dom"
import { useKeycloak } from "@react-keycloak/web"
// Components
import PrimaryLayout from "./components/layouts/PrimaryLayout"
// Pages
import About from "./pages/About/index"
import Collections from "./pages/Collections/index"
import Artworks from "./pages/Artworks/index"
import ArtworkPopup from "./pages/ArtworkPopup"
import Contact from "./pages/Contact/index"
import Login from "./pages/Login/index"
import Logout from "./pages/Logout/index"
import Landing from "./pages/Landing/index"
import NotFound from "./pages/NotFound/index"
import Tests from "./pages/__tests__/index"
// Styles
import './global.css'
function App() {
const { keycloak, initialized } = useKeycloak()
const isAuth = keycloak.authenticated
const PrivateView = (
<>
<Route element={ <PrimaryLayout /> } >
<Route path="about" element={ <About /> } />
<Route path="collections" >
<Route index element={ <Collections /> } />
<Route path=":collectionId" element={ <Navigate replace to="a" /> } />
<Route path=":collectionId/a" element={ <Artworks /> } >
<Route path=":artworkId" element={ <ArtworkPopup />} />
</Route>
</Route>
<Route path="contact" element={ <Contact /> } />
<Route path="logout" element={ <Logout /> } />
</Route>
<Route path="/" element={ <Navigate replace to="collections" /> } />
</>
)
const PublicView = (
<>
<Route path="/" element={ <Landing /> } />
<Route path="login" element={ <Login /> } />
</>
)
const SharedView = (
<>
<Route path="tests" element={ <Tests /> } />
<Route path="*" element={ <NotFound errorMessage={new Error("404 not found")}/> } />
</>
)
if (!initialized) {
console.log("Still loading")
return <div>Authenticating...</div>
}
return (
<Routes>
{console.log("rendering:", isAuth)}
{isAuth ? PrivateView : PublicView}
{SharedView}
</Routes>
)
}
export default App
登录.js:
import { useKeycloak } from "@react-keycloak/web"
import keycloakLogin from "../../data/keycloakLogin"
function Login() {
const { keycloak } = useKeycloak()
keycloak.login({redirectUri: "http://localhost:3001/")
return (
<main className="main">
<div className="page-description">
<h1 className="page-description__name">Login</h1>
</div>
<div>Redirecting to login...</div>
</main>
)
}
export default Login
index.js:
import React from "react"
import ReactDOM from 'react-dom/client'
import { ReactKeycloakProvider } from "@react-keycloak/web"
import { BrowserRouter } from "react-router-dom"
import './index.css'
// APP
import App from './App'
// Config
import keycloakClient from "./data/keycloakClient"
import keycloakInit from "./data/keycloakInit"
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
/* IMPORTANT
I wrapped the ReactKeycloakProvider around the React.StrictMode component to prevent double initialisation of the Keycloak client.
*/
<ReactKeycloakProvider authClient={keycloakClient} initOptions={
onLoad: 'check-sso',
silentCheckSsoRedirectUri: `${window.location.origin}/silent-check-sso.html`,
pkceMethod: "S256"
}>
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
</ReactKeycloakProvider>
);
BRUHH 好吧,这很令人沮丧,因为花了很长时间才弄清楚这个简单的错误,但基本上我初始化客户端的方式是错误的。我使用了silentSSO 方法。无论出于何种原因,这都不允许客户端正确进行身份验证,并且陷入循环中。我通过删除 ReactKeycloakProvider 中的silentCheckSsoRedirectUri选项解决了这个问题:
initOptions={
onLoad: 'check-sso',
// silentCheckSsoRedirectUri: `${window.location.origin}/silent-check-sso.html`,
pkceMethod: "S256"
}