【问题标题】:Role based routes in next.js in ReactReact 中 next.js 中基于角色的路由
【发布时间】:2020-11-10 06:28:48
【问题描述】:

我对 React 很陌生,我有一个入门工具包,其中包含用于在 React 中进行身份验证的 next.js。 我想在用户访问管理员路由时限制对它们的访问。

我有两个角色,adminuser,成功登录后会存储在会话中。

页面文件夹内的 _app.jsx 如下所示。

    /**
 * Custom Next.js App
 *
 * @see https://nextjs.org/docs#custom-app
 */

import React from 'react'
import Head from 'next/head'
import { NextAuth } from 'next-auth/client'
import withRedux from 'next-redux-wrapper'
import NextSeo from 'next-seo'
import App, { Container as NextContainer } from 'next/app'
import { Provider as ReduxProvider } from 'react-redux'
import { Favicon, GTMScript, WebFonts } from '../components/head'
import { AuthUserProvider } from '../contexts/AuthUserContext'
import makeSEO from '../lib/seo'
import makeStore from '../lib/store'
// Global CSS from SCSS (compiles to style.css in _document)
import '../styles/globals.scss'

class CustomApp extends App {
  static async getInitialProps({ Component, ctx }) {
    let pageProps = {}

    ctx.session = await NextAuth.init({ req: ctx.req })

    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx)
    }

    return {
      pageProps,
      seo: makeSEO(ctx.req),
      session: ctx.session,
    }
  }

  componentDidMount() {
    // picturefill for <picture> and srcset support in older browsers
    // eslint-disable-next-line global-require
    if (process.browser) require('picturefill')
  }

  render() {
    const { Component, pageProps, seo, session, store } = this.props

    return (
      <NextContainer>
        {
          // to keep <Head/> items de-duped we should use next/head in _app.jsx
          // @see https://github.com/zeit/next.js/issues/6919
        }
        <Head>
          <meta
            name="viewport"
            content="width=device-width, initial-scale=1, minimal-ui"
          />
          <WebFonts />
          <Favicon />
          <GTMScript />
        </Head>
        <ReduxProvider store={store}>
          <AuthUserProvider session={session}>
            <NextSeo config={seo} />
            <Component {...pageProps} />
          </AuthUserProvider>
        </ReduxProvider>
      </NextContainer>
    )
  }
}

export default withRedux(makeStore)(CustomApp)

任何人都可以指导我如何使路线按角色可访问吗?

【问题讨论】:

    标签: reactjs next.js


    【解决方案1】:

    我能够获得使用 next-auth 和 useSession 的角色。希望这对您也有帮助。

    models/index.js

    import User, { UserSchema } from "./User"
    
    export default {
      User: {
        model: User,
        schema: UserSchema
      }
    }
    

    models/User.js

    import Adapters from "next-auth/adapters"
    
    // Extend the built-in models using class inheritance
    export default class User extends Adapters.TypeORM.Models.User.model {
      constructor(name, email, image, emailVerified, roles) {
        super(name, email, image, emailVerified)
        if (roles) { this.roles = roles}
      }
    }
    
    export const UserSchema = {
      name: "User",
      target: User,
      columns: {
        ...Adapters.TypeORM.Models.User.schema.columns,
        roles: {
          type: "varchar",
          nullable: true
        },
      },
    }
    

    pages/api/auth/[...nextauth].js

    import NextAuth from 'next-auth'
    import Providers from 'next-auth/providers'
    import Adapters from 'next-auth/adapters'
    
    import Models from '../../../models'
    
    export default NextAuth({
      // @link https://next-auth.js.org/configuration/providers
      providers: [
        Providers.Google({
          clientId: process.env.GOOGLE_ID,
          clientSecret: process.env.GOOGLE_SECRET
        })
      ],
      // @link https://next-auth.js.org/tutorials/typeorm-custom-models
      adapter: Adapters.TypeORM.Adapter(
        process.env.DATABASE_URL,
        {
          models: {
            User: Models.User
          }
        }
      ),
      session: { jwt: true },
      callbacks: {
        async jwt(token, user, account, profile, isNewUser) {
          if (account?.accessToken) {
            token.accessToken = account.accessToken
          }
          if (user?.roles) {
            token.roles = user.roles
          }
          return token
        },
        async session(session, token) {
          if(token?.accessToken) {
            session.accessToken = token.accessToken
          }
          if (token?.roles) {
            session.user.roles = token.roles
          }
          return session
        }
      }
    });
    

    用法 - 在 JSX 中

    {!session &&  sessionLoading && <p>Loading...</p>}
    {!session && !sessionLoading && <p>Access Denied - Not logged in</p> }
    { session && !sessionLoading && !session.user?.roles?.includes("Verified") && <p>Access Denied - Unverified</p> }
    { session && !sessionLoading && session.user?.roles?.includes("Verified") && <>
      <p>Stuff for verified users</p>
      {session.user.roles && session.user.roles.includes("Admin") && <>
        <button id="doSomething">Admin Only</button>
      </>}
      <p>More stuff for verified users</p>
    </>}
    

    Github Thread

    【讨论】:

    • 嗨杰森,谢谢你的例子!抱歉,如果这是一个愚蠢的问题,但是您到底在哪里放置/找到了模型/User.js 和模型/index.js?似乎在 node_modules/next-auth/dist/adapters... 文件夹中破解不是正确的方法?谢谢!
    • 我在列出的路径中创建了每个文件。没有理由修改 node_modules 中的任何内容,我建议完全避免这种方法。请查看TypeORM Custom Models,因为我的示例改编自该教程。
    • @JasonReiche,为什么需要数据库 URL?没有任何数据库也可以做同样的事情吗?
    猜你喜欢
    • 2017-07-17
    • 1970-01-01
    • 1970-01-01
    • 2016-06-12
    • 2012-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-20
    • 2015-06-13
    相关资源
    最近更新 更多