programing

Next.js에서의 인증 구현 방법

stoneblock 2023. 3. 20. 21:23

Next.js에서의 인증 구현 방법

Next.js는 처음이라 jwt 토큰을 사용한 인증시스템에 어려움을 겪고 있습니다.인증시스템에서 jwt 토큰과 루팅을 저장하는 가장 좋은/표준적인 방법을 알고 싶습니다.튜토리얼/기사마다 다른 접근 방식을 시도했지만 잘 이해하지 못했습니다.이게 내가 시도한 것이다.

  1. 사용자가 로그인하면 사용자 이름/비밀번호가 분리된 API 서버(예를 들어 백엔드 작업을 처리하는 새 프로젝트)로 전송됩니다.서버는access-tokenNext.js next next next next next 。Next는 Next.js로 .withAuth임시: hoc키키내내 hoc hoc hoc hoc hoc hoc hoc hoc hoc hoc hoc hoc hoc.이 접근법의 문제는 쿠키에 httpOnly 플래그가 없기 때문에 XSS에 취약하다는 것입니다.

  2. , 「1」을 합니다.localStorage는, 「」입니다access-token요구로 할 수 에서는, 의 HTTP 요구를 가 있습니다.) (HTTP 요구access-token 사용: 첫 번째 요청 사용:<a>tag을 합니다.

  3. Next.js 서버(커스텀 익스프레스 서버)에 인증 백엔드를 작성했습니다.사용자가 로그인하면 서버는 이를 검증하고 httpOnly cookie를 설정합니다.문제는 클라이언트 측 라우팅(Next.js Router를 사용하여 URL로 이동)에서는 토큰을 확인할 수 없다는 것입니다.예를 들어, 페이지가 다음과 같이 감겨진 경우withAuth 단, javascript.javascript를 하여 쿠키 수 .

나는 많은 리리고 and and and and and and and and and and and and and and and and and and and and and.getInitialPropscookie/local Storage /서///// 。 그러면 토큰이 취소되거나 블랙리스트에 올라갔을 때 서버에 토큰을 보내지 않았기 때문에 어떻게 처리합니까?아니면 클라이언트 측 페이지를 변경할 때마다 토큰을 서버로 보내야 합니까?

우리는 격리 중이기 때문에 나는 이 질문에 대답할 충분한 시간이 있다.긴 답변이 될 것이다.

Next.js는 App 컴포넌트를 사용하여 페이지를 초기화합니다._app 페이지는 당사의 페이지를 렌더링하는 역할을 합니다.getInitialProps에서 반환되는 모든 것은 다른 모든 페이지에서 액세스할 수 있기 때문에 _app.js에서 사용자를 인증합니다.여기서 사용자를 인증합니다.인증 결정은 페이지마다 페이지마다 전달됩니다.이것에 의해, 각 페이지는 유저의 인증 여부를 판단할 수 있습니다.(프롭의 드릴링 없이 redx를 사용해 실시할 수 있습니다만, 답변이 복잡해집니다.)

  static async getInitialProps({ Component, router, ctx }) {
    let pageProps = {};
    const user = process.browser
      ? await auth0.clientAuth()
      : await auth0.serverAuth(ctx.req); // I explain down below

    //this will be sent to all the components
    const auth = { user, isAuthenticated: !!user };
    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
    }

    return { pageProps, auth };
  }

  render() {
    const { Component, pageProps, auth } = this.props;
    return <Component {...pageProps} auth={auth} />;
  }
}

브라우저 상에서 사용자가 인증되었는지 확인해야 하는 경우 브라우저에서 쿠키를 가져오기만 하면 됩니다.그것은 간단합니다.하지만 우리는 항상 토큰을 확인해야 합니다.이는 브라우저와 서버에서 사용하는 프로세스와 동일합니다.아래에 설명하겠습니다.하지만 서버에 접속되어 있다면.브라우저에서 쿠키에 액세스할 수 없습니다.그러나 cookie는 req.header.cookie에 연결되어 있기 때문에 req 객체에서 읽을 수 있습니다.이것이 서버상의 쿠키에 접속하는 방법입니다.

async serverAuth(req) {
    // console.log(req.headers.cookie) to check
    if (req.headers.cookie) {
      const token = getCookieFromReq(req, "jwt");
      const verifiedToken = await this.verifyToken(token);
      return verifiedToken;
    }
    return undefined;
  }

여기 getCookieFromReq()가 있습니다.기능적으로 생각해야 합니다.

const getCookieFromReq = (req, cookieKey) => {
  const cookie = req.headers.cookie
    .split(";")
    .find((c) => c.trim().startsWith(`${cookieKey}=`));

  if (!cookie) return undefined;
  return cookie.split("=")[1];
};

