[나만무] 06.17 TIL - Next.js 학습 by 코딩애플

2025. 6. 17. 14:07·크래프톤 정글/Equipped in 정글(나만무)

JWT, Session, 그리고 OAuth

유저가 로그인 시 서버는 DB에서 해당 유저의 아이디, 비밀번호가 맞는지 확인한 후 맞다면 입장권을 발급해준다. 이 입장권은 유저가 평소에는 보이지 않는 곳에 숨겨놓고, 유저가 어떤 기능을 요청할 때 해당 입장권을 서버에 제출해 권한이 있는지 검사한다.

 

입장권을 만드는 방식에는 session 방식, token 방식이 있다.

Session 방식

  • 유저 로그인 성공 시 발급하는 입장권에는 sesson id만 적혀 있다.
  • DB 혹은 서버 메모리에 상세 정보('아이디', '로그인날짜', '유효기간', 'session id' 등)가 저장된다.
  • 유저가 기능을 요청하며 입장권 제출 시, 서버 측에서 해당 session id로부터 정보를 비교해 유효성을 검증한다.
  • 유저의 GET/POST 요청마다 로그인 상태를 엄격하게 체크할 수 있다.
  • 다만 DB 부하가 심해진다.
    • 이를 개선하기 위해 입출력이 빠른 redis 같은 DB를 session id 보관 용도로 사용하기도 함.

token 방식

  • 보통 JWT를 의미한다.
  • 유저 로그인 성공 시 발급하는 입장권에는 상세 정보(민감 정보를 제외한 아이디, 로그인날짜, 유효기간 등)가 저장된다.
  • 다만 그대로 저장하지 않고, 암호화를 한 토큰 형태의 입장권을 유저에게 전달한다.
  • 유저가 기능을 요청하여 입장권 제출 시, 해당 암호화된 토큰을 까서 유효성을 검증한다.
  • 입장권 생성 시 암호화를 하기 때문에, 위변조 여부를 쉽게 검사할 수 있다.
  • DB를 조회할 필요가 없어, 유저가 많거나 마이크로서비스 운영 시 부담이 적다.
  • 다만 입장권을 위변조 하는 것이 아니라, 탈취 시 악용하는 것을 막기가 어렵다.

OAUTH

  • A 사이트의 로그인 정보를 통해 획득한 회원 정보, 사용 권한을 B 사이트가 대여하여 사용하는 것.
  • 이를 이용해 소셜 로그인, 회원가입 등을 수행할 수 있다.
  • 특정 사이트에서 소셜 로그인/회원가입을 시도하면 해당 소셜 사이트에 로그인한 뒤, 특정 사이트에 정보 이용을 허락하면 그 특정 사이트가 소셜 사이트의 유저 정보(이메일, 이름, access token 등)를 이용하게 된다.

Next.js에서 회원기능 구현은 전용 라이브러리인 NextAuth.js, Auth.js 등을 활용하면 매우 쉽게 구현할 수 있다. 다만 아이디/비밀번호 로그인 시 JWT를 강제로 사용해야 한다는 사소한 단점이 있다. (session 금지)

 

 

Auth.js를 사용해 소셜 로그인하기

먼저, github의 settings-developer settings의 OAUTH Apps에 현재 개발 중인 사이트(나중에는 서비스할 사이트)를 새로운 앱으로 추가한다.

 

그리고 프로젝트 터미널에서 next-auth(또는 auth)를 설치한다. 이후 pages-api 폴더에 auth 폴더를 새로 만든 뒤 그 안에 [...nextauth].js 파일을 만든다. 그리고 템플릿 코드를 추가해 반영하면 설정이 완료된다.

import NextAuth from "next-auth";
import GithubProvider from "next-auth/providers/github";

export const authOptions = {
    providers: [
        GithubProvider({
            clientId: 'github OAUTH Id',
            clientSecret: 'github OAUTH secret key',
        }),
    ],
    secret: 'jwt token secret key'
};
export default NextAuth(authOptions);

 

