OAuth (소셜 로그인 연동)

JBoB·2023년 2월 13일
0
post-custom-banner

🐧Social Login 연동 (구글,네이버,카카오)

오늘 소셜 로그인 연동에 대해 배웠다. 정리 들어가기 전에 전에 정리했던 OAuth에 다시 한번 말하자면

OAuth

: 인터넷 사용자들이 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여 할

수 있는 공통적인 수단으로서 사용되는, 접근 위임을 위한 개방형 표준.

이다.

각종 브라우저 로그인 연동에 대해 정리하고자 한다.

  • OAPI 서비스 신청( 애플리케이션 등록)

  • redirectURL,callbackURL 요청정보(Scope) 설정

  • 클라이언트 아이디와 비밀번호 정보 등록 완료

수도코드를 적으면서 데이터의 흐름을 파악하면서 적어보자.

  1. 사용자가 브라우저를 통해 서비스 접근 하였을 때 백엔드에서 유저에게 로그인 페이지 제공
// auth.Controller.ts

@UseGuards(AuthGuard('naver'))
  // 가드를 통과해주려면 naver.strategy 를 작성해줘야한다.
  @Get('/login/naver') //로그인 페이지 EndPoint 작성 
  async loginGoogle(
    @Req() req: Request & IOAuthUser, //
    @Res() res: Response, //
  ) {
// OAuth 의 로직은 중복되기 때문에 auth.service에 하나의 함수를 만들어줘 합쳐준다.
// 이건 아래에서 !!
    this.authService.loginOauthService({ req, res });
		}
  1. 시크릿 코드 전달 후 정상일 경우 플랫폼에서 백엔드에게 AccessToken / refreshToken / profile 전달
// jwt-social.naver.strategy.ts
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-naver';

// passport-naver 모듈 설치
// yarn add passport-naver
// 도커 타입설정을 위한 모듈 설치
// yarn add --dev @types/passport-naver

export class JwtNaverStrategy extends PassportStrategy(Strategy, 'naver') {
  constructor() {
    super({
      clientID: process.env.NAVER_CLIENT_ID,
      clientSecret: process.env.NAVER_CLIENT_SECRET,
      callbackURL: 'http://localhost:3000/login/naver',
      scope: ['email', 'profile'],
    });
  }

