0부터 시작하는 Django 공부 - JWT와 인증 방식

Jaehong Lee·2022년 6월 29일
3
post-thumbnail

0 . Token 로그인 방식과 Session 로그인 방식

  • HTTP 프로토콜은 Stateless방식이다. request와 response로 통신이 이루어지며, 응답을 받으면 연결이 끊어지고, 통신이 종료되면 어떠한 상태도 남지 않는다. 그렇다면 HTTP에서는 로그인을 하고 재접속하면 로그인이 끊어질텐데 어떻게 로그인 상태를 유지할까?

  • 참조 ) https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-JWTjson-web-token-%EB%9E%80-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC

    • 쿠키 : 쿠키는 서버가 클라이언트의 브라우저에 저장하는 Data File로 Key-Value 형식이며, Header에 담겨져 전송되는 Data 전송 매개체이다. 서버는 Header의 set-cookie에 쿠키에 전달할 Data를 담아 전송한다. 만료 날짜가 없는 세션 쿠키는 사용자 컴퓨터의 메모리에 저장되며, 브라우저가 열려있는 동안 존재하고, 만료 날짜가 있는 영구 쿠키는 디스크에 저장되며, 삭제되거나 만료 날짜까지 존재한다
    • 세션 : 세션은 웹서버에 접속해 있는 상태를 하나의 단위로 보고 이 상태를 일정 시간동안 유지시키는 기술이다. 사용자가 로그인을 하면 세션이 생성되며 로그아웃하면 세션이 삭제된다. 이 세션은 서버의 세션 저장소에 저장된다
  • 0.1 Token 로그인 방식 ( JWT )

    • Token 로그인 방식은 로그인을 하면 서버에서 Token을 발급하여 HTTP 요청 헤더를 통해 클라이언트에 전달해준다. 이때 접속하기 위한 Access Token을 주는데, 이 Access Token은 중요하므로 유효 시간이 짧다. 이를 Refresh Token을 통해 재발급해주어 로그인 상태를 유지할 수 있다. 이 두 가지 Token은 쿠키와 Local Storage에 나누어 저장하는 편이 보안상으로 좋다
    • Token 로그인 방식은 세션을 생성하지 않는다. 서버의 클라이언트와의 상태를 저장/유지하지 않기에 Stateless 서버를 사용한다
    • DB에 접근하기 위한 사용자 정보는 사용자에게 전달해주는 payload에 담아서 보내준다
    • Header는 Token의 타입(typ)와 Signature 해싱 알고리즘 (alg)로 구성된다
    • Payload는 사용자 정보가 들어있다. 정보의 한 ‘조각’ 을 클레임이라고 부르고, 이는 Json(Key/Value) 형태의 한 쌍으로 이루어진다. 토큰에는 여러개의 클레임들을 넣을 수 있습니다
    • Verify Signature는 Token을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드가 들어있다. 즉, Header와 Payload를 인코딩한 값과 암호화한 값이 들어있다. 이는 Payload가 위변조되지 않았다는 사실을 증명하는 문자열이다
    • 서버는 Token을 발급해주고, 저장하지 않으며, 사용자 요청시 Token을 검증해준다
    • 토큰이 유효한지는 토큰 secret key로 판단하며, 이 secret key는 토큰 기능에 종속된다. 따라서 서버가 껏다 켜져도 유효기간이 끝나지 않은 토큰을 인증할 수 있다
    • secret key로 토큰이 유효한지 검사하고, 그 다음 payload의 사용자 식별 정보를 가지고 DB에서 식별 정보가 일치하는지 검사하는 순서다
    • 과정
      1. 사용자가 로그인 요청을 보낸다
      2. 서버에서는 계정 정보를 읽어 사용자를 확인하고, 사용자의 고유한 ID값을 부여하고 Payload에 정보를 넣는다
      3. Token의 유효기간을 설정합니다.
      4. SECRET KEY를 통해 암호화된 Access Token을 HTTP 응답 헤더를 통해 보낸다
      5. 사용자는 Access Token을 받아 쿠키나 local storage저장한 후, 인증이 필요한 요청마다 토큰을 HTTP 요청 헤더에 담아 보낸다
      6. 서버에서는 해당 토큰의 Verify Signature를 SECRET KEY로 복호화한 후, 조작 여부, 유효 기간을 확인한다
      7. 검증이 완료된다면, Payload를 디코딩하여 사용자의 ID에 맞는 데이터를 가져와서 전달한다
  • 0.2 Session 로그인 방식

    • Session 로그인 방식은 Session id를 통해 이루어진다. 로그인이 되면 사용자 정보가 담긴 세션이 서버의 메모리의 세션 저장소에 저장된다. Session id가 생성되어 이 id를 키로 사용한다
    • 이 쿠키에
    • 과정
      1. 사용자가 로그인을 하면 session id가 생성되고, 이 session id로 세션이 생성된다
      2. 서버에서 session id를 쿠키에 담아 set-cookie를 통해 클라이언트로 전송한다
      3. 사용자는 받은 session id가 담긴 쿠키를 저장한다
      4. 사용자가 session id가 담긴 쿠키를 요청할때 Header에 담아 전달
      5. 서버가 session id를 키로 메모리에서 사용자의 session 정보를 식별하고, 유료하다면 해당 요청에 대한 응답을 보낸다

