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

Posted

技术标签:

【中文标题】如何保护 Next.js next-auth 中的路由?【英文标题】:How to protect routes in Next.js next-auth? 【发布时间】:2021-08-06 04:16:42 【问题描述】:

我正在尝试将身份验证与应用程序中的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)
        
      
    

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

【问题讨论】:

【参考方案1】:

是的,您需要检查每个页面并且您的逻辑没问题(显示微调器直到身份验证状态可用)但是,您可以提升身份验证状态,因此您不要重复 @ 987654323@每一页的代码, _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 是您放置 auth 检查逻辑 的组件。您会注意到AuthGuard 正在包装Component(这是Next.js 框架中的实际页面)。因此AuthGuard 将在查询身份验证提供程序时显示 loading 指示符,如果 auth 为 true,它将显示 Component 如果 auth 为 false,它可能会显示登录弹出窗口或重定向到登录页面。

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

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

我还发了一个example demo app (source)

【讨论】:

只想说,这个答案太棒了,正是我长期以来一直在寻找的。谢谢@Ivan! @J.Jackson 谢谢!请务必查看我正在更新的存储库代码。 是的,这正是我一直在寻找的!致力于删除一些硬编码的 auth.ts 内容并修复我看到的一些 TS 严格错误。 使用 Component.requireAuth 和使用 get staticProps 函数有什么区别? @Kay requireAuth 确定是否应检查组件(页面)auth

以上是关于如何保护 Next.js next-auth 中的路由?的主要内容,如果未能解决你的问题,请参考以下文章

Next.js/Next-Auth/Apollo/GraphQL 设置

使用 Next-Auth 进行身份验证时如何修复内部服务器错误

next-auth 中 useSession() 的“加载”返回值是啥?

为啥切换语言环境时我的会话没有加载?

如何使用具有永恒 API 的 Next-auth 凭证提供程序

Next js:next auth provider + redux provider