Nest.js 소셜 로그인 - 구글 (2)

jegw·2023년 9월 17일
1

TIL

목록 보기
76/77
post-custom-banner

구글에서 profile, email, name등의 정보를 받아오는데 성공했다.
이제 토큰을 발급할 차례이다. 먼저 구글 이메일로 유저를 조회하고 이메일로 가입된 유저가 존재하면 토큰을 발급하여 로그인시키고, 없다면 회원가입을 시킨 후에 토큰을 발급할 것이다.

auth.service.ts

@Injectable()
export class AuthService {
  constructor(
    @InjectRepository(Member)
    private memberRepository: Repository<Member>,
    private jwtService: JwtService,
  ) {}

  async findByEmailOrSave(email: string, fullName: string, photo: string, provider: string): Promise<Member> {
    try {
      const foundMember = await this.memberRepository.findOne({ where: { email } });
      if (foundMember) return foundMember;

      const newMember = this.memberRepository.save({
        email,
        name: fullName,
        nickname: fullName,
        profileImage: photo,
        provider,
      });
      return newMember;
    } catch (error) {
      throw new Error('사용자를 찾거나 생성하는데 실패하였습니다');
    }
  }

  async googleLogin(req): Promise<any> {
    const { email, firstName, lastName, photo, provider } = req.user;

    const fullName = firstName + lastName;
    const member: Member = await this.findByEmailOrSave(email, fullName, photo, provider); // 이메일로 가입된 회원을 찾고, 없다면 회원가입

    // JWT 토큰에 포함될 payload
    const payload = {
      id: member.id,
      email: member.email,
      nickname: member.nickname,
      name: member.name,
      isAdmin: member.isAdmin,
      profileImage: member.profileImage,
    };


    return { access_token: this.jwtService.sign(payload, { expiresIn: process.env.JWT_ACCESS_EXPIRATION_TIME, secret: process.env.ACCESS_SECRET_KEY }) };
  }
}

auth.controller.ts

@Controller('auth')
export class AuthController {
  constructor(private readonly loginService: AuthService) {}

  @Get('google/login') // 구글 로그인으로 이동하는 라우터 메서드
  @UseGuards(AuthGuard('google'))
  async googleAuth() {}

  @Get('oauth2/redirect/google')
  @UseGuards(AuthGuard('google'))
  async googleAuthRedirect(@Req() req, @Res() res) {
    const token = await this.loginService.googleLogin(req);
    res.cookie('access_token', token.access_token, { httpOnly: true });
    res.redirect('/');
  }
}

이전 게시글에서는
@Get('oauth2/redirect/google')로 리디렉션 후 가드에서 validate메서드가 실행되고
req의 user객체에 구글에 로그인한 유저의 정보가 전달됐다. AuthService에 googleLogin과 findByEmailOrSave 메서드를 작성한다.

  • googleLogin : req객체를 인자로 받아서 로그인 or 회원가입을 시키고 토큰을 발급하여 반환
  • findByEmailOrSave : email로 회원을 조회하여 반환한다. 가입된 회원이없으면 가입시키고 반환

user 엔티티 수정

  • 소셜 로그인으로 회원가입을 시키는 경우엔 비밀번호가 필요없다.
    • password를 nullable 옵션으로 둔다.
  • provider 컬럼을 만든다. 소셜미디어로 가입된 회원인지 구분할 수 있고, 다른 소셜로그인을 추가할 경우 구분하기 위해서다.
@Entity()
export class Member {
  @PrimaryGeneratedColumn({ type: 'bigint' })
  id: number;

  @Column()
  email: string;

  @Column()
  name: string;

  @Column()
  nickname: string;

  @Column({ nullable: true })
  @IsOptional()
  password: string;

  @Column()
  profileImage: string;

  @Column({ nullable: true })
  @IsOptional()
  tel: string;

  @Column({ nullable: true })
  @IsOptional()
  address: string;

  @Column({ nullable: true })
  @IsOptional()
  subAddress: string;

  @Column({ default: false })
  isAdmin: boolean;

  @Column({ default: 'none' })
  provider: string;

  @CreateDateColumn()
  createdAt: Date;

  @UpdateDateColumn()
  updatedAt: Date;

  @DeleteDateColumn()
  deletedAt: Date;

 // 관계 설정 코드 생략
}

이렇게 우리 서비스에 소셜 로그인을 추가해보았다. 만약 구글에서 받은 정보 외에 추가 정보가 필수적인 서비스라면 추가 정보를 입력받는 과정을 추가하여 회원가입을 시킬 수 있다.

post-custom-banner

0개의 댓글