缺少httpOnly cookie时如何用React HOC实现受保护页面的服务端重定向
可行方案整理
方案1:使用Next.js Middleware(最优解,不破坏静态优化)
Next.js 12及以上版本提供的Middleware能力可以完美匹配你的需求:
- 运行在服务端Edge节点,在请求到达你的页面资源(不管是静态优化页还是SSR页)之前就执行
- 支持直接读取请求携带的httpOnly Cookie,不需要在客户端执行任何逻辑
- 完全不会影响应用的自动静态优化能力,静态生成的页面依然可以保留所有性能优势
- 只需要编写一次逻辑,全局生效,不需要修改任何页面代码
你可以在项目根目录(或src目录下)新建middleware.ts文件,示例代码如下:
import { NextResponse } from 'next/server' import type { NextRequest } from 'next/server' // 定义需要鉴权的路由前缀,可根据实际需求调整 const PROTECTED_ROUTES = ['/dashboard', '/user', '/settings'] export function middleware(request: NextRequest) { const { pathname } = request.nextUrl // 校验当前请求路径是否属于受保护路由 const isProtectedRoute = PROTECTED_ROUTES.some(route => pathname.startsWith(route)) if (isProtectedRoute) { // 读取你用于鉴权的refresh token的cookie,替换成你实际的cookie名 const refreshToken = request.cookies.get('refresh_token')?.value if (!refreshToken) { // 未携带有效鉴权cookie,直接在服务端重定向到登录页 return NextResponse.redirect(new URL('/auth/login', request.url)) } // 如果你需要严格校验token有效性,也可以在这里调用你的/api/user接口校验,校验不通过同样重定向 } return NextResponse.next() }
你原来写的客户端withAuth HOC可以保留作为二次校验,避免极端场景下绕过中间件的情况。
方案2:App Router 路由组+全局Layout(如果你使用Next.js 13+ App Router)
如果你已经切换到App Router模式,可以把所有受保护的页面放在同一个路由组下,比如(protected),然后在路由组的layout.tsx中编写一次服务端鉴权逻辑即可,所有子页面都会继承这个逻辑,不需要单独编写:
// app/(protected)/layout.tsx import { cookies } from 'next/headers' import { redirect } from 'next/navigation' export default function ProtectedLayout({ children, }: { children: React.ReactNode }) { const refreshToken = cookies().get('refresh_token')?.value if (!refreshToken) { redirect('/auth/login') } return <>{children}</> }
方案3:封装通用getServerSideProps高阶函数
如果你确实需要使用getServerSideProps的能力,可以封装一个通用的高阶函数,避免每个页面重复编写逻辑:
import type { GetServerSideProps, GetServerSidePropsContext } from 'next' export function withAuthSSP<T extends { [key: string]: any }>( getServerSideProps?: GetServerSideProps<T> ): GetServerSideProps<T> { return async (ctx: GetServerSidePropsContext) => { const refreshToken = ctx.req.cookies.refresh_token if (!refreshToken) { return { redirect: { destination: '/auth/login', permanent: false, }, } } // 如果页面有自定义的getServerSideProps逻辑就执行,否则返回空props if (getServerSideProps) { return getServerSideProps(ctx) } return { props: {} as T } } }
使用时只需要在受保护页面导出包装后的方法即可:
// 页面不需要写任何鉴权逻辑,直接导出包装后的getServerSideProps export const getServerSideProps = withAuthSSP()
内容的提问来源于stack exchange,提问作者Amin Abdolrezapoor
相关产品推荐
相关产品推荐

