Remix项目登录页异常:修改Loader后自动跳转至微软登录页
问题分析:登录页面自动跳转至微软登录界面的原因及修复
问题场景
原本登录页面包含「Sign in」按钮,点击后才会跳转至微软登录界面;修改Loader逻辑后,打开登录页直接自动跳转,完全看不到登录页面内容。
问题代码
export const loader = async ({ request }: LoaderArgs) => { const user = await authenticator.authenticate("microsoft", request, { failureRedirect: "/", successRedirect: "/stewardship", }); // 检查访问令牌是否过期 if (new Date((user as User).expiresAt) < new Date()) { const tenantId = process.env.TENANT_ID!; // 调用令牌端点获取新的访问令牌 const data = new FormData(); data.append("client_id", process.env.CLIENT_ID!); data.append("client_secret", process.env.CLIENT_SECRET!); data.append("scope", "openid email profile"); data.append("refresh_token", (user as User).refreshToken); data.append("grant_type", "refresh_token"); const response = await fetch( `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, { method: "POST", body: data }, ); const responseData = await response.json(); // 更新会话中的新访问令牌、刷新令牌和过期时间 const session = await getSession(request.headers.get("Cookie")); session.set("user", { ...(user as User), accessToken: responseData.access_token, refreshToken: responseData.refresh_token, expiresAt: new Date( Date.now() + responseData.expires_in * 1000, ).toISOString(), }); const cookie = await commitSession(session); // 返回用户信息并携带Set-Cookie头 const headers = { "Set-Cookie": cookie }; return json(user, { headers }); } return user; }; export default function Index() { return ( <Form action="/auth/microsoft" method="post"> <Grid container alignItems="center" justifyContent="center" > <Grid item xs="auto"> <Card sx={{ maxWidth: 345 }}> <CardContent> <Box textAlign="center"> <Box component="img" src={Logo} /> <Box my={2}> <Typography align="center"> This site uses your organizational username and password. Sign in with your credentials. </Typography> </Box> <Box> <Button variant="contained" endIcon={<ArrowForward />} sx={{ borderRadius: "30px" }} type="submit" > Sign In </Button> </Box> </Box> </CardContent> </Card> </Grid> </Grid> </Form> ); }
核心原因
问题出在登录页Loader中的authenticator.authenticate调用:
- 该方法的默认行为是:如果检测到无有效会话,会自动触发跳转至微软登录页面,而非允许页面继续渲染。
- 你将这个认证逻辑直接放在了登录页的Loader中,导致每次访问登录页时,只要没有有效会话,就会立即触发跳转,完全没有机会渲染登录页面的「Sign in」按钮。
修复方案
1. 拆分路由逻辑
将微软认证的核心逻辑移至专门的路由(如/auth/microsoft),登录页仅负责渲染登录按钮和检查已登录状态。
2. 修改登录页Loader
登录页Loader仅检查用户是否已登录,已登录则跳转至目标页面,未登录则返回空值让页面渲染:
export const loader = async ({ request }: LoaderArgs) => { // 仅检查会话状态,已登录则跳转,否则渲染登录页 try { await authenticator.isAuthenticated(request, { successRedirect: "/stewardship", }); } catch { // 无有效会话,返回空以渲染登录页面 return null; } };
3. 保留认证与Token刷新逻辑到专门路由
在/auth/microsoft路由中保留原有的认证和Token过期刷新逻辑:
export const loader = async ({ request }: LoaderArgs) => { const user = await authenticator.authenticate("microsoft", request, { failureRedirect: "/", successRedirect: "/stewardship", }); // 检查并刷新过期的Access Token if (new Date((user as User).expiresAt) < new Date()) { const tenantId = process.env.TENANT_ID!; const data = new FormData(); data.append("client_id", process.env.CLIENT_ID!); data.append("client_secret", process.env.CLIENT_SECRET!); data.append("scope", "openid email profile"); data.append("refresh_token", (user as User).refreshToken); data.append("grant_type", "refresh_token"); const response = await fetch( `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`, { method: "POST", body: data }, ); const responseData = await response.json(); const session = await getSession(request.headers.get("Cookie")); session.set("user", { ...(user as User), accessToken: responseData.access_token, refreshToken: responseData.refresh_token, expiresAt: new Date(Date.now() + responseData.expires_in * 1000).toISOString(), }); const cookie = await commitSession(session); return json(user, { headers: { "Set-Cookie": cookie } }); } return user; };
4. 登录页组件保持不变
原登录页的表单已经指向/auth/microsoft,点击「Sign in」按钮会提交至该路由,触发微软认证流程,符合预期逻辑。
内容的提问来源于stack exchange,提问作者arunmmanoharan
相关产品推荐
相关产品推荐

