You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在SolidStart中实现客户端导航时的强制认证与重定向?

在SolidStart 1.1.0中实现可靠的路由认证重定向

问题背景

我用SolidStart 1.1.0构建项目,采用基于Cookie的会话认证方式。为校验用户登录状态,写了一个服务端查询函数getUser(),未认证时会抛出重定向到/Login的异常:

// server/auth.ts
export const getUser = query(async () => {
  "use server"
  const auth = await getAuthSession()
  if (!auth) throw redirect("/Login")
  return auth
}, "user")

在受保护路由(比如/dashboard)里,我用createAsync获取用户信息:

// routes/dashboard.tsx
import { getUser } from "~/server/auth"

export default function Dashboard() {
  const user = createAsync(() => getUser())

  return (
    <main>
      <h1>Welcome, {user()?.name}</h1>
    </main>
  )
}

遇到的问题:

  • 硬刷新或直接输入URL时正常,未认证会自动跳转到登录页
  • 客户端路由导航(比如点击页面内链接)时,SolidStart会复用getUser的缓存结果:
    • 不会重新执行query()函数
    • 不会触发throw redirect("/Login")
    • 页面加载后user()为null,但不会跳转

试过用createEffect或onMount手动检查并重定向,但有两个问题:

  • 没法区分user()为null是加载中还是未认证状态
  • 有时时序不对,已登录用户也会被误重定向

解决方案

方案1:禁用查询缓存,强制每次验证

修改getUser的查询配置,设置revalidate: 0或者cache: "no-store",让每次客户端导航都重新执行认证检查:

// server/auth.ts
export const getUser = query(async () => {
  "use server"
  const auth = await getAuthSession()
  if (!auth) throw redirect("/Login")
  return auth
}, { 
  key: "user",
  revalidate: 0, // 也可以用 cache: "no-store"
})

方案2:用路由加载器处理认证(推荐)

SolidStart的路由加载器(routeData)会在服务端渲染和客户端导航时都执行,是更可靠的方式:

// routes/dashboard.tsx
import { getUser } from "~/server/auth"
import { createRouteData } from "solid-start"

// 路由加载器,组件渲染前先执行认证检查
export const routeData = () => {
  return createRouteData(async () => {
    return await getUser()
  })
}

export default function Dashboard() {
  const user = routeData()

  return (
    <main>
      <h1>Welcome, {user()?.name}</h1>
    </main>
  )
}

只要getUser抛出重定向,SolidStart会自动处理跳转,不会出现缓存导致的失效问题。

方案3:手动管理缓存与状态区分

如果需要保留缓存,可以在客户端导航时手动失效缓存,同时区分加载状态:

// routes/dashboard.tsx
import { getUser } from "~/server/auth"
import { createAsync, useNavigate, useLocation } from "solid-start"
import { invalidateQuery } from "@solidjs/router"

export default function Dashboard() {
  const navigate = useNavigate()
  const location = useLocation()
  const user = createAsync(() => getUser())

  // 客户端路由变化时,失效用户查询缓存
  createEffect(() => {
    location.pathname
    invalidateQuery("user")
  })

  // 仅在加载完成且用户为null时重定向
  createEffect(() => {
    const currentUser = user()
    if (!user.loading && currentUser === null) {
      navigate("/Login")
    }
  })

  // 加载状态提示
  if (user.loading) {
    return <div>Loading...</div>
  }

  return (
    <main>
      <h1>Welcome, {user()?.name}</h1>
    </main>
  )
}

内容的提问来源于stack exchange,提问作者thePooyan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 16:45:56