기타 (Other)

[python] Flask 커스텀 헤더를 이용한 인증 예제

Kim MyeongOk 2025. 2. 11. 20:23

Server

from flask import Flask, request, jsonify
import functools

app = Flask(__name__)
API_KEY = create_api_key()

def create_api_key():
    """
    API Key 생성: 실행할때마다 값이 달라지니 주의필요
    (생성한 API Key는 ".env", ".json", ".yaml", "DB"에 저장해서 관리)
    """
    import uuid
    return str(uuid.uuid4())

def api_key_required(f):
    """
    API 키 인증을 위한 데코레이터
    """
    @functools.wraps(f)  # 원래 함수의 메타데이터를 유지
    def wrapper(*args, **kwargs):
        api_key = request.headers.get("Authorization")  # 헤더에서 API 키 추출
        if api_key != API_KEY:
            print(f"{api_key} != {API_KEY} -> {api_key != API_KEY}")
            return jsonify({"message": "Unauthorized"}), 401
        return f(*args, **kwargs)
    return wrapper

@app.route('/get_api_key', methods=['POST'])
def get_api_key():
    if request.headers.get("Authorization") == 'api_key request':
        return jsonify({"Authorization": API_KEY})
    else:
        return jsonify({"message": "Unauthorized"}), 401
    
@app.route('/kmo_test', methods=['POST'])
@api_key_required  # API 키 인증을 통과해야 접근 가능
def protected():
	# json_data = request.get_json()
    return jsonify({"message": "You have access to this protected resource."})

if __name__ == '__main__':
	app.run(host='0.0.0.0', port=88)

"""
[RESULT]

 * Serving Flask app '__main__'
 * Debug mode: off
2025-02-11 20:06:43,700	INFO	WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:88
 * Running on http://xxx.xxx.xxx.xxx:88
2025-02-11 20:06:43,700	INFO	Press CTRL+C to quit
2025-02-11 20:06:51,323	INFO	127.0.0.1 - - [11/Feb/2025 20:06:51] "POST /get_api_key HTTP/1.1" 200 -
2025-02-11 20:06:53,371	INFO	127.0.0.1 - - [11/Feb/2025 20:06:53] "POST /kmo_test HTTP/1.1" 200 -

"""

 

Client

import requests
import logging
import logging.basicConfig as Config

config(
    #filename='application.log', 
    level=logging.DEBUG, 
    format='%(asctime)s:%(levelname)s:%(message)s'
)

def server_post(url, data=None, json=None, **kwgrs):
    response = requests.post(url=url, data=data, json=json, **kwgrs)

    if response.status_code == 200:
        logging.info(f"Success, {response.json()}")
    else:
    	logging.error(f"Error, {response.status_code}")
        response = 'Error'
    return response

def get_headers():
    result = server_post(url="http://localhost:88/get_api_key", headers={"Authorization": "api_key request"})
    if result != 'Error':
        headers = result.json() # 서버에서 설정한 API 키
    return headers
    
if __name__ == '__main__':
    headers = get_headers()
    logging.info(f"headers: {headers}")
    logging.info('')
    result = server_post(url="http://localhost:88/kmo_test", headers=headers)
    logging.info(f"result: {result.json()}")
"""
[RESULT]
2025-02-11 20:06:49,273	DEBUG	Starting new HTTP connection (1): localhost:88
2025-02-11 20:06:51,325	DEBUG	http://localhost:88 "POST /get_api_key HTTP/1.1" 200 55
2025-02-11 20:06:51,325	INFO	Success, server_post()
2025-02-11 20:06:51,326	INFO	headers: {'Authorization': 'cd20432b-e5d1-47c5-b079-c09da77e72a9'}
2025-02-11 20:06:51,326	INFO	
2025-02-11 20:06:51,327	DEBUG	Starting new HTTP connection (1): localhost:88
2025-02-11 20:06:53,373	DEBUG	http://localhost:88 "POST /kmo_test HTTP/1.1" 200 58
2025-02-11 20:06:53,373	INFO	Success, server_post()
2025-02-11 20:06:53,374	INFO	result: {'message': 'You have access to this protected resource.'}
"""

 

추가해야할 부분

이대로 사용해도 보안장치가 생겨서 나쁘지 않으나, api-key를 받아올 때나, 확인할 때 키 값을 암호화해서 주고 받으면 취약점을 보완할 수 있을 것으로 보여짐.

암/복호화 방식에는 AES, DES, RSA 등이 있으니 마음에 드는 것을 선택해서 사용하면 됨.

'기타 (Other)' 카테고리의 다른 글

[python] PC 최적화 모델  (0) 2025.02.11
[python] PDF 텍스트 추출해서 TXT 파일로 만들기  (0) 2025.02.11
아파치 카프카  (0) 2025.01.21
[python] pandas  (4) 2025.01.09
[python] decorator 예제  (0) 2024.12.07