Programming/Python

(Python) 트위터 메인프레임만들기

armyost 2021. 5. 4. 06:29
728x90

소스 다운로드 : https://github.com/armyost/miniterWithPytest.git

 

armyost/miniter

flask를 사용한 백엔드 1. Contribute to armyost/miniter development by creating an account on GitHub.

github.com

 

app.py를 실행시키면 완성본이 실행됩니다.

기능은 회원가입, 팔로우/언팔로우, 트윗, 타임라인 입니다.

 

Python에서 Contoller는 다음과 같이 구현됩니다. 

@app.route("/signup",method=['POST'])
def signup():
	// 함수정의

 

Flask가 받은 Json을 파싱하여 사용하는 것은 간단하다.

@app.route("/signup",method=['POST'])
def signup():
	new_user 	= request.json						//request.json으로 객체생성 끝
    new_user['password']	= bcrypt.hashpw(     	//password 암호화 하여 저장하기 위함
    	new_user['password'].encode('UTF-8'),		//객체명['key'] 형태로 json데이터 사용
        bcrypt.getsalt()
    }

 

JWT(Json Web Token) 을 적용해서 서버사이드 세션을 적용해보자.

@app.route('/login',methods=['POST'])
    def login():
        credential=request.json
        email = credential['email']
        password = credential['password']
        user_credentail=get_user_id_and_password(email)

        if user_credential and bcrypt.checkpw(password.encode('UTF-8'),user_credential['hashed_password'].encode('UTF-8')):
            user_id=user_credential['id']
            payload={
                'user_id':user_id,
                'exp':datetime.utcnow()+timedelta(seconds=60*60*24)
            }   // 페이로드에 user_id와 현재 시간을 포함하여 credential 생성을 위해 jwt 모듈로 보낸다. 
            token = jwt.encode(payload,app.config['JWT_SECRET_KEY'],'HS256') //jwt 토큰을 생성한다. 사실 여기서 유효시간을 줄 수도 있다.

            return jsonify({
                'access_token':token.decode('UTF-8')
            })
        else:
            return '',401

 

if access_token is not None: //Httpie에서 Json으로 access_token이라는 토큰값을 보내줄 경우 라는 뜻이다.
            try:
                payload = jwt.decode(access_token,current_app.config['JWT_SECRET_KEY'],'HS256') //JWT_SECRET_KEY는 config.py 라는 컨피그 파일에 내가임의의로 입력해놓은 값이다.
            except jwt.InvalidTokenError:
                payload = None

 

 

 

세션토큰값이 없이(로그인을 하지 않은) 기능으로 접근할때 로그인을 강제하기 위해서는 @wraps와 decorated_function을 사용해야 한다. 

 

데코레이터란?

  • 어떤 함수를 받아 명령을 추가한 뒤 이를 다시 함수의 형태로 반환하는 함수.
  • 어떤 함수의 내부를 수정하지 않고 기능에 변화를 주고 싶을 때 사용한다.
  • 말그대로 다른 함수를 꾸며주는 함수.
def 데코레이터이름(func):  # 기능을 추가할 함수를 인자로 받아온다.
    def 내부함수이름(*args, **kwargs):
        기존 함수에 추가할 명령
        return func(*args, **kwargs)
    return 내부함수이름

위와 같이 함수를 인자로 받아 무언가를 추가하고 다시 함수로 반환한다.

 

데코레이터와 wrap으로 구현한 로그인 강제 함수는 다음과 같다.

def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        access_token=request.headers.get('Authorization')
        if access_token is not None:
            try:
                payload = jwt.decode(access_token,current_app.config['JWT_SECRET_KEY'],'HS256')
            except jwt.InvalidTokenError:
                payload = None

            if payload is None:return Response(status=401)

            user_id=payload['user_id']
            g.user_id=user_id
            g.user=get_user(user_id) if user_id else None
        else:
            return Response(status=401)

        return f(*args, **kwargs)
    return decorated_function

 

 

이제 각 기능들에 로그인을 강제할때는 다음과 같은 패턴으로 어노테이션을 해주면 된다.

@app.route('/timeline',methods=['GET'])
    @login_required
    def user_timeline():
        user_id=g.user_id
        .
        .
        .