Next.js Discord

Discord Forum

protect route, check privileges

Unanswered
Golden-crowned Warbler posted this in #help-forum
Open in Discord
Golden-crowned WarblerOP
Check privilege, protect route

So I use next js as front and node express as back, and I have this privileges save in the context when login, example in app router folder: src/app/items/-> in this I have page.tsx for listing records, folder create/page.tsx for create the item, and I want to check the privileges when access to these pages (hard input url/button create click), and when no permission, I want to use toast to show message “permission denied”,
How should I do it? I don’t want to write codes to check it on every page, I want to put it in one file,

8 Replies

Is the action being taken on the express side or the nextjs side?
Oh you want to check authentication on navigation, I would use middleware to do that.
Golden-crowned WarblerOP
How do I do it ? I also use next intl, in middleware
Golden-crowned WarblerOP
Try to check on client side like this but it’s bad:

'use client'
import { usePathname } from '@/hooks/navigation'
import { useRouter } from '@/hooks/navigation'
import useSession from '@/session/useSession'
import { useParams } from 'next/navigation'
import { useEffect } from 'react'

const ProtectedRoute = ({ children }: any) => {
const pathname = usePathname()
const {id} = useParams()
const { session } = useSession()
const router = useRouter()
let hasPermission = false
const privileges = session.role.privileges.map((privilege: any) => privilege.module)
useEffect(() => {
switch (pathname) {
case '/announcements':
hasPermission = privileges.includes('notification-list')
break
case '/announcements/create':
hasPermission = privileges.includes('notification-create')
break
case /announcements/${id}/edit:
hasPermission = privileges.includes('notification-create')
break
default:
hasPermission = true
break
}
const back = id ? pathname.split('/').slice(0, -2).join('/') : pathname.split('/').slice(0, -1).join('/')
if (!hasPermission) router.push(back)
}, [pathname])
return #Unknown Channel{children}</>
}

export default ProtectedRoute
Golden-crowned WarblerOP
Here I try with middleware but redirect did not work;

import { NextRequest, NextResponse } from 'next/server';

export async function checkPrivilegeMiddleware(req: NextRequest) {
try {
const token = req.cookies.get(process.env.COOKIE_NAME as string)
const baseUrl = req.nextUrl.origin
const pathname = req.nextUrl.pathname
const id = Number(pathname.split('/').slice(0, -1).pop())
const response = await fetch(${process.env.BASE_URL}/admin/accounts, {
headers: {
'Authorization': Bearer ${token?.value},
},
});
const { data } = await response.json()
const privileges = data.role.privileges.map((privilege: any) => privilege.module)

let hasPermission = false
switch (pathname) {
case '/announcements':
hasPermission = privileges.includes('notification-list')
break
case '/announcements/create':
hasPermission = privileges.includes('notification-create')
break
case /announcements/${id}/edit:
hasPermission = privileges.includes('notification-create')
break
default:
hasPermission = true
break
}
const backUrl = new URL(baseUrl + pathname.split('/').slice(0, id ? -2 : -1).join('/'))

console.log(backUrl.href, hasPermission);
if (!hasPermission) return NextResponse.redirect(backUrl);
return NextResponse.next()
} catch (err) {
console.log(err);
}
}
import createIntlMiddleware from 'next-intl/middleware';
import { checkPrivilegeMiddleware } from './checkPrivilege';
import { NextRequest } from 'next/server';

const intlMiddleware = createIntlMiddleware({
locales: ['en', 'ja'],
defaultLocale: 'en',
localePrefix: "as-needed"
});

export default async function middleware(req: NextRequest) {

await checkPrivilegeMiddleware(req);

return intlMiddleware(req);
}

export const config = {
matcher: ['/((?!api|_next|.\..).*)'],
};
Golden-crowned WarblerOP
@Jboncz
@Siberian