목표 : 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합니다.
'Development > Flask with Python' 카테고리의 다른 글
[Flask1.1][Mysql] Query Parameter 적용하기 예시 (0) | 2020.01.22 |
---|---|
[Solved][Flask1.1] jsonify 한글 인코딩 변경되어 비정상 출력 문제 해결 방법 2가지 (1) | 2020.01.22 |
[Flask1.1][Mysql] 실습 - 8 : 비밀번호 암호화하기 및 비밀번호check with bcrypt (0) | 2020.01.17 |
[Flask1.1][Mysql] 실습 - 7 : 회원가입 기능 구현하기 (0) | 2020.01.16 |
[Flask1.1][Mysql] 실습 - 6 : 로그인시 접속한 기기의 IP 정보 받기 & 로그인 페이지 리다이렉트 기능 추가 (0) | 2020.01.06 |