안녕하세요

Middleware로 권한이 없는 유저 "/"로 redirect 시키기 본문

Next13 블로그 프로젝트

Middleware로 권한이 없는 유저 "/"로 redirect 시키기

sakuraop 2023. 9. 15. 11:01

Next.js 미들웨어(middleware)

목차

1. 미들웨어란

2. Next.js 에서 middleware 사용하는 법

  • middleware 세팅
  • NextResponse란

3. middleware가 적용될 경로 설정하기


react + express로 서버를 구현했을 때도 유저가 로그인했는지 정보를 확인하기 위해 middleware를 사용했듯

Next.js에서는 middleware를 어떻게 사용하는지 찾아보았다.

1. 미들웨어(middleware)란

특정 경로의 페이지로 접근할 때 또는 특정 api 를 실행하기 전 "이 함수를 실행"하는 역할을 한다.

인증이 되지 않은(비로그인) 유저가

  • url 주소를 통해 게시글 작성 페이지로 접근하려 할 때 (/manage/newpost)
  • 회원 정보 수정 페이지로 접근하려 할 때 (/user/abcd1234)

/manage경로 또는 /user 의 하위 경로를 접근하지 못하도록 할 수 있다.

 

이제부터 "로그인이 된 유저인지 아닌지"를 확인하는 미들웨어를 생성해보자.

 

2. Next.js에서는 middleware 사용하는 법

https://nextjs.org/docs/pages/building-your-application/routing/middleware

공식 문서 제일 위를 보면

Convention

Use the file middleware.ts (or .js) in the root of your project to define Middleware. For example, at the same level as pages or app, or inside src if applicable.

 

1) src 폴더와 동일한 레벨에 middleware.ts 파일을 생성한다.

 

2) 다음으로 아래와 같이 파일을 세팅합니다.

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
 
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
  return NextResponse.redirect(new URL('/home', request.url))
}
 
// See "Matching Paths" below to learn more
export const config = {
  matcher: '/about/:path*',
}

3) NextResponse란

  • NextResponse를 반환하고 있습니다. 이는 미들웨어를 실행한 뒤 다음으로 무엇을 할지 결정하는 역할입니다.
  • NextResponse의 다음 세가지 속성을 기억하면 됩니다.

  • next(): 다음 함수를 실행
  • redirect(): 다른 경로로 이동을 하는데, url을 변경한다.
  • rewrite(): 다른 경로로 이동을 하는데, url을 변경하지 않고 원하는 url을 덮어씌운다.

코드로 보면 다음과 같습니다.

if (비로그인 유저라면) {
  return NextResponse.redirect('/')
}
// (문제 없으니)
return  NextResponse.next()

🔻🔻🔻rewrite 더보기...

더보기

rewrite는 라우팅을 할 때 좀 더 세밀하게 설정을 할 수 있도록 도와줍니다.

 

redirect는 현재 프로젝트가 있는 도메인 내에서만 리다이렉팅을 할 수 있지만,

rewrite는 다음과 같이 다른 도메인으로 리다이렉팅이 가능합니다.

 

// next.config.js

module.exports = {
  async rewrites() {
    return [
      {
        source: '/old-path',
        destination: 'https://example.com/new-path',
      },
    ];
  },
};

3. middleware가 적용될 경로 설정하기

제 코드 예시입니다.

import { getToken } from "next-auth/jwt";
import { NextResponse } from "next/server";
import { NextRequest } from "next/server";
import { isBlogManager } from "./utils/sessionCheck/isBlogManager";
export { withAuth } from "next-auth/middleware";

export const middleware = async (request: NextRequest) => {
  // 1. '/manage'로 시작하는 경로에 접근 시
  if (request.nextUrl.pathname.startsWith("/manage")) {
    // 2. 토큰 정보 가져오기
    const token = await getToken({ req: request });

    // 3. token을 검사하여 접근해도 되는지 확인
    if (token === null || !isBlogManager(token.email as string)) {
      // 4. 접근 불가하면 '/'로 redirect
      return NextResponse.redirect(new URL("/", request.url));
    }
  }

  return NextResponse.next();
};

// middleware를 실행할 경로를 지정합니다.
export const config = {
  matcher: "/manage/:path*",
};

 

middleware를 적용하고 싶은 경로를 지정하려면

matcher: '/manage/:path*" 와 같이 할 수 있습니다.

 

/:path* 가 의미하는 것은 하위경로 모두입니다.

 

여러 경로에 적용을 하고 싶다면 다음과 같이 배열로 적용해주면 됩니다.

matcher: ['/manage', '/user', ' /auth']

 

그리고 조건문을 써서 경로별로 수행할 함수를 만들어 실행해주면 되겠습니다.

  if (request.nextUrl.pathname.startsWith("/manage")) {
    return tryAccessManage()
  }
  if (request.nextUrl.pathname.startsWith("/user")) {
    return tryAccessUser()
  }
  if (request.nextUrl.pathname.startsWith("/auth")) {
    return tryAccessAuth()
  }