  validate(accessToken, refreshToken, profile) {
    console.log(accessToken);
    console.log(refreshToken);
    console.log(profile);
  1. 백엔드API에서 회원가입을 검증하고 회원가입이 안되어있다면 회원가입 시킨뒤 로그인
@UseGuards(AuthGuard('naver'))
  // 가드를 통과해주려면 naver.strategy 를 작성해줘야한다.
  @Get('/login/naver') //로그인 페이지 EndPoint 작성 
  async loginGoogle(
    @Req() req: Request & IOAuthUser, //
    @Res() res: Response, //
  ) {
// OAuth 의 로직은 중복되기 때문에 auth.service에 하나의 함수를 만들어줘 합쳐준다.
// 이건 아래에서 !!
    //this.authService.loginOauthService({ req, res });
	
		//프로필을 받아온 다음, 로그인 처리해야 하는 곳
    // 1. 회원조회
    // 회원이 있으면 findOne 으로 찾아서 기다렸다가 유저 값을 반환한다.
    let user = await this.usersService.findOne({ email: req.user.email });
    // 회원이 없다면 회원등록하고 그 등록된 데이터를 유저에 담아준다.
    // 2. 회원가입이 안돼있다면? 자동회원가입
    if (!user) user = await this.usersService.create({ ...req.user });
    // 3. 회원가입이 돼있다면? 로그인하기
    //   (refreshToken, accessToken 만들어서 브러우저에 전송)
    this.authService.setRefreshToken({ user, res });

		}
  1. 로그인 완료 화면으로 페이지 이동(refreshToken 포함)
// auth Controller.ts

  @UseGuards(AuthGuard('google'))
  // 가드를 통과해주려면 google.strategy 를 작성해줘야한다.
  @Get('/login/google')
  async loginGoogle(
    @Req() req: Request & IOAuthUser, //
    @Res() res: Response, //
  ) {
    //프로필을 받아온 다음, 로그인 처리해야 하는 곳
    // 1. 회원조회
    // 회원이 있으면 findOne 으로 찾아서 기다렸다가 유저 값을 반환한다.
    let user = await this.usersService.findOne({ email: req.user.email });
    // 회원이 없다면 회원등록하고 그 등록된 데이터를 유저에 담아준다.
    // 2. 회원가입이 안돼있다면? 자동회원가입
    if (!user) user = await this.usersService.create({ ...req.user });
    // 3. 회원가입이 돼있다면? 로그인하기
    //   (refreshToken, accessToken 만들어서 브러우저에 전송)
    this.authService.setRefreshToken({ user, res });
    

			res.redirect(
      'http://localhost:5500/class/section11/11-06-login-google/frontend/social-login.html',

    );
  }
}
  1. 모듈이 잘 실행되게 하기 위해 app.module.ts 와 auth.module.ts 수정
// auth.module.ts

@Module({
  imports: [
    JwtModule.register({}),
    UsersModule, //
  ],

  providers: [
    JwtAccessStrategy,
    JwtRefreshStrategy,
			//추가 
    JwtNaverStrategy,
    AuthResolver, //
    AuthService,
  ],
  controllers: [
		//추가 
    AuthController, //
  ],
})
export class AuthModule {}

//app.module.ts

@Module({
  imports: [
       //생략
    ConfigModule.forRoot(),
    GraphQLModule.forRoot<ApolloDriverConfig>({
      driver: ApolloDriver,
      autoSchemaFile: 'src/commons/graphql/schema.gql',
      context: ({ req, res }) => ({ req, res }),
    }),
    TypeOrmModule.forRoot({
					//생략
    }),
  ],
  providers: [
    JwtRefreshStrategy, //
    JwtAccessStrategy,
		//추가
    JwtNaverStrategy,
  ],
})
export class AppModule {}

🐤Google OAuth 등록하는 방법!

  1. Google People API 사용 설정하기

들어가서 사용 버튼 클릭하기!

  1. **OAuth 동의 설정하기**

  1. UserType은 "외부" 선택 → 만들기 클릭하기.

  1. 앱 정보 창 설정하기 ( 필수입력들만 입력하기)

  1. People API 체크 후 업데이트 클릭 후 저장후 계속
  1. 테스트 사용자 본인 이메일 작성

  1. 콜백 URL 작성

  1. 클라이언트 ID 와 SERCET KEY 생성완료

//auth.controller.ts

@Controller()
export class AuthController {
  constructor(
    private readonly userService: UsersService, //
    private readonly authService: AuthService, //
  ) {}

  @UseGuards(AuthGuard('google'))
  @Get('/login/google')
  async loginGoogle(
    @Req() req: Request & IOAuthLoginUser, //
    @Res() res: Response, //
  ) {
		let user = await this.userService.findOne({ email: req.user.email });
    // 회원이 없다면 회원등록하고 그 등록된 데이터를 유저에 담아준다.
    // 2. 회원가입이 안돼있다면? 자동회원가입
    if (!user) user = await this.userService.create({ ...req.user });
    console.log(user);
    // 3. 회원가입이 돼있다면? 로그인하기x
    // (accessToken,refreshToken 만들어서 브라우저 전송)
    this.setRefreshToken({ user, res });
    res.redirect('http://localhost:5500/mainproject/frontend/login/index.html');
  }
}

//jwt.social.google.strategy.ts

export class JwtGoogleStrategy extends PassportStrategy(Strategy, 'google') {
  constructor() {
    super({
      clientID: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
      callbackURL: 'http://localhost:3000/login/google',
      scope: ['email', 'profile'],
    });
  }

  validate(accessToken, refreshToken, profile) {
    console.log(accessToken);
    console.log(refreshToken);
    console.log(profile);

    return {
      name: profile.displayName,
      email: profile.emails[0].value,
      password: '1234',
      phone_number: '010',
    };
  }
}

//app.module.ts 와 main.ts  컨트롤 설정하기 
profile
간절하고 치열하게 살자
post-custom-banner

0개의 댓글