1. JWT 사용하여 Token 로그인 방식 구현

  • https://dj-rest-auth.readthedocs.io/en/latest/installation.html#json-web-token-jwt-support-optional

  • JWT란? Json Web Token으로 Json 포맷을 이용하여 사용자에 대한 속성을 저장하는 Claim 기반의 Web Token이다. 즉, 인증에 필요한 정보들을 암호화시킨 Token이다

  • 라이브러리 설치

  • settings.py에 코드 추가

  • JWT 쿠키 : 사용자가 쿠키를 서버에 넘겨주어 서버가 해당 쿠키를 열어본다. 이 쿠키가 중요하므로 쿠키의 유효시간을 적게주고, 해당 유효시간을 갱신시켜주는 REFRESH 쿠키의 유효시간을 길게한다. 이 두 가지 쿠키는 각각 다른 곳에 저장한다

  • 이름만 좀 바꿔준다

  • 회원등록을 위해 DB를 mysql에 연결해주자. migrate도 실행한다

  • 접속해보자

  • 위에서 Raw Data를 복붙해서 Advanced Rest Client에 넘겨줘서 로그인해보자

  • 이렇게 Advanced Rest Client로도 로그인이 가능하다

  • 이렇게 Token이 전달된다

  • 현재 ARC로 회원가입을 할려고 하면 EMAIL 인증때문에 오류가 난다. 따로 서버를 지정안했기 때문이다. 따라서 인증을 none으로 설정한다

  • 로그인하면 Frontend server에서 token을 쿠키에 저장한다

  • local stoarge에 저장할수도 있다. 이를 통해 쿠키와 local stoarge에 나누어 Token과 Refresh Token을 따로 저장하는 방식도 있다

  • token을 https://jwt.io/ 사이트에 들어가서 입력하면 해당 token에 대한 정보를 볼 수 있다. verify signature는 암호화되있다

2. 로그인 유저만 접근할 수 있게 하기

  • permission_classes를 isauthenticated로 해서 로그인한 유저만 상품을 조회할 수 있게한다
  • 이를 조회할려면 Header에 쿠키를 담아서 보내야한다
  • Header name은 Authorization, value는 Bearer(띄어쓰기)jwt_token을 써줘야된다
  • 목록이 불러와진다. 이처럼 실제 개발에서는 로그인 유저와 비로그인 유저가 Data를 불러올때 넣어주는 것을 달리해야한다
  • 로그인하면 Backend server에서 바로 인식하는 것이 아닌, 위의 과정처럼 로그인 관련 Data를 넘겨줘야한다

3. Jwt Token 갱신

  • 아래 두 사이트를 사용할거다
  • exp가 만료시간, iat가 로그인 시간이다
  • Token 만료시간을 확인할 수 있다
  • 이렇게 Access Token이 만료되면 token/refresh에 "refresh" : refresh token을 담아서 보내주면 새 Access Token이 발급된다. 이 다음 Frontend server에 보내줘서 Access Token을 갱신해준다

4. 상품에 판매자 만들기

  • 판매자를 추가하여 User를 참조한다
  • 잘 동작한다. 허나, 판매자를 따로 지정안하고 자동으로 로그인 유저로 저장되게 해보자
  • seller를 입력받지 않게 한다. 허나, 입력받지 않으면 serializers는 commit=False와 같은 방식이 안되므로, create를 오버라이딩하여 save에서 seller에 request.user를 저장한다
  • 해당 코드가 활성화 되있으면 접속마다 Token을 보내야한다. 지금은 잠시 비활성화시킨다
  • 잘 저장된다
  • permission으로 권한을 조정할 수 있다. OrReadOnly는 로그인 안하면 읽기만 가능하게하고, 하면 읽기, 쓰기, 수정, 삭제 다 되게한다

5. 실습 - Review에 적용하기

  • model에 writer 추가
  • serializers에 필드를 설정해서 writer를 입력받지 않게 한다
  1. Viewset 사용
  • create method를 오버라이딩하여 writer를 따로 저장하게한다
  • 잘 저장된다
  1. APIView 사용
  • post 기능 정의 부분에 추가한다
  • 잘 저장된다

6. permisson

  • 이 코드로는 다른 로그인한 사용자가 다른 사용자의 게시물에 작업을 할 수 있다. 따라서 이를 막기위해서는 기능을 커스텀해야한다. 알아만 두자
profile
멋진 엔지니어가 될 때까지

1개의 댓글

comment-user-thumbnail
2022년 6월 29일

👍👍

답글 달기

관련 채용 정보