쿠키를 얻으면 디코딩하고 유효기간을 추출하여 유효 여부를 확인해야 합니다.이 부분은 쉬워요.또 하나 확인해야 할 것은 jwt의 서명이 유효한지 여부입니다.대칭 알고리즘 또는 비대칭 알고리즘은 jwt에 서명하기 위해 사용됩니다.대칭 알고리즘의 서명을 검증하려면 개인 키를 사용해야 합니다.RS256은 API의 기본 비대칭 알고리즘입니다.RS256을 사용하는 서버는 jwt를 사용하여 시그니처를 검증하기 위한 링크를 제공합니다.[jwks-rsa][1]을 사용하거나 사용자가 직접 수행할 수 있습니다.인증서를 생성한 다음 토큰이 유효한지 확인해야 합니다.

사용자가 인증되었다고 가정합니다."그리고 보호된 루트의 getInitialProps에서는 cookie/localStorage에서 존재 토큰만 확인합니다."라고 말했습니다.보호된 경로를 사용하여 인증된 사용자에게만 액세스를 제공합니다.이러한 루트에 액세스하려면 사용자는 jwt 토큰을 표시해야 하며 express.js는 미들웨어를 사용하여 사용자의 토큰이 유효한지 확인합니다.예시를 많이 보셨기 때문에 이 부분은 생략하겠습니다.

"그럼 토큰이 취소되거나 블랙리스트에 올라간 경우 어떻게 처리합니까? 서버에 토큰을 보내지 않았기 때문에 어떻게 처리합니까?아니면 클라이언트 측 페이지가 변경될 때마다 토큰을 서버로 보내야 합니까?

토큰 프로세스를 확인함으로써 토큰이 유효한지 여부를 100% 확신할 수 있습니다.클라이언트가 서버에 비밀 데이터에 액세스하도록 요구하면 클라이언트는 서버에 토큰을 전송해야 합니다.컴포넌트를 마운트하면 컴포넌트가 보호된 경로에서 데이터를 가져오도록 서버에 요구합니다.서버는 req 객체를 추출하고 jwt를 사용하여 보호된 경로에서 데이터를 가져옵니다.브라우저와 서버의 데이터 가져오기 구현이 다릅니다.브라우저가 요청을 하면 상대 경로만 필요한데 서버는 절대 경로만 필요합니다.아시다시피 컴포넌트의 getInitialProps() 데이터를 가져오고 이 함수는 클라이언트와 서버 모두에서 실행됩니다.구현 방법은 다음과 같습니다.방금 getInitialProps() 부분을 첨부했습니다.

MyComponent.getInitialProps = async (ctx) => {
  const another = await getSecretData(ctx.req);
 //reuslt of fetching data is passed to component as props
  return { superValue: another };
};



    const getCookieFromReq = (req, cookieKey) => {
      const cookie = req.headers.cookie
        .split(";")
        .find((c) => c.trim().startsWith(`${cookieKey}=`));

      if (!cookie) return undefined;
      return cookie.split("=")[1];
    };

   
    const setAuthHeader = (req) => {
      const token = req ? getCookieFromReq(req, "jwt") : Cookies.getJSON("jwt");

      if (token) {
        return {
          headers: { authorization: `Bearer ${token}` },
        };
      }
      return undefined;
    };

    
    export const getSecretData = async (req) => {
      const url = req ? "http://localhost:3000/api/v1/secret" : "/api/v1/secret";
      return await axios.get(url, setAuthHeader(req)).then((res) => res.data);
    };



  [1]: https://www.npmjs.com/package/jwks-rsa

Next의 소개와 함께.JS v8, NextJs 예제 페이지에 예제가 있습니다.따라야 할 기본 개념은 다음과 같습니다.

JWT

  • 쿠키를 사용하여 토큰 저장(추가 암호화 여부를 선택할 수 있음)
  • 쿠키를 인증 헤더로 보내기

OAuth

  • OAuth2.0 등의 서드파티 인증 서비스 사용
  • 여권 사용

이 질문에는 갱신된 답변이 필요할 수 있습니다.Next.js 12 ( 2021년 10월)에 미들웨어가 있습니다.https://nextjs.org/docs/middleware

Next.js에서의 인증에 대해 좀 더 자세히 설명하기 위해 포괄적인 답변 초안을 작성하고 있으니 GitHub에서 진행상황을 따라가시면 됩니다.

여기에서는 미들웨어를 사용하여 Next.js의 요약을 제안합니다.

인증 후 토큰 확인 및 그에 따라 리다이렉트

2020년 4월 @일마즈.'우리'를 .getInitialProps_app요청을 처리하거나 커스텀서버를 선택합니다.

더 이상 그렇지 않습니다.미들웨어를 사용하면 더 깔끔한 코드로 동일한 목적을 달성할 수 있습니다.미들웨어는 이러한 사용 사례에 맞게 특별히 설계되어 있기 때문입니다.

여기에서는 RS256과 같은 비대칭 알고리즘을 사용하여 JWT 액세스 토큰을 얻을 수 있습니다.앞의 답변과 동일합니다.

가능한 실장은 다음과 같습니다.

import { NextFetchEvent, NextRequest, NextResponse } from "next/server";

const removeCookie = (res: NextResponse, cookieName: string) => {
  res.headers.append("Set-Cookie", `${cookieName}=; Max-Age=-1; Path=/`);
  return res;
};

