reactjs - React 中 next.js 中基于角色的路由
问题描述
我对 React 很陌生,我有一个入门工具包,其中包含用于在 React 中进行身份验证的 next.js。当用户访问它们时,我想限制对管理路由的访问。
我有两个角色,admin
和user
,成功登录后存储在会话中。
pages 文件夹内的 _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)
任何人都可以指导我该怎么做才能使路线按角色可访问吗?
解决方案
我能够获得使用 next-auth 和useSession的角色。希望这对您也有帮助。
模型/index.js
import User, { UserSchema } from "./User"
export default {
User: {
model: User,
schema: UserSchema
}
}
模型/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>
</>}
推荐阅读
- java - 从字符串数组对象中检索每个键值
- android - 我可以使用 kotlin 删除文件而不复制到内部存储上的 ../recycle_bin 文件夹吗
- javascript - 当函数导出到不同的 JS 文件时,函数打印两次的结果
- xamarin - Xamarin Datapicker 如何将其自定义为日历图像
- javascript - 单击浏览器中的后退按钮时如何防止导航返回?
- javascript - 有没有办法在 react-js 中扩展另一个类而不是 Component 类
- c++ - 为什么“if”不在循环中执行?
- php - 如何修复水平的导航栏在WordPress中应该是垂直的?
- c++ - wxWindows 2.4.2 配置失败说检查工具包...配置:错误:请最多指定一个工具包
- python - Flask JWT:没有 @jwt_required 的 get_jwt_identity() 总是返回 Non