fix(auth): redirect expired sessions before permission checks
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { signIn } from "next-auth/react";
|
||||
import AccessTimeOutlinedIcon from "@mui/icons-material/AccessTimeOutlined";
|
||||
import {
|
||||
@@ -18,6 +18,7 @@ import { useTheme } from "@mui/material/styles";
|
||||
import { useAuthStore } from "@/store/authStore";
|
||||
|
||||
const WARNING_WINDOW_MS = 15 * 60 * 1000;
|
||||
const EXPIRED_REDIRECT_DELAY_MS = 2_000;
|
||||
|
||||
type SessionExpiryDialogProps = {
|
||||
expiresAt?: number;
|
||||
@@ -31,6 +32,7 @@ export const SessionExpiryDialog = ({
|
||||
const reason = useAuthStore((state) => state.sessionExpiryReason);
|
||||
const [now, setNow] = useState(() => Date.now());
|
||||
const [warningDismissed, setWarningDismissed] = useState(false);
|
||||
const redirectStartedRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = window.setInterval(() => setNow(Date.now()), 30_000);
|
||||
@@ -47,10 +49,27 @@ export const SessionExpiryDialog = ({
|
||||
[expiresAt, now, sessionExpired, warningDismissed],
|
||||
);
|
||||
|
||||
const handleReauthenticate = () => {
|
||||
const handleReauthenticate = useCallback(() => {
|
||||
if (redirectStartedRef.current) return;
|
||||
redirectStartedRef.current = true;
|
||||
const callbackUrl = `${window.location.pathname}${window.location.search}`;
|
||||
void signIn("keycloak", { callbackUrl, redirect: true });
|
||||
};
|
||||
void signIn("keycloak", { callbackUrl, redirect: true }).catch(() => {
|
||||
redirectStartedRef.current = false;
|
||||
});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!sessionExpired) {
|
||||
redirectStartedRef.current = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const timer = window.setTimeout(
|
||||
handleReauthenticate,
|
||||
EXPIRED_REDIRECT_DELAY_MS,
|
||||
);
|
||||
return () => window.clearTimeout(timer);
|
||||
}, [handleReauthenticate, sessionExpired]);
|
||||
|
||||
const isOpen = sessionExpired || isExpiringSoon;
|
||||
const title = sessionExpired ? "登录已过期" : "登录即将到期";
|
||||
@@ -77,6 +96,11 @@ export const SessionExpiryDialog = ({
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
重新认证不会自动重放已失败的写入请求;请在返回后确认内容并再次提交。
|
||||
</Typography>
|
||||
{sessionExpired && (
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
即将自动跳转到登录页面。
|
||||
</Typography>
|
||||
)}
|
||||
</Stack>
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
|
||||
Reference in New Issue
Block a user