• 분류 전체보기 (512)
    • 개발남노씨(Coding Test) (6)
    • 고농축 백엔드 (17)
    • 재귀함수 DFS 총정리 (1)
    • 프론트엔드 날개달기:Vuejs.React (1)
    • 훈훈한 javascript (5)
    • 렛츠기릿 자바스크립트 (18)
    • 나도코딩 (1)
      • 웹 스크래핑 (1)
    • 프로그래머스(자바스크립트) (41)
      • LV.0(자바스크립트) (41)
    • 프로그래머스(자바) (121)
      • LV.0(자바) (56)
      • LV.1(자바) (41)
      • LV.2(자바) (23)
    • 프로그래머스(파이썬) (127)
      • LV.0(파이썬) (46)
      • LV.1(파이썬) (51)
      • LV.2(파이썬) (30)
    • 임시저장소 (31)
    • 프로젝트 (0)
    • 자바 알고리즘 (13)
      • 알고리즘 직빵 자바 문법 (10)
      • String(문자열) (3)
    • 파이썬 알고리즘 (93)
      • 알고리즘 직빵 파이썬 문법 (20)
      • 알고리즘 백준 (2)
      • 파이썬 알고리즘(사고력기르기) (6)
      • 파이썬 탐색 & 시물레이션 (8)
      • 이분탐색 & 그리디 알고리즘 (10)
      • 스택, 큐, 해쉬, 힙 (10)
      • 완전탐색과 DFS기초 (12)
      • DFS, BFS 활용 (19)
      • 동적계획법 (6)
    • 자바 (27)
      • Java TPC(생각하고, 표현하고, 코딩하고) (17)
      • Java (중요하고, 이해 안 되고, 어려운) (10)
    • 스프링 (5)
      • 스프링 MVC 패턴 2편 (5)
hELLO · Designed By 정상우.
@@#@@

기록용 블로그

고농축 벡엔드 11 - AccessToken과 Header의 Authorization// fetchUser()
고농축 백엔드

고농축 벡엔드 11 - AccessToken과 Header의 Authorization// fetchUser()

2023. 2. 13. 13:51
  @Query(() => Product)
  fetchProduct(
    @Args('productId') productId: string, //
  ) {
    return this.productService.findOne({ productId });
  }


"productId"인수는 "사용자"가 GraphQL API에서 직접 입력하는 부분입니다

-----------------------------------------------------------------------------
const profile = {
   name: "철수",
   age: 10,
   school: "다람쥐초등학교"
   name: "영희"
}


객체에서 key가 중복되면 value가 덮어쓰기가 된다.
console.log(profile)
{ name:'영희',  age: 10,  school:'다람쥐초등학교' }
------------------------------------------------------------------------------

 

 

 

 

stateful:상태를 가지고 있다

stateles:상태를 가지고 있지 않다.



백엔드서버에 있는 세션정보를 DB로 옮긴다.

백엔드는 stateless가 된다.

DB에 과부하 →파티셔닝

DB파티셔닝 
  수직 파티셔닝, 수평 파티셔닝 

세션 id == DB에 저장되는 id == 토큰 id



메모리를 활용한 데이터를 저장하는 방법: 

메모리 - 컴퓨터 컸다가 키면, 데이터가 지워짐, cpu의 RAM접근속도가 빠르다. - ex)Redis, Memcache
참고 → 디스크 - 데이터가 영구적으로 저장됨, cpu의 디스크접근속도가 느리다. 


-------------------------------------------------------------------------------------------------

JWT의 구조
Header(Http Header가 아님에 주의한다)
토큰에 대한 메타 데이터를 포함하고 있다.
(타입, 서명알고리즘, RSA...)

Payload
유저 정보, 만료기간, 주제 등

Verify Signature
JWT의 마지막 세그먼트는 토큰이 보낸 사람에 의해 서명되었는지, 다른 방식으로 변경되지 않았는지 
확인하는데 사용되는 서명이다. 

