HOWTO: 在 Next.js 中实现服务端鉴权

Travis2024/01/01
621 字, 阅读需要 4 分钟
代码仓库

最近在写自己的练手项目,其中不可避免的遇到了授权、鉴权的问题。方式有以下两种:

  1. 直接在客户端这边调用鉴权接口,再根据结果触发重新渲染
  2. 在服务端调用鉴权接口,根据结果渲染界面

第一种方式很容易想到,但是不可避免的,在客户端调用鉴权接口,到接口返回信息,触发重新渲染的过程中,会给用户整个界面闪了一下的感觉。不太直观,对用户体验来说也不合适。

我们在这里采用第二种方式。在请求页面时,就携带上用户的认证信息(session),然后在服务端调用鉴权接口,如果鉴权通过,则渲染请求的页面;否则,就重定向到登录页面。

在 Next.js 中:

  • 在 13.0 版本之前的 Page Router 中,一直都有 getServerSideProps 函数,这一函数可用于在每一次页面请求时,生成一些 props 注入要返回的 page component 当中。即服务端渲染。
  • 在 13.0 版本以来的 App Router 当中,新加入了 Server Action1。即定义一些只在服务端使用的函数,在服务端组件中可以随意调用。

接下来我的代码将使用 Next.js 14.0 的版本进行编写,服务端使用 Golang 的 http 包编写了基本的功能,即函数接口: /api/login/api/logout/api/islogin

  1. 实现 Server Action,将页面请求中的 cookie 携带着进行鉴权,这里 http.StatusOK 则代表已登录,否则未登录。最后则可以返回一个 Promise,以供进一步的判断回调。
frontend/src/lib/auth.ts
export async function isLogin(): Promise<boolean> {
  console.log("check login");
  console.log(cookies().toString());

  const hasLogin = await fetch("http://localhost:8080/api/islogin", {
    cache: "no-store",
    headers: {
      Cookie: cookies().toString(),
    },
  }).then((res) => {
    return res.status === 200;
  });
  return hasLogin;
}
  1. 在页面中添加鉴权调用,如果没有登录,则重定向到登录页面。如果读者跑了这个 demo 应当可以看到,未登录的用户即使最开始访问的是 http://localhost:8080/ 这个路径,也会被直接导向 /login 路径进行登录。
警告

这里一定要记得添加 awaitasync

2023/authentication_serverside/frontend/src/app/page.tsx
export default async function Home() {
  await isLogin().then((res: boolean) => {
    if (!res) {
      redirect("/login");
    }
  });

  return (
    <main >
      <>
        You has logged in
        <div>
          <Logout />
        </div>
      </>
    </main>
  );
}

脚注

  1. Server Actions and Mutations

© LICENSED UNDER CC BY-NC-SA 4.0