728x90

서비스에서 가장 기본적으로 제공되어야 하는 기능 중에선, 로그인한 사람들을 구분하고(인증), 그에 따른 추가적인 서비스를 제공하는 것이다(권한). 하지만 HTTP통신은 stateless이기 때문에 이전에 실행된 HTTP 통신을 알 수 없다. 

 

따라서 이러한 HTTP 통신의 특성을 해결하고, 계속적으로 해당 유저가 로그인 하고 있다는 사실을 인지하기 위해  JWT(Json Web Tokens) 라이브러리를 사용하여 토큰을 발행하여 호출되는 API인증을 체크한다.

 

 

Access Token 에 대하여

 - 로그인 정보를 HTTP 요청에 첨부해서 보내야 API 서버에서 로그인된 상태를 처리

   > 이런 로그인 정보를 담고 있는 것이 access token임

 - access token 생성 방법

   > 대표적으로 JWT 기술을 사용

   > JSON 데이터를 token으로 변환하는 방식

   > 유저가 로그인 요청을 하면, API 서버가 인증을 확인한 후, access token을 떨굼

   > 그 토큰을 쿠키 등에 저장했다가 요청할 때 사용

 

일반적으로 권한을 부여 받는데엔 access token만 가지고 있으면 된다. 하지만 access token을 만약 악의적인 유저가 얻어냈다면? 이 악의적인 유저는 자신이 00유저인것 마냥 서버에 여러가지 요청을 보낼 수 있다. 그렇기 때문에 access token에는 비교적 짧은 유효기간 을 주어 탈취 되더라도 오랫동안 사용할 수 없도록 하는것이 좋다.

Access token의 유효기간이 만료된다면 refresh token을 사용하여 새로운 access token을 발급 받는다. 이때, 유저는 다시 로그인 할 필요가 없다.

그러나 유효기간이 긴 refresh token마저 악의적인 유저가 얻어낸다면 큰 문제가 될 것이다. 그렇기 때문에 유저의 편의보다 정보를 지키는 것이 더 중요한 웹사이트들은 refresh token을 사용하지 않는 곳이 많다. 

 

 

JWT의 구조

- Header.Payload.Signature

1. Header : hash alorithm, token type

 ->  토큰 타입과 사용되는 해시 알고리즘을 지정

2. Payload: userid, password....등의 요청정보

-> JWT를 통해 실제로 서버 간에 전송하고자 하는 데이터. HTTP 메시지의 body와 비슷함

- iss: token 발행자

- sub: 사용자와 사용자 resource URI / 제목

- aud : 발급대상

- exp: 토큰이 만료되는 시간

- nbf: 토큰 활성화 시간

- iat: 토큰 발급 시간

- jti: token 구별을 위한 unique id

3. Signature: secret key등 포함

 ->JWT가 원본 그대로임을 확인할 때 사용. 프론트엔드가 JWT를 백엔드 API로 전송하면 서버에서 JWT signature 부분을 복호화하여 서버에서 생성했는지 확인. 누구나 원본 데이터를 볼 수 있는 부분(Base64URL 코드화)이라 민감한 데이터는 저장하지 않도록 해야함

 

토큰기반 인증 절차

  1. 클라이언트가 서버에 아이디/비밀번호를 담아 로그인 요청을 보낸다.
  2. 아이디/비밀번호가 일치하는지 확인하고, 클라이언트에게 보낼 암호화된 토큰을 생성한다.
  3. 토큰을 클라이언트에게 보내주면, 클라이언트는 토큰을 저장한다.
    • 저장하는 위치는 local storage, cookie, react의 state 등 다양하다.
  4. 클라이언트가 HTTP 헤더(authorization 헤더)에 토큰을 담아 보낸다.
  5. 서버는 토큰을 해독하여 "아 우리가 발급해준 토큰이 맞네!" 라는 판단이 될 경우, 클라이언트의 요청을 처리한 후 응답을 보내준다.

토큰기반 인증의 장점

  1. Statelessness & Scalability (무상태성 & 확장성)
    • 서버는 클라이언트에 대한 정보를 저장할 필요 없다 (토큰 해독이 되는지만 판단합니다)
    • 클라이언트는 새로운 요청을 보낼때마다 토큰을 헤더에 포함시킨다
      • 같은 토큰으로 여러 서버에서 인증 가능
  2. 안전하다
    • 암호화 한 토큰을 사용하고, 암호화 키를 노출 할 필요가 없기 때문에
  3. 어디서나 생성 가능하다
    • 토큰을 확인하는 서버가 토큰을 만들어야 하는 법이 없다.
  4. 권한 부여에 용이하다

 

