인증- 유저가 누군지 알아내기
권한 -유저가 보려는 데이터에 접근 권한이 있는지
### Auth Logic
|
type alias와 interface의 차이
type-alias는 모든 타입을 선언할 때 사용될 수 있고, interface는 객체에 대한 타입을 선언할 때 사용될 수 있다. 둘 다 객체에 대한 타입을 선언하는 데 사용될 수 있는데, 확장 측면에서 사용 용도가 달라진다. 확장이 불가능한 타입을 선언하려면 type-alias를 사용하면 되고, 확장이 가능한 타입을 선언하려면 선언 병합이 가능한 interface를 사용하면 된다.
Mutation
Mutation은 서버에 데이터를 업데이트 하도록 서버에 네트워크 호출을 실시한다
CRUD(Create, Read, Update, Delete)에서
useQuery가 C를 맡았다면, useMutation은 RUD를 담당한다
Mutation은 변경 내용을 사용자에게 보여주거나 진행된 변경 내용을 등록하여 사용자가 볼 수 있게 하는 방법들이 있다
PlanetScale 데이터베이스 연결
pscale connect carrot-market
pscale connect carrot-market 실행하지 않으면 프리스마가 db에 접근하지 못함.
문자열 쉽게 정수로 바꾸는법
String -> Number : +"1234"
Number -> String : 1234 + ""
객체 내에서 if else기능을 사용하는 es6 문법
where:{
...(phone &&{phone:+phone})
...(phone &&{phone:+phone})
}
}
userId가 생성된 이유는 model Token에 실제 user데이터가 db에 들어가진 않음 단순 텍스트이기 때문에 userId가 user임을 알려줌
schema생성 후
npx prisma db push
--> 새로운 토큰이 planetscale에 있는 케럿마켓 데이터베이스에 추가될 것임
db수정, prisma client새로만들어줌
client 재생성 , 변경 후
npm run dev 서버 재시작
token에 undefiend인 프로퍼티를 읽을 수 없다고 에러가 난다면?
--> client를 재생성, 변경 후 서버를 재시작하지 않아서 기존 token 생성하기 전 구버전의 client를 사용하고 있는 거임
재시작해야 업뎃 됨
npx primsa studio에서 유저가 어떤 토큰을 갖고있고
반대로 토큰이 어떤 유저를 갖고있는지 확인 할 수 있다.
Update or create records (upsert)
upsert()는 기존 데이터를 업데이트하거나 새 데이터베이스 레코드를 생성합니다. 다음 쿼리는 upsert를 사용하여 특정 이메일 주소로 사용자 레코드를 업데이트하거나, 존재하지 않는 경우 해당 사용자 레코드를 생성합니다.
```
const upsertUser = await prisma.user.upsert({
where: {
email: 'hello@gmail.com', // email이 존재하는지 찾고,
},
update: {
name: 'pizza', //존재하면 update 실행
},
create: {
email: 'hello@gmail.com', // email이 존재하지 않다면 생성
name: 'pizza',
},
})
```
https://www.prisma.io/docs/concepts/components/prisma-client/crud#update-or-create-records
https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#upsert
connect
connect 쿼리는 ID 또는 고유 식별자를 지정하여 레코드를 기존 relation 레코드에 연결합니다. (레코드를 연결)
@relation 관계가 있을 경우에
https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#connect
Payload
페이로드(payload)는 전송되는 데이터를 의미합니다. 데이터를 전송할 때, 헤더와 메타데이터, 에러 체크 비트 등과 같은 다양한 요소들을 함께 보내어, 데이터 전송의 효율과 안정성을 높히게 됩니다. 이 때, 보내고자 하는 데이터 자체를 의미하는 것이 바로 페이로드입니다. 우리가 택배 배송을 보내고 받을 때, 택배 물건이 페이로드이고, 송장이나 박스, 뾱뾱이와 같은 완충재 등등은 부가적인 것이기 때문에 페이로드가 아닙니다.
json으로 보는 실제 데이터에서의 payload는 json에서 “data”입니다. 그 이외의 데이터들은 전부 통신을 하는데 있어 용이하게 해주는 부차적인 정보들입니다.
connectOrCreate 프리즈마의 강력한도구 !
조건을 만족하는 유저가있으면 connect하고
없으면 생성하기
connectOrCreate
connectOrCreate는 ID 또는 고유 식별자로 기존 관련 레코드에 레코드를 연결하거나 레코드가 존재하지 않는 경우 새 관련 레코드를 생성합니다.
아래 글의 unique violation 참조
https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#connectorcreate
Prisma Client API (Reference)
API reference documentation for Prisma Client.
www.prisma.io
That is how we can have `passwordless` log in. 로그인 할 때 마다 토큰을 받는 방식구현하기
Twilio 통해 메세지 보내기
Twilio
Twilio는 전화 걸기 및 받기, 문자 메시지 보내기 및 받기, 웹 서비스 API를 사용하여 기타 커뮤니케이션 기능 수행을 위한 프로그래밍 가능한 커뮤니케이션 도구를 제공합니다.
https://www.twilio.com/
Twilo Document
https://www.twilio.com/docs
Messaging Services
메시징 서비스는 특정 사용 사례 및 메시징 캠페인을 위한 메시징 기능을 번들로 제공하는 컨테이너입니다. 특정 채널 및 번호 유형 중에서 선택하여 발신자를 메시징 서비스와 일치시키십시오.
랜덤 6자리 숫자 생성
방법 1) Math.floor(100000 + Math.random() * 900000) + "";
방법 2) String(Math.random()).substring(2,8)
+Math.random으로 최솟값 최댓값만들기
Math.floor(Math.random() * (최대값 - 최소값) + 최소값)
Math.random(): 0~1 사이의 부동소수점 값 (1은 포함하지 않습니다) 0~0.999
0 <= random <= 9
Math.floor(Math.random() * 10);
Math.random() 함수의 결과는 0~0.99999...이고,
Math.random() * 10 의 결과는 0~9.99999...입니다.
따라서, Math.floor(Math.random() * 10)의 결과는 0~9 범위의 정수입니다.
Math.random() 함수를 이용하여 정수 범위의 난수를 생성할 때는
이렇게 Math.random() 함수를 호출한 결과를 조작하고, Math.floor()를 사용합니다.
0 <= random <= 10
Math.floor(Math.random() * 11);
10을 포함하는 정수 난수를 얻고 싶다면
Math.random() 함수의 결과에 11을 곱하고, 소수점 이하를 버림합니다.
0 <= random <= 99
Math.floor(Math.random() * 100);
0~99 범위의 정수 난수를 생성하려면
Math.random() 함수의 결과에 100을 곱해주고, 소수점 이하를 버림합니다.
0 <= random <= 100
Math.floor(Math.random() * 101);
0~100 범위의 정수 난수를 생성하려면
>Math.random() 함수의 결과에 101을 곱하고, 소수점 이하를 버림합니다.
(7) 1 <= random <= 10
Math.random() * 10) + 1;
최소값을 지정하고 싶을 때는
Math.random() * (max - min + 1) 값을 계산하고, 소수점 이하를 버림합니다.
그리고, min 값을 더해줍니다.
1~10 범위의 정수 난수를 계산하기 위해서 아래와 같이 계산하였습니다.
Math.floor(Math.random() * (10 -1 + 1)) + 1
= Math.floor(Math.random() * 10) + 1
(8) 2 <= random <= 5
Math.floor(Math.random() * 4) + 2;
(7)번 예제와 같이 범위를 지정하는 예제입니다.
Math.floor(Math.random() * (5 - 2 + 1)) + 2
= Math.floor(Math.random() * 4) + 2
(Math.random()*(최대-최소))+최소
예)
출처:https://hianna.tistory.com/454
sid, token,messaging services sid,myphone(국가번호도 기재해야함)
TWILIO_TOKEN=
TWILIO_MSID=
MY_PHONE=+821012345678
.env에 저장
npm i twilio
input에 입력한 phone이 들어가야하지만
제한된 계정이기 때문에 무슨 번호를 입력해도 내폰으로 문자옴
Node.js용 프로그래밍 가능한 SMS 빠른 시작
Twilio의 메시징 채널을 사용하여 전송된 모든 메시징은 A2P(Application-to-Person) 메시징으로 취급되며 Twilio의 메시징 정책이 적용됩니다. 몇 줄의 코드로 Node.js 애플리케이션에서 Twilio Programmable SMS로 문자 메시지를 보내고 받을 수 있습니다.
```
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const twilioClient = require('twilio')(accountSid, authToken);
const messageInstance: MessageInstance = await twilioClient.messages.create({
messagingServiceSid: process.env.MESSAGING_SERVICES_SID,
to: process.env.MY_PHONE_NUMBER as string,
body: `휴대폰 로그인을 위한 토큰 ${createdRandomPayload} 입니다.`,
});
```
https://www.twilio.com/docs/sms/quickstart/node
nodeMailer로 메일 보내기
1. 네이버 이메일 -> 내 메일함 오른쪽 설정버튼 클릭 -> 상단 메뉴들 중 'POP/IMAP 설정' -> 바로 아래에 'IMAP/SMTP 설정' -> 사용함, 동기화 메일 제한은 1000으로 해놓았습니다.
2. 하단에 보시면 SMTP 서버 명, SMTP 포트가 표시되어있습니다.
3. server폴더 내에 email.ts를 만들어줍니다.
4. npm install --save nodemailer @types/nodemailer
5. email.ts에
-------------------------------------------------------------
import nodemailer from "nodemailer";
const smtpTransport = nodemailer.createTransport({
service: "Naver",
host: "smtp.naver.com",
port: 587,
auth: {
user: process.env.MAIL_ID,
pass: process.env.MAIL_PASSWORD,
},
tls: {
rejectUnauthorized: false,
},
});
export default smtpTransport;
---------------------------------------------------------
6. enter.tsx에 돌아오셔서
------------------------------------------------------------------
if (email) {
const mailOptions = {
from: process.env.MAIL_ID,
to: email,
subject: "Nomad Carrot Authentication Email",
text: `Authentication Code : ${payload}`,
};
const result = await smtpTransport.sendMail(
mailOptions,
(error, responses) => {
if (error) {
console.log(error);
return null;
} else {
console.log(responses);
return null;
}
}
);
smtpTransport.close();
console.log(result);
}
--------------------------------------------------------
여기서 메일 옵션의 from은 제 아이디를 써야 동작하는 것 같더라구요...
carrot@noreply.com 같은 존재하지 않는 이름으로 해보았는데 오류가 발생해서
테스트 용으로 사용할 거니까 일단 제 메일주소로 진행했더니 정상적으로 보내집니다.
혹시 저처럼 sendgrid에서 메일 오는 것 기다리기 지치신 분들은 sendgrid사용 전에 이렇게 해서 테스트해보시는것도 추천드립니다...
혹시 글이 부족하다면 'nodemailer 네이버 연동'으로 검색하시면 어렵지 않게 사용법 확인 가능합니다!
❗ npx prisma studio에서 에서 유저를 삭제하면 오류가난다
token schema를 살펴보면 user가 반드시 있어야하는데 상응하는 user가 사라지면 안 되어서 오류가 남
onDelete:cascade 부모 user가 사라지면 자식인 token도 사라지는것
npx prsima db push
bigInt , onDelete 변경한 부분을 데이터베이스 update 도와줌
res.end()는 보내줄 아무 데이터도 없는데 response를 끝내고 싶을 때 사용한다고 하네요
const onTokenValid = (validForm: TokenForm) => {
console.log(validForm);//Object token: "12345"
confirmToken(validForm); //confirmToken : useMutate함수 ! validForm을 인자로 넣어서 api호출 함수 작동!
};
세션 vs 토큰 vs 쿠키? 기초개념 잡아드림. 10분 순삭! (노마드코더 유튜브)
https://www.youtube.com/watch?v=tosLBcAX1vk
쿠키:
session ID를 전달하기 위한 매개체
session id뿐만아니라 다른 정보도 포함할 수 잇음
유저 정보 뿐만아니라 사이트의 kor버전 설정
sever에 req 요청 시 마다 쿠키 전달
서버가 브라우저에 쿠키 저장 후 해당 사이트 방문시마다 브라우저는 해당 쿠키 요청과 함께 보냄
only browser! no native app
sessionID
req 요청 할 때마다 session DB와 비교확인함
로그인 된 유저의 모든 정보 저장 --> 인스타그램의 여러 계정 중 특정 계정 로그아웃시키기 , 넷플릭스 여러 계정 중 현재 동시 접속 유저 몇명 인지 등을 구현 하는것 모두 db가 있어야함
로그인유무
token
서버가 기억하는 매우 이상한 텍스트 e.g) id card 같은 것
JWT
DB확인 하는게 아니고 정보확인을하고 SIGN해서 전달
TOKEN이 유효한가만 확인함
구현이 쉬움
e.g )코로나 qr 인증
강제로 로그아웃하거나 이런 기능은 안됨
유저에대해 관리할게 많거나 큰 플랫폼이면 사용하는데 제약이있음
파일을 누구나 볼 수 있음 암호화 필요
제약되는 는 점을 확실히 알아둬야함.
https://medium.com/@alysachan830/cookie-and-session-i-the-basic-concept-fea3d52bc8d3
iron session
# iron session : https://github.com/vvo/iron-session
- 데이터를 저장하기 위해 서명, 암호화된 쿠키를 사용하는 nodejs stateless 세션 도구
- JWT는 암호화되지 않고 서명이 되어있음
- 유저가 안에 있는 정보를 볼 수 없음
- 세션을 위한 백엔드 구축이 필요 없음
Next.js, Express, Nest.js, Fastify 및 모든 Node.js HTTP 프레임워크와 함께 작동합니다. 세션 데이터는 암호화된 쿠키("seals")에 저장됩니다. 그리고 당신의 서버만이 세션 데이터를 디코딩(decode)할 수 있습니다. 세션 ID가 없으므로 서버 관점에서 iron session을 "stateless"로 만듭니다.
npm i iron-session
```
import { withIronSessionApiRoute } from "iron-session/next";
export default withIronSessionApiRoute(NextApiHandler)
```
https://github.com/vvo/iron-session
GitHub - vvo/iron-session: 🛠 Next.js stateless session utility using signed and encrypted cookies to store data. Also works w
🛠 Next.js stateless session utility using signed and encrypted cookies to store data. Also works with Express, and Node.js HTTP servers - GitHub - vvo/iron-session: 🛠 Next.js stateless session util...
github.com
사용법 위 링크 참조 !
withIronSessionApiRoute도우미 함수로 객체로 감싸면 iron session이 알아서 요청 객체 안에 요청하는 세션 유저인req.session.user 를 담아줌 !옵션으로 쿠키이름, 패스워드 같이보내야함
핸들러를 도우미 함수로 감쌌기때문에 handler 함수 내에서 console.log(req.session)하면 확인 할 수있음
특정 토큰을 가진 유저를 찾고 req.session.user에 넣고 req.session.save 할꺼임 req.session.안에 이름은 우리가지은거임
로그인하고 토큰 후 개발자도구에서 cookie확인
브라우저가 받은 쿠키가 유용한지 테스트 해볼거임.
get user profile하기 !
우선 그 전에
https://github.com/vvo/iron-session#typing-session-data-with-typescript
api > user > me.tsx 생성후
위에 템플릿 복사 후에 필요없는걸 지우고 맨 아래 withHandler("GET")형태로 변형 후
console.log(req.session.user)하여 쿠키가 갖고있는 세션에 userId가 저장되어 있어 user정보를 가져올 수 있음
쿠키 특성상 새로고침할 때마다 서버에 요청하여 콘솔에 여러개의 console찍히는 것도 확인 !
모든 api url은 실제 백엔드 없이 개별적으로 동작하기 때문에
각 api 마다 type과 withIronSessionApiRoute config를 매번 설정해줘야함
profile 가져오기
저장된 쿠키 이용해서 가져오기
32자 랜덤 비밀번호 필요하신 분들은 아래 사이트에서 Length 32로 설정 후 복사해서 사용하시면 됩니다.
https://1password.com/password-generator/
새 api만들 때마다 작성 할 수 없으니
wrapper를 만들자
모든 API 경로 파일 또는 페이지에서 비밀번호와 쿠키 이름을 전달하지 않으려면 다음과 같이 래퍼를 만들 수 있습니다.
1withHandler 안에 넣기 -->지금 더 넣으면 복잡
2iron session의 wrapper만들기
create server > withSession.ts
1.api route에서 session을 받아오기 위한 function
2페이지를 rendering할 대 next.js의 serversiderendering에서 session
다시 돌아와서
confirm에서 확인 끝난 후에
res.json({ok:true} 작동 후
fe에서 api로부터 ok:tre을 받았다는것 다른 페이지로 전환해야한다는 뜻!
유저 인증 후에는 token지우기 !
인증 할 때마다 새로운 token을 갖는데 지우지 않으면 db에 로그인 할 때마다 token 쌓임
confirm.tsx
쉽게 authentication하는 법
NextAuth.js
Next.js에서 Authentication 구현을 도와주는 패키지이다. 입맛대로 바꾸기 쉽지 않다. 데이터베이스가 없어서 유저는 로그인 시킬 수 있지만 어떤 유저인지 알지 못함. prisma db 이용 할꺼면 따로 확인 해야 할 문서가 있다.
npm i next-auth
Getting Started
아래 예제 코드는 Next.js 앱에 인증을 추가하는 방법을 설명합니다.
```
// pages/api/auth/[...nextauth].js
import NextAuth from "next-auth"
import GithubProvider from "next-auth/providers/github"
export default NextAuth({
// Configure one or more authentication providers
providers: [
GithubProvider({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
// ...add more providers here
],
})
```
https://next-auth.js.org/getting-started/example
Next.js에 대한 인증
NextAuth.js는 Next.js 애플리케이션을 위한 완전한 오픈 소스 인증 솔루션입니다. Next.js 및 Serverless를 지원하도록 처음부터 설계되었습니다.
https://www.npmjs.com/package/next-auth
'코딩 > NextJs' 카테고리의 다른 글
당근마켓 :6 Authorization (0) | 2023.04.11 |
---|---|
당근마켓 4 :Refactoring (0) | 2023.03.30 |
당근마켓 3: database setup (0) | 2023.03.29 |
당근마켓 2:Tailwind css (0) | 2023.03.17 |
당근마켓 :1 NextJs, Tailwind setup (0) | 2023.03.15 |