혹시나 예제 코드가 필요하신 분들은 해당 링크에서 받아가세요!
오늘은 저번시간에 이어서 NextAuth.js
사용법에 대해서 알아볼 예정이다.
저번 포스팅이 너무 길어지는 탓에 간략하게 맛보기만 다뤘었는데 이번에는 조금 더 NextAuth
에 대해서 살펴보고 커스텀해서 사용 할 수 있는 방법에 대해서 다뤄보도록 하겠습니다.
npm install --save next-auth
와 npm install -D @types/next-auth
설치pages
> api
> auth
> [...nextauth].ts
파일 생성[...nextauth].ts
파일에 다음 내용을 작성import NextAuth from "next-auth"
import Providers from "next-auth/providers"
import {NextApiRequest} from "next";
export default NextAuth({
providers: [
Providers.Credentials({
name: "email-password-credential",
credentials: {
email: { label: "Email", type: "email", placeholder: "test@test.com" },
password: { label: "Password", type: "password" }
},
async authorize(credentials: Record<any, any>, req: NextApiRequest){
return credentials;
}
})
]
})
pages
> index.tsx
화면을 다음과 같이 수정import { useSession, signIn, signOut } from "next-auth/client"
const Login = () => {
const [session, loading] = useSession();
if (session) {
return (
<>
Signed in as {session.user.email} <br />
<button onClick={() => signOut()}>Sign out</button>
</>
)
}
return (
<>
Not signed in <br />
<button onClick={() => signIn()}>Sign in</button>
</>
)
}
export default Login;
npm run dev
로 실행시키고 http://localhost:3000 으로 접속해서 로그인 테스트물론 NextAuth
에서 생성해주는 로그인 뷰를 그대로 사용하고 싶은 사람들은 필요 없는 내용일지 모르지만 아마도 직접 만든 로그인 화면에 NextAuth
를 붙이고 싶은 사람들이 더 많을 것 같다.
따라서 자신이 만든 로그인 화면에서 로그인 버튼을 클릭하면 NextAuth
인증이 이루어질 수 있는 방법을 소개하도록 하겠다.
먼저 [...nextauth].ts
파일을 열 수 있도록 한다. 그 다음 설정을 하나 추가해주도록 하자.
export default NextAuth({
providers: [
Providers.Credentials({
name: "email-password-credential",
credentials: {
email: { label: "Email", type: "email", placeholder: "test@test.com" },
password: { label: "Password", type: "password" }
},
async authorize(credentials: Record<any, any>, req: NextApiRequest){
return credentials;
}
})
],
// 추가
pages: {
signIn: '/login',
}
})
여기서 추가되는 pages
라는 설정은 기존에 NextAuth
가 설정해둔 여러가지 화면들을 자기가 원하는 화면으로 매핑시켜주는 설정이라고 생각하면 쉬울 것 같다. 로그인 뷰 말고도 여러가지 커스텀 화면을 매핑할 수 있으므로 더 많은 정보를 원하면 링크에서 찾아보면 될 것 같다.
따라서 현재 우리는 로그인 버튼을 누르면 /login
URL로 이동하도록 만들어두었다.
(http://localhost:3000/login 으로 이동하게 된다.)
그럼 한 번 살펴보도록 하자.
http://localhost:3000 으로 들어가서 Sign in
버튼을 클릭하면 다음과 같은 화면이 뜬다.
현재는 login 화면을 만들지 않았기 때문에 404 뜨는것이 당연합니다.
URL에 http://localhost:3000/login?callback=<콜백주소> 라고 뜨면 정상적으로 설정된 것 입니다.
일단 설정은 정상적으로 되었으니 로그인 화면을 만들어보도록 하자. Next.js
는 pages
하위에 파일을 생성하면 라우팅이 자동으로 되므로 pages
하위에 login.tsx
파일을 하나 생성하면 http://localhost:3000/login 주소로 접속할 때 해당 화면이 실행이 될 것이다.
login.tsx
화면은 다음과 같이 작성해본다.
const Login = () => {
return (
<form>
<label>
이메일 :
<input type="email" name="email" placeholder="test@test.com" />
</label>
<label>
비밀번호 :
<input type="password" name="password" />
</label>
<button type="submit">로그인</button>
</form>
)
}
export default Login;
화면 디자인은 따로 하지 않았습니다. (제가 잘 못해서..^^;;)
작성하고 저장한다음 http://localhost:3000/login 으로 들어가면 다음과 같은 화면이 나온다.
아직까지는 로그인 버튼을 클릭하면 화면이 새로고침만 되고 아무런 반응이 일어나지 않을 것이다. 이제부터 로그인 버튼을 누르면 정상적으로 로그인 처리가 될 수 있도록 해보자
다시 login.tsx
파일을 열고 다음과 같이 코드를 추가한다.
import { signIn } from "next-auth/client";
const Login = () => {
// 추가
const login = async (e: any) => {
// 원래 실행되는 이벤트 취소
e.preventDefault();
// Form 안에서 이메일, 패스워드 가져오기
const email = e.target.email.value;
const password = e.target.password.value;
const response = await signIn("email-password-credential", {
email,
password,
redirect: false
});
console.log(response);
}
return (
// onSubmit에 login 함수 등록
// 로그인 버튼을 클릭하면 login 함수가 실행된다.
<form onSubmit={login}>
<label>
이메일 :
<input type="email" name="email" placeholder="test@test.com" />
</label>
<label>
비밀번호 :
<input type="password" name="password" />
</label>
<button type="submit">로그인</button>
</form>
)
}
export default Login;
지금 이 코드에서 봐야할 핵심 부분은 signIn
이다. 무언가 길게 string
으로 적히고 옵션값이 정의되어있는데, signIn
이 바로 [...nextauth.ts]
에 정의된 Provider
를 호출하는 함수이다. 그 중에서도 따옴표 사이에 적힌 ID
값에 해당하는 Provider
를 호출한다.
하지만 우리는 Provider
에 ID
를 지정해준 적이 없다. 그럼 지정해주면 된다.
[...nextauth.ts]
파일을 열고 다음과 같이 수정해준다.
providers: [
Providers.Credentials({
// 수정
id: "email-password-credential",
name: 'Credentials',
type: 'credentials',
credentials: {
email: { label: "Email", type: "email", placeholder: "test@test.com" },
password: { label: "Password", type: "password" }
},
async authorize(credentials: Record<any, any>, req: NextApiRequest){
return credentials;
}
})
],
name
옵션은NextAuth
에서 만들어주는Form
태그의 로그인 버튼에 노출될 텍스트를 적는 부분이다.
이렇게 수정을 완료했으면 값을 입력하고 로그인 버튼을 클릭해보자.
(redirect를 false를 했기 때문에 callback URL로 이동하지 않는다.)
다음과 같이 response
정보가 error: null
인 형태로 떴다면 아주아주 지금까지 잘 따라와준거다. 우리가 입력한 email
과 password
는 정보는 그럼 어디로 들어간걸까?
이전에도 말했듯이 [...nextauth].ts
파일의 authorize
부분의 credentials
파라미터에에 JSON
형태로 전달된다. 콘솔로 찍어보면 다음과 같이 나온다.
async authorize(credentials: Record<any, any>, req: NextApiRequest){
console.log(credentials);
return credentials;
}
따라서 authorize
부분에서 이제 로그인 인증 처리를 해주면 되는데 우리는 간략하게 if
문을 이용해서 해보도록 하자. authorize
코드를 다음과 같이 수정해준다.
async authorize(credentials: Record<any, any>, req: NextApiRequest){
const email = credentials.email;
const password = credentials.password;
if(email === "test@test.com" && password === "test"){
return credentials;
}
throw new Error("아이디 혹은 패스워드가 틀립니다.");
}
이메일이 test@test.com
이면서 패스워드가 test
이면 credentials
를 리턴해주면서 정상적으로 인증이 되었다고 알려줍니다. 반대로 이메일이나 패스워드중 둘 중 하나라도 틀리면 에러를 던져서 사용자에게 알려줄 수 있도록 합니다.
❗ 여기서 유저들에게 정보 전달은 명확하게 한다고 아이디가 틀리면 아이디가 틀렸다, 패스워드가 틀리면 패스워드가 틀렸다고 특정해서 전달하시는 분들이 간혹 있다. 그렇게 하게 되면 해커들이 아이디의 존재 유무를 파악하고 해킹 공격을 할 수 있기 때문에 로그인 부분에서는 불친절하게 에러 메시지를 간결하게 띄우는 것이 좋다.
그리고 코드를 저장한 후 다시 로그인을 진행해보자.
Response 응답이 다르게 들어온 것을 알 수 있다.
따라서 Response
의 Error
의 유무를 이용해서 인증이 되었는지, 아니면 에러 메시지를 띄워서 사용자에게 로그인을 다시 시도하게 할지를 확인하면 될 것 같다.
오늘 포스팅이면 로그인 부분에 대해서는 끝낼 수 있을 줄 알았는데 하다보니 내용이 많이 길어졌다. 다음 포스팅을 마지막으로 로그인을 마무리하고 본격적인 Next.js
의 SSR 렌더링에 대해서 알아보는 시간을 가질 수 있도록 하겠다.
긴 글 읽어주셔서 감사드리고 혹시 잘못된 부분이 있어가 추가했으면 하는 내용들이 있으면 댓글로 작성해주시면 빠르게 피드백 하겠습니다.
좋은글 잘봤읍니다,,, ^^