client: 일반 사용자가 아닌 소셜 로그인을 사용하는 사람
= 서비스를 만드는 "나"
resource owner: 소셜 로그인 기능을 제공하는 서비스를 사용하는 유저
= client가 받고자 하는 정보의 주인
resource server: 소셜 로그인 기능을 제공하는 곳
= client가 필요한 진짜 유저의 데이터를 가지고 있는 곳
1) 사용자가 소셜로그인 버튼을 클릭 시, 로그인하고자 하는 소셜의(카카오나 구글) 로그인페이지로 이동
2) 이 때 이 로그인 페이지로 가게 하기 위해, 서비스제공자와 소셜 사이에서의 이 상호작용 발생, 이 상호작용을 위해 서비스 제공자는 미리 OAuth
라는 서비스를 사용
3) 로그인을 성공 시, 소셜은 사용자의 페이지가 기존에 사용하던 서비스 페이지로 redirect
중개자의 역할을 가능하도록 해주는 서비스 **OAuth **
=> 사용자가 소셜로그인에 로그인 시, OAuth를 거쳐서 소셜에서는 "나"에게 Access Token을 제공하고, "나"는 이 토큰을 통해서 소셜에 접근할 수 있게 되고, 사용자에게 로그인 페이지를 제공!!!!
1) 등록
Client는 Resource Server 를 사용하기 위해서는 등록필요! =
Google Developer, naver Developer와 같은 사이트에서 진행합니다.
등록 완료 후 , Client 와 Resource Server 는 3가지를 공유
절대 코드에 노출되어지면 안되는 정보!!! = env 파일로 따로 관리해야함!
)2) 인증
로그인 하고자 하는 resource owner 즉, 데이터의 주인인 서비스 유저에게 승인필요.
버튼을 누르면, resource owner가 resource server에 로그인을 시도하는 창으로 이동
로그인 되어 있는 경우 : 소셜서비스(resource server)에서 로그인을 시도한 링크의 client ID를 점검
로그인 되어 있지 않은 경우 : 로그인을 진행
→ 로그인 완료 후에, 로그인을 시도한 링크의 redirect URL을 비교
- 소셜서비스(resource server)가 해당 URL을 가지고 있지 않다면 종료
→ 허용할 경우, 그 응답이 client에게 전달됩니다.
전달된 내용을 이용해 데이터 요청
서비스제공자인 "나"가 소셜서비스로 접속할때 가지고 간 주소링크에서 Authorizaion code와 clientID, client secret, redirect URL이 모두 일치하는지를 확인
일치하면 드디어 Access Token
을 발급
→ 발급된 access token을 가지고 소셜서비스(resource server)에서 resource owner에 대한 데이터를 받아옴
// goole-oauth
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-google-oauth20';
@Injectable()
export class JwtGoogleStrategy extends PassportStrategy(Strategy, 'google') {
constructor() {
// 1. 검증부
super({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.GOOGLE_CALLBACKURL,
scope: ['email', 'profile'],
});
}
// 2. 검증이 완료되면 실행
validate(accessToken: string, resfreshToken: string, profile: any) {
console.log(accessToken);
console.log(resfreshToken);
console.log(profile);
return {
// return 값은 context안의 request안 user로 들어감
email: profile.emails[0].value,
password: '1111',
name: profile.displayName,
phone: '01022222222',
address: '주소없음',
};
}
}
// naver-oauth
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-naver-v2';
@Injectable()
export class JwtNaverStrategy extends PassportStrategy(Strategy, 'naver') {
constructor() {
// 1. 검증부
super({
clientID: process.env.NAVER_CLIENT_ID,
clientSecret: process.env.NAVER_CLIENT_SECRET,
callbackURL: process.env.NAVER_CALLBACKURL,
});
}
// 2. 검증이 완료되면 실행
validate(accessToken: string, resfreshToken: string, profile: any) {
console.log(accessToken);
console.log(resfreshToken);
console.log(profile);
return {
// return 값은 context안의 request안 user로 들어감
email: profile.email,
password: '1111',
name: profile.name,
phone: profile.mobile,
address: '주소없음',
};
}
}
//kakao-oauth
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-kakao';
@Injectable()
export class JwtKakaoStrategy extends PassportStrategy(Strategy, 'kakao') {
constructor() {
// 1. 검증부
super({
clientID: process.env.KAKAO_CLIENT_ID,
clientSecret: process.env.KAKAO_CLIENT_SECRET,
callbackURL: process.env.KAKAO_CALLBACKURL,
scope: ['account_email', 'profile_nickname'],
});
}
// 2. 검증이 완료되면 실행
validate(accessToken: string, resfreshToken: string, profile: any) {
console.log(accessToken);
console.log(resfreshToken);
console.log(profile);
return {
// return 값은 context안의 request안 user로 들어감
email: profile._json.kakao_account.email,
password: '1111',
name: profile.username,
phone: '01022222222',
address: '주소없음',
};
}
}
=> 각 소셜마다 전체적인 사용 형태는 비슷하지만 profile내용이 전달되는 형태가 다르므로 확인 후 알맞게 사용해야함!