JWT 생성을 위한 모듈 4가지
@nestjs/jwt
-nestjs에서 jwt를 사용하기 위해 필요한 모듈

@nestjs/passport
-nestjs에서 passport를 사용하기 위해 필요한 모듈

passport 
-passport 모듈

passport-jwt
-jwt 모듈


-------------------------------------------------------------------------------------------------------
JWT사용 흐름

유저로그인 → 벡엔드 서버의 로그인 API에서 토큰 생성(Payload + Secret Text) → 백엔드 서버에 토큰 보관




JWT(AccessToken)활용한 로그인 데이터 저장
→JWT토큰을 (로그인)접근용도로 사용한다면 JWT를 AccessToken이라고 부르는 것이며,
→DB에 저장되는 id도 (로그인)접근용도로 사용한다면 AccessToken이라고 부른다. 
→따라서 어떠한 토큰이 접근용도로 사용될 때 해당 토큰을 AccessToken이라고 말한다.

{ email: aaa@naver.com 
  isLogin: true    
}




------------------------------------------------------------------------------

1. AccessToken을 받아오는 과정-----→Authentication(인증)
로그인정보가 백엔드 서버에 들어옴 로그인 정보가 맞는지 DB에 가서 확인한 후 맞으면 →로그인API에서 Json객체 전체를 암호화 → 토큰생성: 특수한 문자열형태(AccessToken) 
→ 벡엔드 서버에서 토큰(JWT)을 브라우저(사용자)에게 전달, 브라우저에 저장
→ 벡엔드 서버는 Secret Key(Text)를 보관하고 있다. 


2. 토큰에 근거해서 해당사용자가 맞는지 판단하는 과정-----→Authorization
사용자가 로그인하는 경우 request객체의 Http Header에 AccessToken(특수한 문자열)을 넣어서 로그인API로 전달
→그러면 클라이언트에서 온 JWT의 header와 클라이언트에서 온 JWT의 payload를 가져온 다음 
→서버에 보관되어 있는 secret Key로 Verify Signature를 만든 다음 
→클라이언트에서 온 JWT의 Verify Signature와 서버가 방금 전에 만든 Verify Signature를 비교하여 같으면 
→해당 사용자를 정당한 사용자로 판단하며
→정당한 사용자인 경우 DB에 가서 정상처리 후 브라우저(사용자)에게 response를 날림 
→정당한 사용자가 아닌 경우 브라우저에게 "에러"를 던짐,

 

 

 

 

인가(Authorization)
토큰을 복호화해서 해당 사용자가 맞는지 검증하기 - ex)유저조회(fetchUser)는 로그인 사용자만 접근가능

프론트엔드에서 벡엔드로 데이터가 패킷형태로 전달됨 → 해커에 의해서 토큰이 탈취 될 가능성이 있다. 
→따라서 http의 요청헤더(Request Headers)의 Authorization(키)에 "토큰(value)을 삽입"하여 벡엔드로 전달 
→"Authorization" : "Bearer + 토큰"
→Bearer: 관례

벡엔드는 해당 토큰을 복호화해서 철수 인지 확인

 

 

 

AccessToken과 Bearer인증 

 

인가(Authorization)의 흐름도

User가 로그인을 하면, 벡엔드 서버로 부터 토큰(JWT)을 받고, 

다시 User가 Bearer방식으로 Http Header에 JWT을 넣어서 fetchUser API를 요청하면

@UserGuards에서 검문을 한다.★★
--------------------------------------------------------------------------------------------

  @UseGuards(GqlAuthAccessGuard) //검문소
  @Query(() => String)
  fetchUser(
    @CurrentUser() currentUser: any, //
  ) {
    console.log('fetchUser 실행완료!!!');
    console.log('유저정보는?', currentUser); //validate() 함수에서 리턴한 유저정보 
    return 'qqq';
  }
}



