[Flask] 3-7 로그인과 로그아웃

2023. 12. 2. 21:40Web/Flask

728x90

여러 사람이 사용하는 게시판 서비스를 만들 것 이기 떄문에

로그인, 로그아웃은 필수 기능이다

로그인과 로그아웃 기능을 만들어보자

 

로그인 폼

아래와 같이 로그인시 사용할 UserLoginForm을 만들자

[파일명: projects/myproject/pybo/forms.py]

username, password 필드를 추가하고 각각 필수 입력 항목으로 지정해 주었고

 username의 길이는 3~25자로 제한했다

 

로그인 라우팅 함수

로그인을 수행할 라우팅 함수를 다음처럼 작성해 보자

[파일명: projects/myproject/pybo/views/auth_views.py]
[파일명: projects/myproject/pybo/views/auth_views.py]

/login/ URL과 매핑되는 login 함수를 생성했다

login 함수는 signup 함수와 비슷하게 동작한다

POST 방식에는 로그인을 수행하고

GET 요청에는 로그인 화면을 보여준다

 

POST 요청에 의해 로그인 하는 과정을 알아보자면

폼 입력으로 받은 username으로 데이터베이스에 해당 사용자가 있는지를 검사한다

만약 사용자가 없으면 "존재하지 않는 사용자입니다 "라는 오류를 발생시킨다

사용자가 존재한다면 폼 입력으로 받은 password와 check_password_hash 함수를 사용하여

데이터베이스의 비밀번호와 일치하는지를 비교한다

사용자도 존재하고 비밀번호도 일치한다면 플라스크 세션(session)에 사용자 정보를 저장한다

세션 키에 'user_id'라는 문자열을 저장하고 키에 해당하는 값은 데이터베이스에서 조회한 사용자의 id 값을 저장했

 

세션에 대해 생각해 보면

session은 request와 마찬가지로 플라스크가 자체적으로 생성하여 제공하는 객체이다

브라우저가 플라스크 서버에 요청을 보내면 request 객체는 요청할 때마다 새로운 객체가 생성된다

 하지만 session은 request와 달리 한번 생성하면 그 값을 계속 유지하는 특징이 있다

 

따라서 세션에 사용자의 id 값을 저장하면 다양한 URL 요청에 이 세션에 저장된 값을 읽을 수 있다

예를 들어 세션 정보를 확인하여 현재 요청한 주체가 로그인한 사용자인지 아닌지를 판별할 수 있다

 

로그인 템플릿

로그인 템플릿을 만들어 보자

 로그인 폼에서 생성한 필드 2개(username, password)를 input 엘리먼트로 만들자

[파일명: projects/myproject/pybo/templates/auth/login.html]

템플릿에서 <로그인> 버튼을 누르면 form 엘리먼트가

POST 방식으로 현재 웹 브라우저의 주소 창에 표시된 URL인 /auth/login/로 요청될 것이다

 

로그인 링크

로그인할 수 있는 모든 준비를 마쳤으므로 내비게이션 바에 로그인 링크를 추가하자

내비게이션 바의 "로그인" 링크를 누르면 /auth/login으로 이동하며

아래와 같은 로그인 화면이 나타난다

만약 데이터베이스에 없는 username 또는 password를 입력하면 아래처럼 오류 메시지가 나타난다

username과 password를 제대로 입력하면 로그인을 수행한 다음 메인 화면으로 이동한다

 

로그아웃

하지만 로그인한 후에도 내비게이션 바에는 여전히 "로그인" 링크가 남아 있다

사용자의 로그인 여부는 "session에 저장된 값을 조사"하면 알 수 있다

단순히 session에 저장된 user_id값 여부로 로그인을 확인할 수도 있지만

여기서는 좀 더 일반적으로 사용할 수 있는 방법에 대해서 알아보자

 

로그인 여부 확인

 로그인한 사용자 정보를 조회하여 사용할 수 있도록 auth_views.py파일

load_logged_in_user 함수를 다음처럼 구현해 보자

[파일명: projects/myproject/pybo/views/auth_views.py]
[파일명: projects/myproject/pybo/views/auth_views.py]

여기서는 @bp.before_app_request 애너테이션을 사용했다

이 애너테이션이 적용된 함수는 라우팅 함수보다 항상 먼저 실행된다

앞으로 load_logged_in_user 함수는 모든 라우팅 함수보다 먼저 실행될 것이다

 

load_logged_in_user 함수에서 사용한 g는 플라스크의 컨텍스트 변수이다

이 변수는 request 변수와 마찬가지로 [요청 → 응답] 과정에서 유효하다

코드에서 보듯 session 변수에 user_id값이 있으면 데이터베이스에서 사용자 정보를 조회하여 g.user에 저장한다

이렇게 하면 이후 사용자 로그인 검사를 할 때 session을 조사할 필요가 없다

g.user에 값이 있는지만 확인하면 된다

g.user에는 User 객체가 저장되어 있으므로 여러 가지 사용자 정보(username, email 등)를 추가로 얻어내는 이점이 있다

 

로그인 로그아웃 표시하기

내비게이션 바를 아래와 같이 수정해보자

{% if g.user %} 코드를 추가하여 사용자의 로그인 유무를 판별할 것이다

[파일명: projects/myproject/pybo/templates/navbar.html] Copy
[파일명: projects/myproject/pybo/templates/navbar.html] Copy

g.user는 앞 단계에서 구현한 load_logged_in_user 함수로 생성한 사용자 정보값이다

로그인 했다면 g.user가 만들어진 상태이므로 username을 표시하고 "로그아웃" 링크를 보여 줄 것이다

반대로 로그인을 하지 않았다면 "로그인"과 "계정생성" 링크를 보여 줄 것이다

 

로그아웃 라우팅 함수

로그아웃을 구현하기 위해 auth_views.py 파일을 열어 /logout/ URL에 매핑되는 logout 함수를 다음과 같이 작성해보자

[파일명: projects/myproject/pybo/views/auth_views.py]

logout 함수에는 세션의 모든 값을 삭제할 수 있도록 session.clear()를 추가했다

 따라서 session에 저장된 user_id는 삭제될 것이고

앞에서 작성한 load_logged_in_user 함수에서 session의 값을 읽을 수 없으므로 g.user도 None이 될 것이다

 

로그아웃 링크

"로그아웃" 링크가 활성화될 수 있도록 내비게이션바를 수정하자

[파일명: projects/myproject/pybo/templates/navbar.html]

 

이제 로그인, 로그아웃 기능이 잘 실행되는지 확인해 보자

로그아웃을 누르면 네비게이션 바에는 다시 계정생성, 로그인 링크가 나타날 것이다

 

정상적으로 동작하였다

728x90