JWT 인증 방식으로 로그인 구현하기 (Flask)

코딩하는 어린콩·2021년 11월 2일
4

I learned

목록 보기
2/14

1. JWT

JWT(Json web Token)은 토큰 기반 인증 방식으로, 클라이언트의 세션 상태를 저장하는 게 아니라 필요한 정보를 토큰 body에 저장해 클라이언트가 가지고 있고 그것을 증명서처럼 사용합니다.

JWT의 기본 구성은 3가지로 나눠집니다.

  • header : JWT인 토큰의 유형이나 HMAC SHA256 또는 RSA와 같이 사용되는 해시 알고리즘이 무엇으로 사용했는지 등 정보가 담깁니다. Base64Url로 인코딩되어 있습니다.
  • Payload : 클라이언트에 대한 정보나, meta Data같은 내용이 들어있고, Base64Url로 인코딩되어있습니다.
  • Signature : header에서 지정한 알고리즘과 secret 키, 서명으로 payload와 header를 담습니다.

2. JWT의 위험성

JWT는 자체 내에 정보를 가지고 있기 때문에 클라이언트가 해독해 정보를 볼 수 있지만 받는 자가 secret 키를 알고 있어야만 수정이 가능합니다. 그리고 JWT 인증 방식을 채용할려면 기한 조절이 중요합니다. 만약 수명이 길면 해커에게 해독될 위험이 있고 수명이 짧다면 토큰이 만료될때마다 로그인을 다시 해줘야됩니다.

3. Flask로 구현해보기

일단 아주 간단하게 테스트하기위해서 저는 버튼 하나만 구현하였습니다.

<button onclick="loginClick()">로그인</button>

이 버튼을 클릭하게 되면 자동으로 로그인이 되게 코드를 만들었습니다.

버튼클릭이벤트 함수와 flask의 login부분을 보여드리겠습니다.

클릭이벤트
function loginClick(){
            $.ajax({
              type: "POST",
              url: "http://localhost:5000/login",
              data: {id:'Minsu', pw:'123456'},
              success: function(response){
                  console.log(response)
                  
              }
            })
        }

admin_id = "Minsu"
admin_pw = "123456"
SECRET_KEY = 'apple'

@app.route("/login", methods=['POST'])
def login_proc():
	print(request.form)
	input_data = request.form
	user_id = input_data['id']
	user_pw = input_data['pw']

	# 아이디, 비밀번호가 일치하는 경우
	if (user_id == admin_id and
			user_pw == admin_pw):
		payload = {
			'id': user_id,
			'exp': datetime.utcnow() + timedelta(seconds=60)  # 로그인 24시간 유지
		}
		token = jwt.encode(payload, SECRET_KEY, algorithm='HS256')

		return jsonify({'result': 'success', 'token': token})


	# 아이디, 비밀번호가 일치하지 않는 경우
	else:
		return jsonify({'result': 'fail'})

코드를 보시면 POST로 {id:'Minsu', pw:'123456'} 값을 받아 오게 됩니다. 받아온 id와 pw는 항상 admin_id와 pw랑 같게 설정을 해주었습니다. 그래서 payload의 id는 해당 토큰의 고유성을 식별하기 위한 정보이고 exp는 해당 토큰의 만료일자 입니다. 즉 payload를 설정하고 jwt.encode()함수에 우리가 설정한 payload와 JWT 토큰을 생성하는데 필요한 시크릿 값과 사용할 암호화방식을 선택하고 토큰을 생성하게 됩니다.
즉 비밀번호와 아이디가 일치하는경우 이 토큰값을 넘겨주고 아닌경우에는 result:fail을 보내주게 됩니다.

클라이언트의

function(response){
                  console.log(response) 
              }

이부분을 로그를 찍게되면

토큰값이 나오는것을 확인할 수 있습니다.
자 이제 토큰값으로 인증을 해보도록 하겠습니다.

function loginClick(){
            $.ajax({
              type: "POST",
              url: "http://localhost:5000/login",
              data: {id:'Minsu', pw:'123456'},
              success: function(response){
                  console.log(response)
                  let access_token = response['token']
                  console.log((access_token))
                   if (response['result'] == 'success') {
                        $.cookie('mytoken', response['token'], {path: '/'});
                        window.location.replace("/mainPage")
                    } else {
                        alert(response['msg'])
                    }
              }
            })
        }

cookie에 토큰값을 저장하는 코드를 작성한후에 mainPage으로 페이지 이동을 시킵니다.
따라서 app.py의

@app.route('/mainPage')
def home2():
	token_receive = request.cookies.get('mytoken')
	try:
		payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256'])
		print(payload)
		return render_template('main.html')
	except jwt.ExpiredSignatureError:
		return redirect("http://localhost:5000/")
	except jwt.exceptions.DecodeError:
		return redirect("http://localhost:5000/")

이부분이 동작하게 되는데
cookie에 저장되어있는 token값을 꺼낸뒤에 token_receive에 저장합니다
그리고 payload = jwt.decode(token_receive, SECRET_KEY, algorithms=['HS256']) 이 부분에서 token값을 다시 id값으로 바꿔줍니다 이때 만약 만료된 토큰이거나 가지고 있는 토큰이 문제가 있다면 다시 버튼이 있는 페이지로 redirect시켜줍니다.

JWT 인증 방식이 여기서 끝은 아니지만 오늘 큰 틀이라도 배운것 같아서 기분이 좋네요...

0개의 댓글