목표 : Flask에 인증 기능을 추가합니다. (사용자의 비밀번호 암호화에 대하여)

 

 

 

2. Access Token 에 대하여

 - HTTP는 stateless이기 때문에 이전에 실행된 HTTP 통신들을 알 수 없음

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

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

 - access token 생성 방법

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

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

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

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

 

 

 

3. JWT의 구조

 

JWT의 Token을 생성하기 위해서 . 으로 구분해주고, 3개의 부문으로 구분됩니다.

Header.Payload.Signature

    ⓐ                  

 

ⓐ Header : hash algorithm, token type

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

  {
   "alg": "HS256",
   "typ": "JWT"
  }

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

     JWT를 통해 실제로 서버 간에 전송하고자 하는 데이터

     HTTP 메시지의 body와 비슷함

ⓒ Signature : secret key 등의 정보

     JWT가 원본 그대로임을 확인할 때 사용됨

     Base64URL 코드화된 header, payload, JWT Secret을 헤더에 지정된 암호 알고리즘으로 암호화하여 전송

     프론트엔드가 JWT를 백엔드 API로 전송하면 서버에서 JWT signature 부분을 복호화하여 서버에서 생성했는지 확인

     누구나 원본 데이터를 볼 수 있는 부분(Base64URL 코드화)이라 민감한 데이터는 저장하지 않도록 해야함

 

 

 

4. PyJWT 설치

$ pip install PyJWT

파이썬에서 JWT를 수현할 때 사용할 수 있는 라이브러리

 

 

 

5. models 로그인 부문 수정

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

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

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

# vim app001/models.py

# ...

import bcrypt
import jwt
#### JWT ####
app.config['JWT_SECRET_KEY'] = 'your_secret_key_for_jwt'
algorithm = 'HS256'

# ...

class User():
    def login(email, input_password):
        # bcrypt hash transfer
        password_bytes = input_password.encode('utf-8')
        # MySQL DB에 해당 계정 정보가 있는지 확인
        cursor = mysql.connection.cursor(MySQLdb.cursors.DictCursor)
        cursor.execute('SELECT * FROM users WHERE email = %s', [email])
        # 값이 유무 확인 결과값 account 변수로 넣기
        account = cursor.fetchone()
        if account:
            db_password_bytes = account['hashed_password'].encode('utf-8')
            check_password = bcrypt.checkpw(password_bytes, db_password_bytes)
            payload = {
                'email': account['email'],
                'hashed_password': account['hashed_password']
            }
            jwt_token = jwt.encode(payload, app.config['JWT_SECRET_KEY'], algorithm)
            return check_password, jwt_token.decode('utf-8')
        return False, False

 

 

 

6. 로그인 성공시 jwt token 제공

model에서 보내준 jwt token을 data의 access_token에 넣어서 보내줍니다.

jwt 시스템을 통한 인증 강화를 위해 추후 refresh_token을 함께 발행하기도 하는데, 일단 현재 실습에서는 access_token만 발행하는 것으로 하였습니다.

추후 refresh_token으로 확장하기 편하도록 하기 위해 아래와 같이 access_token이라고 따로 명시해서 보내줍니다.

@app.route('/user/auth', methods=['POST'])
def user_auth():
    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)

로그인 실패시에는 {result:401} 을 return합니다.

 

 

 

 

 

+ Recent posts