export default async function middleware(
  req: NextRequest,
  ev: NextFetchEvent
) {
  const { pathname } = req.nextUrl;
  const isPublic = isPublicRoute(pathname);

  if (isPublic) {
    return NextResponse.next();
  }

  const accessToken = req.cookies[TOKEN_PATH];
  if (!accessToken) {
    return NextResponse.redirect(LOGIN_HREF);
  }

  const isValidToken = await checkAccessToken(accessToken);

  if (!isValidToken) {
    let res = NextResponse.redirect(LOGIN_HREF);
    res = removeCookie(res, TOKEN_PATH);
    return res;
  }

  return NextResponse.next();
}

토큰 확인 방법

예에서는, 「 」가 됩니다.checkAccessToken는 토큰을 확인해야 합니다(디코딩이 아닌 시그니처를 확인합니다).

여기가 가장 복잡한 지점이야

RSA256 알고리즘을 사용하는 경우

또, PUBLIC 증명서도 취득할 수 있습니다(SECRET 키와 함께 취득할 필요가 있습니다).을 사용법 event the the the in in in event event에서 체크할 수 있다.middleware이것은 개인 코드이며 서버 전용 코드입니다.이것은 이론적으로는 브라우저에서도 사용할 수 있다는 것을 의미하기 때문에 좋은 소식입니다.

이렇게 하면 '어느 쪽인가', '어느 쪽인가', ' 쪽인가'fetch인증 서버에서 제공하는 토큰 검증 엔드포인트 또는 토큰을 직접 확인합니다.설명서에 따르면 가져오기는 Vercel/Next Edge 기능을 중단하고 지연 시간을 추가할 수 있으므로 권장되지 않습니다.

Next.js:)를 사용하여 토큰을 아직 검증하지 못한 것을 인정해야 합니다.코드 샘플이 정상적으로 동작할 수 있게 되면 이 답변을 갱신하겠습니다.

대칭 암호화를 사용하는 경우

PRIVATE 비밀 암호만 가지고 있습니다.즉, 디코딩은 서버 측에서 이루어져야 합니다(좋은 소식은 미들웨어를 쓰고 있다는 것입니다).

로그인/로그아웃

이것은 미들웨어에서도 변하지 않습니다.은 「접속 토큰」으로합니다.httpOnly를 클릭합니다로그아웃 시 이 쿠키를 설정 해제했습니다.

이러한 Set-Cookies 헤더의 관리는 인증 서버의 책임입니다.

이것은 기본 워크플로우이지만 작동해야 합니다.그런 다음 유사한 방법으로 혼합에 새로 고침 토큰을 추가할 수 있습니다.

토큰 취소 정보

  • 미들웨어에서 토큰을 확인할 경우 액세스 토큰에 대한 즉각적인 취소 메커니즘은 없습니다.데이터베이스에 대한 호출이 없기 때문입니다.

따라서 이 시나리오에서는 리프레시 토큰과 함께 짧은 기간(5분 등)의 액세스 토큰을 선택할 수 있습니다.새로 고침 토큰을 해지할 수 있으므로 기본적으로 취소는 작동하지만 몇 분 정도 걸립니다.

  • 서드파티 서버가 토큰을 확인하는 경우: 블랙리스트에 있는 토큰을 확인할 수 있습니다.

주의사항

또, 온라인상의 기사나 튜토리얼등의 대부분은, 서버간의 통신에 초점을 맞추고 있습니다.또는 클라이언트-to-API.웹 페이지에 액세스하기 전에 인증을 확인하는 것은 완전히 최악입니다.

를 들어,하다, 설정하다, 하다.Authorization브라우저에서는 헤더를 사용할 수 없습니다.API를 사용합니다.웹 페이지의 경우 쿠키는 필수입니다.

그래도 이 API가 브라우저에서 호출되는 경우 쿠키를 받아들이는 것이 좋습니다.

현장 전문가와 논의할 때는 항상 Next.js 사용 사례를 명확히 해야 합니다.

개방형 질문: 세션 기반 인증에 대해

일부 프레임워크는 데이터베이스에 의존하는 것을 선호하는 것 같습니다.해시된 토큰은 세션 역할을 하는 DB에 저장됩니다.auth를 확인하려면 저장된 토큰에 대해 사용자의 토큰을 확인할 서버가 필요합니다(= 이 토큰으로 활성 세션이 있는지 확인).

나는 예를 들어 Meteor를 생각하고 있다.

그러나 이 메커니즘의 이름과 JWT와의 실제 관계를 찾을 수 없었습니다.JWT 접근법의 단순한 변형인가?

Next.js 공식 인증 문서는 작성 시 미들웨어를 표시하지 않고 대신 을 사용합니다.getServerSideProps네, 네, 네.일종의 세션 시스템을 사용하고 있습니다만, 그 내부는 불명확합니다.이름조차 확실하지 않습니다(세션 기반 인증입니까?).

Vercel 엣지 핸들 예는 API 루트를 보호하는 방법을 나타내고 있지만 페이지(쓰기 시)는 표시하지 않습니다.

언급URL : https://stackoverflow.com/questions/49920234/how-to-implement-authentication-in-next-js