JWT 사용하기

라이브러리 설치하기

pip install PyJWT

 

JWT 사용하기

예시

1
2
3
4
5
6
7
8
9
10
11
import jwt
 
json = {
    "id""justkode",
    "password""password"
}
encoded = jwt.encode(json, "secret", algorithm="HS256")  # byte-string
decoded = jwt.decode(encoded, "secret", algorithm="HS256")  # dict
 
print(encoded) #b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6Imp1c3Rrb2RlIiwicGFzc3dvcmQiOiJwYXNzd29yZCJ9.TKGlCElSgGthalfeTlbN_giphG9AC5y5HwCbz93N0cs'
print(decoded) #{'id': 'justkode', 'password': 'password'}
cs

jwt.encode()로 우선 jwt 인코딩을 실시. 첫 번째 파라미터로는 인코딩 하고자 하는 dict 객체, 두 번째 파라미터로는 시크릿 키, 세 번째 파라미터로는 알고리즘 방식을 삽입.

jwt.decode()는 jwt.encode()로 인코딩한 JWT의 디코딩을 실시. 첫 번째 파라미터로는 디코딩 하고자 하는 bytes-string 객체, 두 번째 파라미터로는 시크릿 키(단, 이는 jwt.encode() 에 넣은 시크릿 코드와 일치), 세 번째 파라미터로는 알고리즘 방식을 삽입.

 

 

실제 flask에 적용하기

Model 부분(DB에 실제로 로그인 진행하는 부분)

jwt secret key 설정 및 algorithm HS256 설정합니다.

예시에서는 payload에 password 정보를 넣었지만, 굳이 password를 넣을 필요는 없다.

payload와 app config, algorithm 값을 통해 jwt token을 생성하고, utf-8 string 으로 변경해줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import bcrypt
import jwt
#### JWT ####
app.config['JWT_SECRET_KEY'= 'your_secret_key_for_jwt'
algorithm = 'HS256'
 
# ...
 
class User():
    def login(email, input_password):
        # 중략........로그인 진행 시, DB에 아이디 비번 탐색하고 로그인진행하는 과정
            jwt_token = jwt.encode(유저의 아이디등 정보(이메일, 비번), app.config['JWT_SECRET_KEY'], algorithm)
            return check_password, jwt_token.decode('utf-8')
        return FalseFalse
cs

로그인 성공시 jwt token 제공

보내준 jwt token을 data의 access_token에 넣어서 보내준다. jwt 시스템을 통한 인증 강화를 위해 추후 refresh_token을 함께 발행하기도 하는데, 일단 access_token만 발행하는 것으로도 가능하다.

위의 DB 탐색과정에서, 올바른 로그인 과정이 아니면 false 값이 온다. 따라서 아래에서 {result:401} 을 return한다.

1
2
3
4
5
6
7
8
9
@app.route('api주소 ', methods=['POST'])
def user_login():
    if request.method == 'POST' and 'email' in request.form and 'password' in request.form:
        user_email = request.form['email']
        user_password = request.form['password']
        check_login, jwt_token = User.login(user_email, user_password)
        if check_login:
            return jsonify(result=200, data={'access_token':jwt_token})
    return jsonify(result=401)
cs

 

 

 

 

 

 

growingsaja.tistory.com/348?category=825126

 

[Flask1.1][Mysql] 실습 - 9 : jwt 활용하여 인증 기능 추가하기

목표 : Flask에 인증 기능을 추가합니다. (사용자의 비밀번호 암호화에 대하여) 2. Access Token 에 대하여  - HTTP는 stateless이기 때문에 이전에 실행된 HTTP 통신들을 알 수 없음  - 로그인 정보를 HTTP 요

growingsaja.tistory.com

fenderist.tistory.com/141

 

[python, flask] JWT(json web tokens) 인증 사용

[python, flask] JWT(json web tokens) 인증 사용 ​ JWT 라이브러리를 사용하여 token을 발행하여 호출되는 API인증을 체크 ​ JWT의 Token을 생성하기 위해서 .으로 구분되서 3개로 구성이 됩니다. - Header.Pay..

fenderist.tistory.com

justkode.kr/python/flask-restapi-3

 

Flask로 REST API 구현하기 - 3. JWT로 사용자 인증하기

REST API를 사용 하게 된다면, 사용자 인증 방법으로 제일 많이 사용하는 것이 JWT (JSON Web Token) 입니다. JWT에 대해 더 알고 싶다면. Velopert 님의 게시글을 참고 해 주세요! 우선 설치해야 할 것 일단 b

justkode.kr

 

728x90

+ Recent posts