Social Login

장여진·2022년 4월 17일
0

Social Login💻

1. social login을 진행하는 주체: client/resource owner/resource server

client: 일반 사용자가 아닌 소셜 로그인을 사용하는 사람
= 서비스를 만드는 "나"
resource owner: 소셜 로그인 기능을 제공하는 서비스를 사용하는 유저
= client가 받고자 하는 정보의 주인
resource server: 소셜 로그인 기능을 제공하는 곳
= client가 필요한 진짜 유저의 데이터를 가지고 있는 곳

2. 소셜 로그인 Flow

1) 사용자가 소셜로그인 버튼을 클릭 시, 로그인하고자 하는 소셜의(카카오나 구글) 로그인페이지로 이동
2) 이 때 이 로그인 페이지로 가게 하기 위해, 서비스제공자와 소셜 사이에서의 이 상호작용 발생, 이 상호작용을 위해 서비스 제공자는 미리 OAuth라는 서비스를 사용
3) 로그인을 성공 시, 소셜은 사용자의 페이지가 기존에 사용하던 서비스 페이지로 redirect

중개자의 역할을 가능하도록 해주는 서비스 **OAuth **
=> 사용자가 소셜로그인에 로그인 시, OAuth를 거쳐서 소셜에서는 "나"에게 Access Token을 제공하고, "나"는 이 토큰을 통해서 소셜에 접근할 수 있게 되고, 사용자에게 로그인 페이지를 제공!!!!

3. 소셜 로그인 구현방법

1) 등록
Client는 Resource Server 를 사용하기 위해서는 등록필요! =
Google Developer, naver Developer와 같은 사이트에서 진행합니다.

등록 완료 후 , Client 와 Resource Server 는 3가지를 공유

  • Client ID
    • 내가 구현 할 어플리케이션을 식별 할 수 있는 ID
  • Client Secret
    • 내가 구현 할 어플리케이션을 식별 할 수 있는 PW
      (절대 코드에 노출되어지면 안되는 정보!!! = env 파일로 따로 관리해야함!)
  • Authorized Redirect URL
    • 소셜 서비스가 인증이 가능하도록 권한을 부여하는 과정에서 그 인증코드(Authorized Code)를 전달해줄 경로

2) 인증
로그인 하고자 하는 resource owner 즉, 데이터의 주인인 서비스 유저에게 승인필요.

버튼을 누르면, resource owner가 resource server에 로그인을 시도하는 창으로 이동

  • 로그인 되어 있는 경우 : 소셜서비스(resource server)에서 로그인을 시도한 링크의 client ID를 점검

  • 로그인 되어 있지 않은 경우 : 로그인을 진행

→ 로그인 완료 후에, 로그인을 시도한 링크의 redirect URL을 비교

소셜서비스(resource server)가 해당 URL을 가지고 있지 않다면 종료

  • 같은 URL을 가지고 있지 않다면,  resource owner의 개인 정보를 client에게 제공해도 되는지 허용여부에 대한 메시지

→ 허용할 경우, 그 응답이 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내용이 전달되는 형태가 다르므로 확인 후 알맞게 사용해야함!


공부하며 작성하고 있는 블로그입니다.
잘못된 내용이 있을 수 있으며 혹시 있다면 댓글 달아주시면 감사하겠습니다 😊

0개의 댓글