이후 사용하고자 하는 프로젝트 폴더에서 next-auth/react로부터 siginIn을 import 한 뒤, button의 onClick에 signIn을 바인딩하면 자동으로 로그인 페이지로 이동 후, github로 oauth 로그인을 할 수 있다.

 

로그인 완료 후, await getServerSession(authOptions)을 통해 로그인된 유저의 정보를 확인할 수 있다.

 

참고: JSX 안에서 if문을 쓰고 싶다면?

삼항연산자를 사용하면 된다.

{
	조건식 ? 조건식이 참일 때 실행할 코드(HTML) : 거짓일 때 실행할 코드(HTML)
}

이를 이용해서 어떤 조건에 따라 HTML을 다르게 보여줄 수도 있다.

 

로그인되어 있으면 로그아웃, 안되어 있으면 로그인 버튼 보여지게 만들기

let session = await getServerSession(authOptions);

{
    session == null ?
      <LoginButton /> :
      <>
        <div style={{ display: 'inline', marginRight: '20px' }}>환영합니다, {session.user.name}님!</div>
        <LogoutButton />
      </>
}

 

 

OAuth + Session 방식으로 로그인하기

기본 next-auth는 JWT 방식으로 동작하는데, 이 방식이 아닌 Session 방식으로 진행하고자 하는 경우, DB Adapter를 사용하면 된다. 첫 로그인 시 자동 회원 가입을 시키고(DB 저장), 로그인 시 DB에 세션 정보를 보관한다. 그리고 현재 로그인 된 유저의 정보가 필요하면 DB에서 조회한다.

 

npm에서 DB에 맞는 adaptor를 설치하고, DB adapter를 세팅한다.

npm install @next-auth/mongodb-adapter

그리고 [...nextauth].js에 다음 설정을 추가하면 설정이 완료된다.

adapter: MongoDBAdapter(connectDB)

이후 OAuth로 로그인을 하면, DB에 다음 컬렉션들이 추가된다

  • sessions: 현재 로그인된 유저 세션 정보 저장
    • 세션토큰, session id, 만료일자 
  • users: 가입된 유저 정보
    • email로 가입된 유저를 구분한다. email이 같으면 같은 유저로 간주
  • accounts: 가입된 유저의 계정정보
    • 하나의 유저가 여러 형식으로 가입하면 여러 document가 생성된다.

서버 api 쪽에서도 마찬가지로 getServerSession를 사용할 수 있는데 request, response 파라미터를 추가해줘야 한다.

let session = await getServerSession(request, response, authOptions);

참고로, 유저 컴포넌트에서는 getServerSession을 사용할 수 없다.

 

글 작성자에게만 수정/삭제 기능이 보이도록 만들기

<div className="list-item">
    <Link href={`/detail/${data._id}`}><h4>{data.title}</h4></Link>
    {
        session.user.name == data.author &&
        <>
            <Link href={`/edit/${data._id}`}>수정</Link>
            <span onClick={async (e) => {
                let isDelete = confirm('정말 삭제하시겠습니까?');

                if (isDelete) {
                    try {
                        const resp = await axios.delete(`/api/board/delete?_id=${data._id}`,
                        );
                        if (resp.data.success) {
                            alert('삭제 완료!');

                            e.target.parentElement.style.opacity = 0;
                            setTimeout(() => {
                                e.target.parentElement.style.display = 'none';
                            }, 1000)
                        } else {
                            throw new Error('서버 오류: ' + resp.status);
                        }
                    } catch (err) {
                        console.log(err);
                    }
                }
            }}> 삭제</span>
        </>
    }

    <p>1월1일</p>
</div>

 

 

아이디/비밀번호 + JWT 방식으로 로그인하기

기존 [...nextauth].js 설정 파일에 CredentailsProvider 속성을 추가한다. 이 속성을 추가하면 session 방식을 사용할 수 없고, 오직 JWT 방식만 사용할 수 있게 된다.

 

