import { z } from 'zod'
export const SignupFormSchema = z.object({
name: z
.string()
.min(2, { message: 'Name must be at least 2 characters long.' })
.trim(),
email: z.string().email({ message: 'Please enter a valid email.' }).trim(),
password: z
.string()
.min(8, { message: 'Be at least 8 characters long' })
.regex(/[a-zA-Z]/, { message: 'Contain at least one letter.' })
.regex(/[0-9]/, { message: 'Contain at least one number.' })
.regex(/[^a-zA-Z0-9]/, {
message: 'Contain at least one special character.',
})
.trim(),
})
export type FormState =
| {
errors?: {
name?: string[]
email?: string[]
password?: string[]
}
message?: string
}
| undefined
사용자 생성 또는 자격 증명 확인
export async function signup(state: FormState, formData: FormData) {
// 1. Validate form fields
// ...
// 2. Prepare data for insertion into database
const { name, email, password } = validatedFields.data
// e.g. Hash the user's password before storing it
const hashedPassword = await bcrypt.hash(password, 10)
// 3. Insert the user into the database or call an Auth Library's API
const data = await db
.insert(users)
.values({
name,
email,
password: hashedPassword,
})
.returning({ id: users.id })
const user = data[0]
if (!user) {
return {
message: 'An error occurred while creating your account.',
}
}
// TODO:
// 4. Create user session
// 5. Redirect user
}
세션 관리
세션의 2가지 유형
Stateless : 세션을 브라우저의 쿠키에 저장 → 보안성이 떨어질 수 있음
Database : 세션을 데이터베이스에 저장 → 안전하지만 리소스 사용 증가
데이터베이스 세션
데이터베이스 세션을 만들고 관리하려면 다음 단계를 따라야 합니다.
세션과 데이터를 저장할 데이터베이스에 테이블을 만듭니다(또는 인증 라이브러리가 이를 처리하는지 확인합니다).
세션을 삽입, 업데이트, 삭제하는 기능을 구현합니다.
사용자의 브라우저에 저장하기 전에 세션 ID를 암호화하고, 데이터베이스와 쿠키가 동기화된 상태를 유지하도록 합니다(권장)
import cookies from 'next/headers'
import { db } from '@/app/lib/db'
import { encrypt } from '@/app/lib/session'
export async function createSession(id: number) {
const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
// 1. Create a session in the database
const data = await db
.insert(sessions)
.values({
userId: id,
expiresAt,
})
// Return the session ID
.returning({ id: sessions.id })
const sessionId = data[0].id
// 2. Encrypt the session ID
const session = await encrypt({ sessionId, expiresAt })
// 3. Store the session in cookies for optimistic auth checks
cookies().set('session', session, {
httpOnly: true,
secure: true,
expires: expiresAt,
sameSite: 'lax',
path: '/',
})
}
권한 부여
사용자가 인증되고 세션이 생성되면 애플리케이션 내에서 사용자가 액세스하고 수행할 수 있는 작업을 제어하는 권한 부여를 구현할 수 있습니다.
권한 확인에는 두 가지 주요 유형이 있습니다.
Optimistic
쿠키에 저장된 세션 데이터를 사용하여 사용자가 경로에 액세스하거나 작업을 수행할 권한이 있는지 확인합니다. 이러한 확인은 UI 요소를 표시/숨기거나 권한이나 역할에 따라 사용자를 리디렉션하는 것과 같은 빠른 작업에 유용합니다.
보안
사용자가 데이터베이스에 저장된 세션 데이터를 사용하여 경로에 액세스하거나 작업을 수행할 권한이 있는지 확인합니다. 이러한 검사는 보다 안전하며 민감한 데이터 또는 작업에 액세스해야 하는 작업에 사용됩니다.
Middleware를 사용한 낙관적 검사(선택 사항)
권한에 따라 미들웨어를 사용하고 사용자를 리디렉션하려는 경우가 있습니다 .
낙관적 검사를 수행하려면 Middleware가 모든 경로에서 실행되므로 리디렉션 논리를 중앙 집중화하고 허가받지 않은 사용자를 사전 필터링하는 좋은 방법입니다.
사용자 간에 데이터를 공유하는 정적 경로를 보호합니다(예: 유료 콘텐츠).
그러나 미들웨어는 사전 페치된 경로를 포함한 모든 경로에서 실행되므로 쿠키에서만 세션을 읽고(낙관적 검사) 성능 문제를 방지하기 위해 데이터베이스 검사를 피하는 것이 중요합니다.
import { NextRequest, NextResponse } from 'next/server'
import { decrypt } from '@/app/lib/session'
import { cookies } from 'next/headers'
// 1. Specify protected and public routes
const protectedRoutes = ['/dashboard']
const publicRoutes = ['/login', '/signup', '/']
export default async function middleware(req: NextRequest) {
// 2. Check if the current route is protected or public
const path = req.nextUrl.pathname
const isProtectedRoute = protectedRoutes.includes(path)
const isPublicRoute = publicRoutes.includes(path)
// 3. Decrypt the session from the cookie
const cookie = cookies().get('session')?.value
const session = await decrypt(cookie)
// 4. Redirect to /login if the user is not authenticated
if (isProtectedRoute && !session?.userId) {
return NextResponse.redirect(new URL('/login', req.nextUrl))
}
// 5. Redirect to /dashboard if the user is authenticated
if (
isPublicRoute &&
session?.userId &&
!req.nextUrl.pathname.startsWith('/dashboard')
) {
return NextResponse.redirect(new URL('/dashboard', req.nextUrl))
}
return NextResponse.next()
}
// Routes Middleware should not run on
export const config = {
matcher: ['/((?!api|_next/static|_next/image|.*\\\\.png$).*)'],
}
미들웨어는 초기 검사에 유용할 수 있지만, 데이터를 보호하는 유일한 방어선이 되어서는 안 됩니다. 대부분의 보안 검사는 데이터 소스에 최대한 가깝게 수행해야 합니다. 자세한 내용은 데이터 액세스 계층을 참조하세요.
데이터 엑세스 계층(DAL) 생성
(• DAL은 데이터베이스와 직접 상호작용하여 데이터를 읽고 쓰는 계층입니다.)
데이터 요청과 권한 부여 논리를 중앙에서 관리하려면 DAL을 만드는 것이 좋습니다.
DAL에는 사용자가 애플리케이션과 상호 작용할 때 사용자의 세션을 확인하는 기능이 포함되어야 합니다. 최소한 이 기능은 세션이 유효한지 확인한 다음 추가 요청을 하는 데 필요한 사용자 정보를 리디렉션하거나 반환해야 합니다.
예를 들어, verifySession() 함수를 포함하는 DAL에 대한 별도 파일을 만듭니다. 그런 다음 React의 캐시를 사용합니다.
책을 종종 읽는 편이어서 ‘그리스인 조르바’라는 책에 대한 이야기를 들어본 적은 있다. 자유에 관한 책이면서 고전 명작이라는 이야기를 들은 적이 있었으나 지루할 것 같아서 찾아보진 않았다
그러던 중 독후감이라는 숙제가 생겼고, 지인들에게 가지고 있는 책을 물어보니 ‘그리스인 조르바’가 있다기에 냉큼 받아왔다. 도대체 ‘자유’라는 주제를 어떻게 풀어나갈 것인지 궁금했기 때문이다. 그리고 앞으로의 나의 ‘자유’를 어떠한 자세로 맞이할 것인지 배울 수 있을 것 같았다.
이야기의 시작은 독립 투쟁에 뛰어드는 친구가 나(화자)에게 ‘안녕, 책벌레야’라고 말하면서 떠난다. 그 말을 듣고 주인공은 행동하는 삶을 살기 위해 크레타섬으로 떠나면서 ‘조르바’를 만나면서 경험했던 이야기를 풀어나간다.
인생을 사랑하자면서 모순적으로 책과 잉크로 더럽혀진 종이에 자신을 오랫동안 처박아둔 것인가! ‘안녕 책벌레야’라는 말이 드디어 나 자신을 볼 수 있게 해주었다.
친한 친구의 말에 깨달음을 얻고 행동하는 삶을 위해 자신의 환경부터 변화시키기로 한 ‘나’는 크레타섬으로 가기 위한 배에 올라탔다. 그곳에서 한 노인이 다가와 함께 동행하자고 제안하자 “왜요?”라고 물었더니 “<왜요>가 없으면 아무것도 못 하는 건가요? 가령, 하고 싶어서 한다면 안 됩니까? 난 요리사입니다.”라고 노인은 대답했다. 그러고도 우물쭈물하는 나에게 그는 말했다. “당신 역시 저울 한 벌 가지고 다니는 거 아니오? 매사를 정밀하게 달아 보는 버릇 말이오. 자 젊은 양반, 결정해버리쇼. 눈 딱 감고 해버리는 거요”라고 말하는 노인을 보며 이름을 묻자 대답했다. ‘알렉시스 조르바’
그렇다. 나는 그제아 알아들었다. 조르바는 내가 오랫동안 찾아다녔으나 만날 수 없었던 바로 그 사람이었다. 그는 사람 있는 가슴과 커다랗고 푸짐한 언어를 쏟아 내는 입과 위대한 야성의 영혼을 가진 사나이. 아직 모태인 대지에서 탯줄이 떨어지지 않는 사나이였다.
보통 사람들은 자신이 못하는 것을 가뿐하게 해내는 사람을 부러워하는 경향이 있다. 분명 ‘나’는 책도 많이 읽은 지식인이면서, 엘리트의 삶을 살았지만 자유롭게 생각하고 행동하는 조르바를 부러워하고 동경하는 것처럼 보였다. 왜냐하면 나 또한 행동하기보단 생각만 하고 행동하지 못했던 때가 많았기 때문에, 책 속의 ‘나’에게 감정이 몰입되는 것 같았다.
그에게서 ‘해방감’을 느끼고 매료된 ‘나’는 그에게 크레타에서의 갈탄 사업을 함께하자고 제안한다. 조르바는 ‘나’를 ‘두목’이라고 부르면서 다음과 같이 말했다.
“당신이 바라는 만큼 일해 주겠소. 거기 가면 나는 당신 사람이니까. 하지만 산투르 말인데, 그건 달라요. 산투르는 짐승이오. 짐승에게 자유가 있어야 해요. 처음부터 분명히 말해 놓겠는데, 마음이 내켜야 해요. 분명히 해둡시다. 나한테 윽박지르면 그때는 끝장이에요. 결국 당신은 내가 인간이라는 걸 인정해야 한다 이겁니다.”
“인간이라니, 무슨 뜻이지요?”
“자유라는 거지!”
조르바가 생각하는 ‘자유’에 대한 인상적인 문구였다. 누구에게도 구속되지 않겠다는 의지가 느껴졌고 겉치레 없이 솔직하게 윽박지르면 바로 끝장이라고 말하는 조르바가 부럽다고 생각했다. 전 재산을 털어서 산투르를 구매하고 연주 방법을 배우기 위해 떠돌아다녔다는 조르바의 열정을 보면서 질투심마저 들었다. 살면서 무언가에 푹 빠져서 열중해 본 적 없는 나는 솔직히 조르바를 완벽하게 이해하지 못할 것 같다. ‘좋아하는 것’, 결국 내가 원하는 것을 명확하게 이해하지 못한다면 ‘자유’를 명확하게 이해한다는 것은 불가능하다는 것이 나의 생각이다.
<자유라는게 뭔지 알겠지요?> 금화를 약탈하는데 정열을 쏟고 있다가 갑자기 그 정열에 손을 들고 애써 모은 금화를 공중으로 던져 버리다니… 다른 열정, 보다 고상한 정열에 사로잡히기 위해 쏟아 왔던 정열을 버리는 것. 그러나 그것 역시 일종의 노예근성이 아닐까? 이상이나 종족이나 하느님을 위해 자신을 희생시키는 것은? 따르는 전형이 고상할수록 우리가 묶이는 노예의 사슬이 길어지는 것은 아닐까? 그리고 우리는 좀 더 넓은 경기장에서 찧고 까불다가 그 사슬을 벗어나 보지도 못하고 죽는 것은 아닐까? 그렇다면 우리가 자유라고 부르는건 무엇일까?
이 문장을 읽은 나는 표현하기 힘든 감동을 느끼면서 그 감동을 언어로 표현하기 어렵다는 것을 깨닫고 좌절감도 느껴졌다. 조르바가 무엇을 얘기하고자 하는지 명확하게 알 수 없지만 주체성 없이 무언가를 추구하다 보면 결국 그것에 구속되는 것은 아닐까라는 생각이 들었다. 금화를 모으는 것에 집중하다가 갑자기 집착을 버리고 이상이나 국가, 하느님과 같은 관념적인 것에 자신을 희생시키는 것은 일종의 노예근성 또는 자가 구속이 아닐까? 무신론자인 나로서는 공감이 가지만 결국 ‘자유’란 무엇인지 정의 내리기는 어려웠다.
사람을 대할 때도 나무를 대하듯이 하면 돼요. 무화가 나무한테 버찌가 안 열린다고 화내는 사람은 어리석다는 거죠. 사람은 다 다르고, 각자 있는 그대로 받아들여야 해요. 상대의 부족한 부분을 우리의 욕망으로 채워넣고, 제멋대로 실망하고 다툴 필요가 없어요.
살다 보면 타인에게 자신의 가치관을 주입시키려고 시도해 본 경험은 대부분 있을 것 같다. 예를 들면 매일 취미생활만을 즐기는 단편적인 모습만을 보고, 공부 좀 하면서 현실을 살라고 조언을 하는 경우도 있을 것이다. 하지만 ‘사람은 고쳐 쓰는 거 아니다’라는 말처럼 변하기도 쉽지 않을뿐더러, 사람마다 행복을 느끼는 포인트는 다르기에 강요할 필요는 없다고 생각한다. 조르바 또한 머리가 백발이 될 때까지 살아온 사람이므로 같은 경험을 하고 느끼지 않았을까 생각이 든다.
산다는 건 곧 말썽이오. 죽으면 말썽이 없지. 당신.. 산다는 게 뭔 줄 아시오? 허리띠를 풀고 말썽거리를 만드는 게 바로 삶이요!
실패를 한다는 것, 타인의 시선을 신경 쓰는 것과 같은 것이 여기서 말하는 말썽이 아닐까? 그리고 조르바가 말하는 “여자는 영원한 사업”도 남들의 신경을 쓰면 도무지 할 수 없는 사업이다. 나 또한 사람들의 시선이 쓰이기에 맘에 드는 전화번호를 묻고, 데이트를 신청하고, 사랑한다고 말하는 건 어렵다고 느껴진다. 그렇기에 말썽을 부리는 사람을 보면 멋지다고 생각한다. 도전해 보지도 않고 뒤에서 욕하는 사람보다는 용기를 가지고 도전함으로써 실패를 겪는 게 100배는 멋진 것 같다.
새 길을 닦으려면 새 계획을 세워야지요. 나는 어제 일어난 일은 생각 안합니다. 내일 일어날 일을 자문하지도 않아요. 내게 중요한 것은 오늘, 이 순간에 일어나는 일입니다.
글로만 지식을 습득했던 ‘나’는 조르바와 대화를 나누면서 진짜 삶을 깨달아간다. 종이와 펜으로 혈투를 벌이던 ‘나’는 육체노동을 하는 조르바의 방식을 점차 따르게 된다. 조르바는 여인숙을 운영하는 오르탕스라는 늙은 여자에게 구애하면서 사귀게 된다. 그는 먹을 때는 먹는 것에만 집중하고, 사랑을 나눌 때는 사랑하는 일에만 집중한다. 탄광에서 일을 하며 땀을 흘릴 때 그는 오로지 그 순간에만 몰입한다. 조르바는 과거와 미래에 얽매이지 않고 현재 순간만을 생각한다. 불교를 믿지는 않지만 불교를 좋아하는 내가 감명있게 읽었던 부처님의 명언과 조르바의 말은 일맥상통하고 있다. “과거에 머물지 말고, 미래를 꿈꾸지 말라. 마음을 현재에 집중하라”
전에는 그토록 나를 매혹하던 시편들이 그날 아침에는 느닷없이 지적인 광대놀음, 세련된 사기극으로 보이는 것이 아닌가! (…) 최후의 인간(모든 믿음에서, 모든 환상에서 해방된, 그래서 기대할 것도 두려워할 것 도 없어진)은 자신의 원료가 되어 정신을 산출한 진흙이며, 이 정신이 뿌리내리고 수액을 빨아올릴 토양은 아무 데도 없다는 것을 깨닫는 인간이다. 최후의 인간은 자신을 비운 인간이다.
말은 어렵지만 그토록 집착했던 것을, 모든 것을 버린 순간 깨달음이 ‘나’에게 찾아왔다. 지금까지 진리라고 믿고 있던 모든 가치는 한순간에 무너졌다. 인간이기에 쉽게 포기할 수 없는 가치를 놓는 순간 깨달음을 얻은 것 같다. 내가 가장 감명 있게 읽었던 데이비드 호킨스의 ‘놓아버림’에서 나온 문구인 ‘고통의 주된 원인은 애착’이라는 말처럼 자신도 모르는 잘못된 신념, 생각 등을 모두 비워야 자유로워질 수 있다고 생각이 든다.
나는 행복했고, 그 사실을 알고 있었다. 행복을 체험하면서 그것을 의식하기란 쉽지 않다. 행복한 순간이 과거로 지나가고, 그것을 되돌아보면서 우리는 갑자기(이따금 놀라면서) 그 순간이 얼마나 행복했던가를 깨닫는 것이다. 그러나 그 크레타 해안에서 나는 행복을 경험하면서, 내가 행복하다는 걸 실감하고 있었다.
사람들은 대부분 현재보다는 과거를 보고 사는 것 같다. 사진첩에 있는 과거 여행 사진을 보며 현재의 일을 괴로워하며 수행하면서 미래에 여행을 떠나는 자신의 모습을 상상하며 견뎌내는 뻔한 스토리처럼 말이다. 지금 현재에서 느낄 수 있는 커피 한 잔의 여유, 싱싱한 야채와 달콤한 소스로 양념된 샌드위치는 즐기지 못하고 즐거웠던 과거나 미래의 일정만으로 가득 채운다. 하지만 지금의 행복을 의식할 수 있도록 노력해야만 한다.
자네는 자네가 지향하는 삶을 행복한 것이라고 생각하고 있을 것이네. 그리고, 그렇게 생각하기 때문에 자네는 행복할 것이네.
‘나’는 조르바를 통해 많은 것들을 배우고 깨닫고 있었다. 그와 함께 사업을 확장하면서 많은 일이 있었지만 결국 사업은 철저하게 실패했다. 조르바는 나에게 미안해했지만, 오랜 기간 동안 조르바에게 동화된 나는 개의치 않고 조르바와 함께 양고기를 뜯고 춤을 춘다. 광산 사업을 정리한 뒤 나는 외국으로 나가고, 조르바는 다른 지역으로 떠나면서 각자 갈 길을 떠났다. 그리고 5년 뒤 조르바가 죽었다는 편지를 받으며 이야기는 끝이 난다.
‘그리스인 조르바’의 책 속의 조르바의 대사와 행동들은 마치 야생동물을 보는 것 같으면서도 인생을 통달한 현자를 보는 것 같은 느낌이 들었다. 현대 시대에 조르바가 있다면 인터넷 기사로 그의 기행이 한 번쯤은 소개될 것 같다. 강간하고, 약탈하면서 세상 모든 면을 깨우칠 수 있다는 비도덕적인 말도 있기에 곧이곧대로 조르바의 사상을 모두 받아들이긴 어려울 것 같다. 다만 자신의 자유를 지키겠다는 조르바의 사상에 초점을 맞추는 것이 좋겠다는 생각이 들었다.
책의 저자 ‘니코스 카잔자키스’의 묘비명에는 “나는 아무것도 바라지 않는다. 나는 아무것도 두려워하지 않는다. 나는 자유다”라고 적혀있다고 한다. 결국 책에서 가장 중점적으로 다루는 것은 ‘자유’다. 결국 사람마다 느끼는 자유는 다를 것이라 생각한다. 조르바에게 달라붙는 젊은 여자는 자유가 싫다면서 조르바와 함께하는 것이 좋다고 한다. 젊은 여자처럼 “얽매이는 자유”도 존재할 것이고, 그저 자신의 일에 “몰두하는 자유”도 있다고 생각한다. 결국 누군가 정의한 “거짓된 자유”에 속지 않고 각자 자신만의 “자유”를 추구하며 살아갈 수 있으면 좋을 것 같다.
1. 불규칙한 생활과 비만의 관계 불규칙한 식사 시간과 생활 습관은 비만을 초래하고, 이는 생체 리듬을 더욱 악화시킵니다. 이러한 악순환은 체중 증가와 다양한 건강 문제를 일으킵니다.
2. 시간 제한 다이어트의 원리와 효과 시간 제한 다이어트는 하루 중 음식을 섭취하는 시간을 12시간 이내로 제한하는 방법입니다. 연구에 따르면, 이 방법은 체중 감량에 효과적이며, 생체 리듬을 회복하는 데 도움이 됩니다. 예를 들어, 저녁을 늦게 먹지 않고 규칙적으로 식사 시간을 지키는 것이 중요합니다.
3. 다이어트 성공 사례 규칙적인 식사와 운동으로 체중을 감량한 김용갑 씨는 26kg을 감량하고 유지하고 있습니다. 그는 술을 끊고 야식을 자제하며 건강한 생활 습관을 찾았습니다.
4. 생체 리듬과 건강의 관계 생체 리듬은 낮과 밤의 주기에 따라 변하며, 이는 신진대사와 질병에 큰 영향을 미칩니다. 생체 리듬이 깨지면 비만, 심혈관 질환 등의 위험이 증가합니다. 특히 늦은 시간의 음식 섭취는 체지방 증가와 밀접한 관련이 있습니다.
5. 건강 회복을 위한 방법 생체 리듬을 회복하기 위해 식사 시간을 조절하고 충분한 수면을 취하는 것이 중요합니다. 잠들기 3~4시간 전에 마지막 식사를 마치고, 최소 7시간 이상 자는 것이 좋습니다.
6. 수면 부족과 비만의 관계 수면 부족은 식욕 조절을 어렵게 하고, 코르티솔 호르몬 분비를 증가시켜 비만을 유발할 수 있습니다. 규칙적인 생활 습관과 충분한 수면이 비만 예방에 도움이 됩니다.
7. 시간 제한 다이어트의 장점 시간 제한 다이어트는 간단하게 실천할 수 있으며, 식사 습관을 개선하고 부작용을 최소화할 수 있습니다. 3개월간 프로그램을 통해 식사 종료 시간을 관리하고, 꾸준히 운동을 시작하는 것이 효과적입니다.
8. 다이어트를 생활습관으로 만드는 방법 시간 제한 다이어트는 성인병 예방과 건강 유지에 중요한 생활 방식이 될 수 있습니다. 규칙적인 식사와 수면 습관을 통해 다이어트를 장기적인 습관으로 만들어가는 것이 중요합니다.