Algorithm study

Backend Class

로그인 방식

scale-up
: 컴퓨터의 성능( CPU, Memory 등)을 올려주는 것.
scale-out
: 똑같은 성능의 컴퓨터를 추가하는 것.
stateful
: session에 로그인한 유저 정보를 저장하여 가지고 있는 상태
stateless
: session에 로그인한 유저 정보가 없는 상태
Redis
: 메모리에 저장해두는 임시 데이터 베이스 ( 속도 문제 해결)

테이블 파티셔닝 이해 - 수평(샤딩)과 수직

session을 scale-out 해오지 못하는 문제점을 보완한 방법이며, 현재 많이 쓰이고 있는 방법 중 하나
로그인 정보를 백엔드 session에 저장하는 것이 아니라 DB에 저장하는 방법 => DB의 부하 초래
DB에 저장할 때는 메모리 기반의 session 방식에서 디스크 기반의 token(DB에 저장되어 있는 유저의 ID) 방식으로 바뀜

  • 수직으로 나누는 수직파티셔닝
  • 수평으로 나누는 수평파티셔닝(샤딩)

JWT(JSON Web Token) 토큰 방식

JWT 토큰은 유저정보를 담은 객체를 암호화를 통해 문자열로 만들어 암호화된 키(accessToken)를 브라우저로 전달

브라우저는 받아온 암호화된 키를 브라우저 저장소에 저장해두었다가 유저의 정보가 필요한 API를 사용할 때 API 요청과 함께 보내주게 되면, 해당 키를 백엔드에서 복호화해서 사용자를 식별한 후 접근이 가능하도록함

JWT 토큰에는 해당 토큰이 **발급 받아온 서버에서 정상적으로 발급을 받았다는 증명을하는 signature를 가지고 있음 → 사용자의 정보를 DB를 열어보지 않고도 식별할 수 있음

📍JWT 토큰의 구성
1. header : 토큰의 타입, 암호화시 사용한 알고리즘 정보
2. payload : 토큰 발행정보(누구인지, 언제 발행되었는지, 언제 만료될 것 인지)
3. signature : 토큰의 비밀번호
JWT토큰은 암호화 했지만 누구든 열어볼 수 있다는 것 -> 중요한 데이터는 JWT 토큰에 저장해서는 안됨

인증(Authentication)

로그인을 해서 accessToken을 받아오는 과정

인가(Authorization)

accessToken을 통해 복호화하여 유정정보를 검증하는 과정

암호화(양방향 암호화)와 해싱(단방향 암호화)

  • 양방향 암호화(Encryption) : 암호화와 복호화과정을 통해 송 ・ 수신 간 주고받는 메시지를 안전하게 암호화하고 평문으로 복호화하는 과정.
  • 단방향 암호화 : 해싱(Hashing)을 이용한 암호화 방식으로 양방향과는 다른 개념으로, 평문을 암호문으로 암호화는 가능하지만 암호문을 평문으로 복호화 하는 것은 불가능. 즉, 암호를 푸는 것은 불가

Hash(단방향 암호화)

해시에 의해 암호화된 데이터를 다이제스트(digest)

회원가입 API 구현

// users.resolver.ts

import { Args, Int, Mutation, Resolver } from '@nestjs/graphql';
import { User } from './entities/user.entity';
import { UserService } from './user.service';

@Resolver()
export class UsersResolver {
  constructor(
    private readonly userService: UserService, //
  ) {}

  @Mutation(() => User)
  createUser(
    @Args('email') email: string,
    @Args('password') password: string,
    @Args('name') name: string,
    @Args({ name: 'age', type: () => Int }) age: number,
      //@Args 를 통해 createUser 시 필요한 정보들을 받아오고, 받아온 데이터를 users.service.ts  파일로 넘겨줌
  ) {
    return this.userService.create({ email, password, name, age });
    //return 을 통해 프론트로 유저 정보 객체 결과 값을 보내줌
  }
}
// users.service.ts 

import { ConflictException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
  ) {}

  async create({ email, password, name, age }) {
    const user = await this.userRepository.findOne({ where: { email } });
    if (user) throw new ConflictException('이미 등록된 이메일입니다.');
    //중복 이메일 가입 방지 
    // if(user) throw new HttpException("이미 등록된 이메일입니다.", HttpStatus.CONFLICT) // 이렇게도 가능

    return this.userRepository.save({ email, password, name, age });
    // 넘겨받은 유저정보를 DB에 저장하고 `return`을 통해 `users.resolver.ts`
  }
}
// user.entity.ts

import { Field, Int, ObjectType } from '@nestjs/graphql';
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';

@Entity()
@ObjectType()
export class User {
  @PrimaryGeneratedColumn('uuid')
  @Field(() => String)
  id: string;

  @Column()
  @Field(() => String)
  email: string;

  @Column()
  // @Field(() => String) 비밀번호 노출 금지!!(graphql)
  password: string;

  @Column()
  @Field(() => String)
  name: string;

  @Column()
  @Field(() => Int)
  age: number;
}

Bcrypt

해싱의 대표적인 라이브러리

// users.resolver.ts

import { Args, Int, Mutation, Resolver } from '@nestjs/graphql';
import { User } from './entities/user.entity';
import { UsersService } from './user.service';
import * as bcrypt from 'bcrypt';
// as를 사용해 bcrypt 모듈의 모든 메서드를 사용

@Resolver()
export class UserResolver {
  constructor(
    private readonly userService: UserService, //
  ) {}

  @Mutation(() => User)
  async createUser(
    @Args('email') email: string,
    @Args('password') password: string,
    @Args('name') name: string,
    @Args({ name: 'age', type: () => Int }) age: number,
  ) {
    const hashedPassword = await bcrypt.hash(password, 10);
    //hash 메서드의 두 번째 인자는 salt . 원본 password를 10회 salt 시켜 주는 것
    console.log(hashedPassword);
    return this.userService.create({ email, hashedPassword, name, age });
  }
}
// users.service.ts

import { ConflictException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private readonly usersRepository: Repository<User>,
  ) {}

  async create({ email, hashedPassword: password, name, age }) {
    //resolver 파일에서 받아온 hashedPassword를 create 함수내에서 password로 바꿔서 사용하기 위해
    //`hashedPassword: password` 를 인자값
    const user = await this.userRepository.findOne({ where: { email } });
    if (user) throw new ConflictException('이미 등록된 이메일입니다.');
    // if(user) throw new HttpException("이미 등록된 이메일입니다.", HttpStatus.CONFLICT) // 이렇게도 가능

    return this.userRepository.save({ email, password, name, age });
  } //short hand property
}

HW

0개의 댓글