如何在 Next.js next-auth 中保护路由?

How to protect routes in Next.js next-auth?

我正在尝试将身份验证与应用程序中的 next-auth 库集成。我一直在关注这里给出的官方教程 https://github.com/nextauthjs/next-auth-example/。给定示例的问题是我需要检查是否每个页面上都有一个会话需要这样的身份验证。

    import { useState, useEffect } from 'react';
    import { useSession } from 'next-auth/client'
    
    export default function Page () {
      const [ session, loading ] = useSession()
      
      // Fetch content from protected route
      useEffect(()=>{
        const fetchData = async () => {
          const res = await fetch('/api/examples/protected')
          const json = await res.json()
        }
        fetchData()
      },[session])
    
      // When rendering client side don't display anything until loading is complete
      if (typeof window !== 'undefined' && loading) return null
    
      // If no session exists, display access denied message
      if (!session) { return  <Layout><AccessDenied/></Layout> }
    
      // If session exists, display content
      return (
        <Layout>
          <h1>Protected Page</h1>
          <p><strong>{content || "\u00a0"}</strong></p>
        </Layout>
      )
    }

或像这样用于服务器端检查

    import { useSession, getSession } from 'next-auth/client'
    import Layout from '../components/layout'
    
    export default function Page () {
      // As this page uses Server Side Rendering, the `session` will be already
      // populated on render without needing to go through a loading stage.
      // This is possible because of the shared context configured in `_app.js` that
      // is used by `useSession()`.
      const [ session, loading ] = useSession()
    
      return (
        <Layout>
          <h1>Server Side Rendering</h1>
          <p>
            This page uses the universal <strong>getSession()</strong> method in <strong>getServerSideProps()</strong>.
          </p>
          <p>
            Using <strong>getSession()</strong> in <strong>getServerSideProps()</strong> is the recommended approach if you need to
            support Server Side Rendering with authentication.
          </p>
          <p>
            The advantage of Server Side Rendering is this page does not require client side JavaScript.
          </p>
          <p>
            The disadvantage of Server Side Rendering is that this page is slower to render.
          </p>
        </Layout>
      )
    }
    
    // Export the `session` prop to use sessions with Server Side Rendering
    export async function getServerSideProps(context) {
      return {
        props: {
          session: await getSession(context)
        }
      }
    }

这很让人头疼,因为我们需要在每个需要身份验证的页面上手动正确,是否有任何方法可以全局检查给定路由是否受保护,如果没有登录则重定向,而不是将其写入每页?

是的,您需要检查每个页面并且您的逻辑没问题(显示微调器直到身份验证状态可用)但是,您可以提升 身份验证状态,因此您不需要'为每个页面重复 auth 代码, _app 组件是一个完美的地方,因为它自然地包装了所有其他组件(页面)。

      <AuthProvider>
        {/* if requireAuth property is present - protect the page */}
        {Component.requireAuth ? (
          <AuthGuard>
            <Component {...pageProps} />
          </AuthGuard>
        ) : (
          // public page
          <Component {...pageProps} />
        )}
      </AuthProvider>

AuthProvider 组件包装用于设置第三方提供商(Firebase、AWS Cognito、Next-Auth)的逻辑

AuthGuard 是放置 身份验证检查逻辑 的组件。您会注意到 AuthGuard 包装了 Component(这是 Next.js 框架中的实际 page)。所以 AuthGuard 将在查询 auth 提供程序时显示 loading 指示符,如果 auth 为真,它将显示 Component 如果 auth 为假,它可以显示登录弹出窗口或重定向到登录页面。

关于 Component.requireAuth 这是一个方便的 属性 设置在每个页面上以将 Component 标记为需要身份验证,如果该属性为假 AuthGuard 则永远不会渲染。

我已经更详细地介绍了这种模式:Protecting static pages in Next.js application

而且我还做了一个example demo app (source)