---------------------------------------------------------------------------------------------

그러면 GqlAuthAccessGuard요청이 RestAPI요청으로 바뀌면서 myGuard를 찾고,
---------------------------------------------------------------------------------------------

//graphql API를 구현하는 경우 graphql API요청을 RestAPI 요청으로 바꾸기 위한 별도조치
import { ExecutionContext } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';
import { AuthGuard } from '@nestjs/passport';


export class GqlAuthAccessGuard extends AuthGuard('myGuard') {
  getRequest(context: ExecutionContext) {
    const ctx = GqlExecutionContext.create(context);
    return ctx.getContext().req;
  } //오버라이딩
}

----------------------------------------------------------------------------------------------------------

//Request Header에 Bearer를 넣어주는 방식 
//user.resolver.ts의 myGuard를 만들기 위한 전체로직
//jwt-access.strategy.ts
import { PassportStrategy } from '@nestjs/passport';
import { Strategy, ExtractJwt } from 'passport-jwt';

export class JwtAccessStrategy extends PassportStrategy(Strategy, 'myGuard') {
  constructor() {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), //req.headers.Authorization...
      secretOrKey: 'myAccessKey', //서명 //Docs에 나와있는 양식임. 외울필요X
    });
  }
  //인가에 실패하는 경우 에러발생



  //인가에 성공하는 경우 validate()실행(오버라이딩)
  validate(payload) {
    console.log(payload); // {email:c@c.com, sub: sdjhfsdkf-012093sd}
    return {
      email: payload.email,
      id: payload.sub,
    };
  }
}

validate() 메서드에서 return 할 때 req객체에 user객체에 email, id를 넣어준다.★ →req.user 

-------------------------------------------------------------------------------------------------------------------

import { createParamDecorator, ExecutionContext } from '@nestjs/common';
import { GqlExecutionContext } from '@nestjs/graphql';

//req.user에서 user정보를 받기 위한 나의 데코레이터 만들기 ---- @CurrentUser(일종의 함수)
//데코레이터==함수 만들기 
export const CurrentUser = createParamDecorator(
  (data, context: ExecutionContext) => { 
    const ctx = GqlExecutionContext.create(context); //graphqlAPI요청을 RestAPI요청으로 바꾸기 위한 작업 
    return ctx.getContext().req.user; //context에서 getContext를 한 다음, req정보에서 user정보만 뽑아와줘 
  },
);
----------------------------------------------------------------------------------------------------------------------

  @UseGuards(GqlAuthAccessGuard) //검문소
  @Query(() => String)
  fetchUser(
    @CurrentUser() currentUser: any, //
  ) {
    console.log('fetchUser 실행완료!!!');
    console.log('유저정보는?', currentUser); //validate() 함수에서 리턴한 유저정보 
    return 'qqq';
  }
}
-----------------------------------------------------------------------------------------------------------------------

 

저작자표시 비영리 변경금지 (새창열림)

'고농축 백엔드' 카테고리의 다른 글

고농축 벡엔드 13 - Google 로그인  (0) 2023.02.14
고농축 벡엔드 12 - RefreshToken + Cookie  (0) 2023.02.13
고농축 백엔드 docker-bind★★  (0) 2023.01.31
고농축 벡엔드 10 - TypeScript  (0) 2023.01.30
고농축 백엔드 9 - 객체, 약한결합, 강한결합, 의존성, 의존성주입  (0) 2023.01.25
    '고농축 백엔드' 카테고리의 다른 글
    • 고농축 벡엔드 13 - Google 로그인
    • 고농축 벡엔드 12 - RefreshToken + Cookie
    • 고농축 백엔드 docker-bind★★
    • 고농축 벡엔드 10 - TypeScript
    @@#@@
    @@#@@
    자바, 스프링, 알고리즘, 깃허브, 파이썬

    티스토리툴바