ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Flask] 로그인 기능 만들기 ft.JWT,Token,Cookie,hashlib
    programming/python 2022. 8. 29. 14:24

    목차

    사전 준비

    로그인 로직

    고민점(api로 get 요청하는 것, flask데이터로 주는 것 --개인 생각 주의)

    토큰과 세션과 쿠키

    사전 준비

    1. jwt 설치

    2. 아이디, 패스워드를 저장(패스워드를 hashlib를 통해 인코딩하여 저장한다)

    doc = {
        'name' : '관리자짱',
        'password' : hashlib.sha256('admin12'.encode('utf-8')).hexdigest()
        #hexdiget-16진수 문자열, digest-바이트문자열
    }
    db_user.inser_one(doc)

    로그인 로직

    1. 사용자의 아이디와 패스워드를 받아온다.

    2. 받아온 패스워드를 해시함수를 통한 암호화 값으로 만든다.

    3. db에서 유저를 찾는다.

    4. 유저가 있다면 jwt 토큰을 발급한다.

    5. 토큰을 암호화 하여 브라우저에 보낸다.

    6. 브라우저 쿠키에 토큰 값을 저장한다.

    7. 토큰이 있는 경우에서의 활동을 정한다.

     

    예제

    1. 사용자의 아이디와 패스워드를 받아온다.

    http://로컬서버/admin
    <form action="" method="POST">
        <input type="text" name="name" id="name">
        <input type="password" name="password" id="password">
        <input type="submit" onclick="getcookie()">
    </form>
    @app.route('/admin', methods=['POST'])
    def loginAdmin():
        name = request.form['name']
        password = request.form['password']
    #    pw_hash = hashlib.sha256(password.encode('utf-8')).hexdigest()
    #    user = db_user.find_one({'name':name, 'password': pw_hash})
    #    if user:
    #        payload = {
    #            'name' : name,
    #            'exp' : datetime.datetime.utcnow() + datetime.timedelta(seconds=100)
    #        }
    #        token = jwt.encode(payload, SECRET_KEY, algorithm = 'HS256')
    #        return jsonify({'result':'success', 'token': token})
    #    else:
    #        return jsonify({'result' : 'fail', 'msg':'check id or pw'})

    2. 받아온 패스워드를 해시함수를 통한 암호화 값으로 만든다.

    @app.route('/admin', methods=['POST'])
    def loginAdmin():
        name = request.form['name']
        password = request.form['password']
        pw_hash = hashlib.sha256(password.encode('utf-8')).hexdigest()
    #    user = db_user.find_one({'name':name, 'password': pw_hash})
    #    if user:
    #        payload = {
    #            'name' : name,
    #            'exp' : datetime.datetime.utcnow() + datetime.timedelta(seconds=100)
    #        }
    #        token = jwt.encode(payload, SECRET_KEY, algorithm = 'HS256')
    #        return jsonify({'result':'success', 'token': token})
    #    else:
    #        return jsonify({'result' : 'fail', 'msg':'check id or pw'})

    3. db에서 유저를 찾는다

    @app.route('/admin', methods=['POST'])
    def loginAdmin():
        name = request.form['name']
        password = request.form['password']
        pw_hash = hashlib.sha256(password.encode('utf-8')).hexdigest()
        user = db_user.find_one({'name':name, 'password': pw_hash})
        if user:
    #        payload = {
    #            'name' : name,
    #            'exp' : datetime.datetime.utcnow() + datetime.timedelta(seconds=100)
    #        }
    #        token = jwt.encode(payload, SECRET_KEY, algorithm = 'HS256')
    #        return jsonify({'result':'success', 'token': token})
    #    else:
    #        return jsonify({'result' : 'fail', 'msg':'check id or pw'})

     

    4. 유저가 있다면 jwt 토큰을 발급한다.(아이디의 정보를 넣고(원하는 데이터 넣으면 된다) 토큰을 얼마나 유지할 건지 시간도 넣는다)

    @app.route('/admin', methods=['POST'])
    def loginAdmin():
        name = request.form['name']
        password = request.form['password']
        pw_hash = hashlib.sha256(password.encode('utf-8')).hexdigest()
        user = db_user.find_one({'name':name, 'password': pw_hash})
        if user:
            payload = {
                'name' : name,
                'exp' : datetime.datetime.utcnow() + datetime.timedelta(seconds=100)
            }
            token = jwt.encode(payload, SECRET_KEY, algorithm = 'HS256')
    #        return jsonify({'result':'success', 'token': token})
    #    else:
    #        return jsonify({'result' : 'fail', 'msg':'check id or pw'})

    5. 토큰을 암호화 하여 브라우저에 보낸다.

    @app.route('/admin', methods=['POST'])
    def loginAdmin():
        name = request.form['name']
        password = request.form['password']
        pw_hash = hashlib.sha256(password.encode('utf-8')).hexdigest()
        user = db_user.find_one({'name':name, 'password': pw_hash})
        if user:
            payload = {
                'name' : name,
                'exp' : datetime.datetime.utcnow() + datetime.timedelta(seconds=100)
            }
            token = jwt.encode(payload, SECRET_KEY, algorithm = 'HS256')
            return jsonify({'result':'success', 'token': token})
        else:
            return jsonify({'result' : 'fail', 'msg':'check id or pw'})

    6. 브라우저 쿠키에 토큰 값을 저장한다.

    <form action="" method="POST">
            <input type="text" name="name" id="name">
            <input type="password" name="password" id="password">
            <input type="submit" onclick="getcookie()">
        </form>
        <script>
            $(document).ready(function () {
            })
            function getcookie(){
                console.log('asdf')
                $.ajax({
                    type: "POST",
                    url: "/admin",
                    data: { name: $('#name').val(), password: $('#password').val() },
    
                    success: function (response) {
                        if (response['result'] == 'success') {
                            $.cookie('mytoken', response['token']);
                            alert('로그인 완료')
                            //저는 로그인이 완료 되면 홈 화면으로 보냈습니다.
                            window.location.href = '/'
                        } else {
                            // 로그인이 안되면 에러메시지를 띄웁니다.
                            alert(response['msg'])
                        }
                    }
                }) 
            }

    7. 토큰이 있는 경우에서의 활동을 정한다.

    {% if name %}
    hi
    {% else %}
    bye
    {% endif %}

    참고 사이트. https://thalals.tistory.com/166

     

    고민점(api로 get 요청하는 것, flask데이터로 주는 것 --개인 생각 주의)

    api로 get 요청하는 것

    @app.route('/api/admin', methods=['GET'])
    def apiAdmin():
        token = request.cookies.get('mytoken')
        try:
            payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
            user_info = db_user.find_one({'name':payload['name']})
            return jsonify({'result':'success', 'name':user_info['name']})
        except jwt.ExpiredSignatureError:
            return jsonify({'result': 'fail'})
        except jwt.exceptions.DecodeError:
            return jsonify({'result': 'fail'})
    <script>
            $(document).ready(function () {
            getCookie()
            showContent()
            })
            let admin = false
            function getCookie(){
                $.ajax({
                    type: "GET",
                    url: "/api/admin",
                    data: {},
    
                    success: function (response) {
                        if (response['result'] == 'success') {
                    	admin = true
                        } else {
                            alert('일반사용자입니다.')
                        }
                    }
                }) 
            }
            function showContent(){
                let content = $('#content')
                let temp = ''
                if (admin){
                   temp = `<div>admin</div>`
                }else{
                   temp = `<div>not admin</div>`
                 .
                 .
                 .
                 }
            }
        </script>

    api로 get 요청하는 것의 장점(개인적 생각)

    1. 원하는 곳에서 get요청을 통해서 토큰이 유효한 지 확인, 사용이 가능하다.

    2. 요구하는 페이지가 많을수록 flask에서 보내는 것보다 가독성이 좋지 않을까 싶다.

    api로 get 요청하는 것의 단점(개인적 생각)

    1. 서버에 요청량이 flask에서 보내는 것보다 많아진다.

    flask데이터로 주는 것의 장점(개인적 생각)

    1. api로 get 요청을 통하는 것 보다 서버에 요청량이 적다.

    2. flask 문법을 통해 HTML에 활용이 가능하고 js 변수에도 할당이 가능하다.

    flask데이터로 주는 것의 단점(개인적 생각)

    1. 많이 사용하는 데이터의 경우 app.py의 코드량이 비례하여 많아질 것이다.

    토큰, 세션, 쿠키

    사용해보고 숙지하여 포스팅할 예정.

    참고할 블로그. https://tofusand-dev.tistory.com/89

    댓글

Designed by Tistory.