CredentialsProvider

  • credentials 필드: 로그인 페이지에서 폼을 자동 생성해주는 코드
    • 필요한 필드(email, password 등), 표시할 필드명, 필드 타입 등
  • authorize: 로그인 요청 시 실행되는 코드
    • 유저가 제출한 비밀번호와 DB의 비밀번호가 맞는지 확인
    • 맞으면 유저 정보를, 틀리면 null을 반환
  • session: session/JWT 방식 선택 및 로그인 상태 유지 기간 설정
  • callbacks
    • jwt: JWT를 만들어서 보낼 때 태워서 보낼 정보 설정
    • session: 컴포넌트에서 JWT 조회 시 보내줄 유저 정보

먼저 회원가입 페이지를 만들고, 유저의 가입 정보를 받아 DB에 추가한다. 이때, 비밀번호의 경우 그대로 DB에 저장하면 보안 상 문제가 생길 수 있으므로, 비밀번호를 암호화해서 저장해야 한다. 이를 위해 암호화 라이브러리로 터미널에서 bcrypt를 설치해주고, bcrypt를 import해서 사용한다.

 

그리고 회원가입 시 다음과 같은 사항들을 고려해야 한다.

  • 채워야 할 input을 빈 칸으로 보내는 경우
  • 이메일 혹은 아이디(고유한 필드)가 중복되는 경우

 

추가로 JWT secre key 등 민감한 개인 정보들은 .env.local 파일을 따로 만들어서 Github 등에 올라가지 않게 주의를 기하는 것이 좋다. (.gitignore에 추가되었는지도 확인 필수) 이후 저장된 변수들은 다른 js 파일에서 process.env.변수명으로 사용이 가능하다

 

 

Input 데이터 다루기

유저 컴포넌트에서 form 태그를 사용하지 않을 때 Input 값을 추적하기 위해서는 useState를 사용한다.

let [comment, setComment] = useState('')

/* return 문 내부 */
<input onChange={(e) => { setComment(e.target.value) }} value={comment}/>
<button type='button' className={styles.submitButton} onClick={() => {
    fetch('/api/reple', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            parent: id,
            writer: session.user.userId,
            content: reple,
        })
    })
}}>등록</button>

 

참고자료

코딩애플 온라인 강의 <Next.js로 웹서비스 만들기>

저작자표시 비영리 변경금지 (새창열림)

'크래프톤 정글 > Equipped in 정글(나만무)' 카테고리의 다른 글

[나만무] Jungle-Board 댓글 기능 및 검색, 페이지네이션 구현 및 배포하기  (1) 2025.06.20
[나만무] Jungle-Board 로그인/회원가입 기능 구현 및 게시판 권한 반영하기  (0) 2025.06.18
[나만무] Jungle-Board 기본 CRUD 구현하기  (0) 2025.06.17
[나만무] 06.16 TIL - Next.js 학습 by 코딩애플  (0) 2025.06.16
[나만무] 06.15 TIL - Next.js 학습 by 코딩애플  (0) 2025.06.15
'크래프톤 정글/Equipped in 정글(나만무)' 카테고리의 다른 글
  • [나만무] Jungle-Board 댓글 기능 및 검색, 페이지네이션 구현 및 배포하기
  • [나만무] Jungle-Board 로그인/회원가입 기능 구현 및 게시판 권한 반영하기
  • [나만무] Jungle-Board 기본 CRUD 구현하기
  • [나만무] 06.16 TIL - Next.js 학습 by 코딩애플
그냥사람_
그냥사람_
IT 관련 포스팅을 합니다. 크래프톤 정글 8기 정경호
  • 그냥사람_
    그냥코딩
    그냥사람_
  • 전체
    오늘
    어제
    • 글 전체보기 N
      • 크래프톤 정글 N
        • 로드 투 정글(입학시험)
        • CS기초(키워드, 개념정리)
        • 컴퓨터구조(CSAPP)
        • Code 정글(C언어)
        • Equipped in 정글(나만무) N
        • 마이 정글(WIL, 에세이)
      • 자료구조&알고리즘
        • 자료구조
        • 알고리즘
      • 일상
  • 블로그 메뉴

    • 홈
  • 링크

    • Github
  • hELLO· Designed By정상우.v4.10.3
그냥사람_
[나만무] 06.17 TIL - Next.js 학습 by 코딩애플
상단으로

티스토리툴바