feat(admin): sync and authorize Keycloak users
This commit is contained in:
@@ -115,6 +115,29 @@ describe("RefineContext access authentication", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("shows an authorization message when access-context rejects the account", async () => {
|
||||
global.fetch = jest.fn().mockResolvedValue({
|
||||
ok: false,
|
||||
status: 403,
|
||||
headers: new Headers(),
|
||||
} as Response);
|
||||
|
||||
render(
|
||||
<App>
|
||||
<div>应用内容</div>
|
||||
</App>,
|
||||
);
|
||||
|
||||
expect(
|
||||
await screen.findByText("账号尚未获得访问权限"),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText("应用内容")).not.toBeInTheDocument();
|
||||
expect(useAuthStore.getState()).toMatchObject({
|
||||
sessionExpired: false,
|
||||
sessionExpiryReason: null,
|
||||
});
|
||||
});
|
||||
|
||||
it("prioritizes an unauthenticated session over route permissions", async () => {
|
||||
mockSessionState = { data: null, status: "unauthenticated" };
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { RefineKbar, RefineKbarProvider } from "@refinedev/kbar";
|
||||
import { RefineSnackbarProvider } from "@refinedev/mui";
|
||||
import { SessionProvider, signIn, useSession } from "next-auth/react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import React, { useEffect } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
import routerProvider from "@refinedev/nextjs-router";
|
||||
import { NavigationLink } from "@components/loading/NavigationLink";
|
||||
@@ -75,6 +75,7 @@ export const App = (props: React.PropsWithChildren<AppProps>) => {
|
||||
const setAccessContext = useAccessStore((state) => state.setContext);
|
||||
const setAccessLoading = useAccessStore((state) => state.setLoading);
|
||||
const resetAccess = useAccessStore((state) => state.reset);
|
||||
const [accessDenied, setAccessDenied] = useState(false);
|
||||
const can = (permission: string) => permissions.includes(permission);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -103,21 +104,29 @@ export const App = (props: React.PropsWithChildren<AppProps>) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (status !== "authenticated") {
|
||||
setAccessDenied(false);
|
||||
resetAccess();
|
||||
return;
|
||||
}
|
||||
|
||||
let cancelled = false;
|
||||
setAccessDenied(false);
|
||||
setAccessLoading(true);
|
||||
apiFetch(`${config.BACKEND_URL}/api/v1/access-context`, {
|
||||
projectHeaderMode: currentProjectId ? "include" : "omit",
|
||||
})
|
||||
.then(async (response) => {
|
||||
if (cancelled) return;
|
||||
if (response.status === 403) {
|
||||
setAccessDenied(true);
|
||||
resetAccess();
|
||||
return;
|
||||
}
|
||||
if (!response.ok) {
|
||||
resetAccess();
|
||||
return;
|
||||
}
|
||||
setAccessDenied(false);
|
||||
setAccessContext(await response.json());
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -392,7 +401,10 @@ export const App = (props: React.PropsWithChildren<AppProps>) => {
|
||||
}}
|
||||
>
|
||||
<SessionExpiryDialog expiresAt={data?.sessionExpiresAt} />
|
||||
<RoutePermissionGuard authenticated={status === "authenticated"}>
|
||||
<RoutePermissionGuard
|
||||
authenticated={status === "authenticated"}
|
||||
accessDenied={accessDenied}
|
||||
>
|
||||
{props.children}
|
||||
</RoutePermissionGuard>
|
||||
<RefineKbar />
|
||||
|
||||
Reference in New Issue
Block a user