현재 Django로 ERP 중에 있는데 고객이 로그인연장을 요구하였다.
그래서 세션을 통해 로그인을 연장해보려고 했다.
프로세스는 로그인을 하고 15분동안 세션이 유지가 되며 로그인연장 버튼을 누르지 않으면 자동으로 로그아웃되는 형식이다.(은행과 비슷하다)
* 참고로 로그인 기능은 이미 완료된 상태이다
위 사진의 오른쪽 상단의 시간연장 버튼을 누르면 시간이 15:00으로 초기화가 되야한다.
#settings.py
MIDDLEWARE = [
...
'django.contrib.sessions.middleware.SessionMiddleware',
...
]
django의 settings.py에는 위와 같이 session MIDDLEWARE가 등록되어 있기에 Import 하여 세션기능을 사용할 수 있다.
# settings.py
# Session 설정
SESSION_COOKIE_AGE = 900 # 15분
하단에 session 만료기한을 설정해준다. 초단위로 계산되므로 900초면 15분이다
# views.py
from django.shortcuts import redirect
from django.contrib.auth.decorators import login_required
from django.contrib import auth
from django.contrib.sessions.models import Session
from django.http import JsonResponse
...
## 로그아웃
@login_required
def logout(request):
auth.logout(request)
return redirect('account:login')
## 남은 세션 시간
@login_required
def remaining_session_time(request):
session_key = request.session.session_key
expire_date = Session.objects.get(pk=session_key).expire_date
remaining_time = expire_date - timezone.now()
return JsonResponse({'remaining_session_time':remaining_time.seconds})
## 세션 연장
@login_required
def extend_session(request):
if request.method == 'GET':
request.session.set_expiry(900)
return JsonResponse({'result':'success'})
...
views.py에서 위와 같은 함수들을 구성했다.
logout 함수는 단순히 로그아웃 후 로그인 화면으로 돌아가는 함수이다.
remaining_session_time 함수는 남은 세션시간을 계산하여 JsonResponse로 return 해준다.
extend_session 함수는 세션시간 종료시간을 현재시간을 기준으로 900초로 다시 계산한다.
extend_session 함수가 사용가능한 이유는 DB에 위와 같이 django_session 테이블이 만들어지는데 로그인할때마다 한 행이 만들어지고 expire_date라고 세션 종료시간이 기록된다.
extend_session 함수를 통해 이 expire_date를 다시 갱신하는 것이다.
// session.js
/* START ajax csrf token */
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
/* END ajax csrf token */
var time;
// 남은 세션시간
function remaining_session_time() {
$.ajax({
type: 'GET',
url: '/remaining_session_time/',
dataType: 'json'
}).done(function (data) {
time = data['remaining_session_time'];
});
}
// 세션 타이머
function session_timer() {
if (time > 0) {
time--;
var minute = Math.floor(time / 60);
var second = Math.floor(time % 60);
if (second < 10)
second = "0" + second;
$('#sesson_time').text(`${minute}:${second}`);
} else {
alert("세션이 만료되었습니다. 다시 로그인해주세요.");
clearInterval(timer);
window.location.href = "/logout/";
}
}
remaining_session_time(); // 남은 세션 시간 할당
timer = setInterval(session_timer, 1000); // timer 시작
// 세션 연장
$('#extend_submit').bind('click', function () {
$.ajax({
type: "GET",
url: "/extend_session/",
dataType: "json",
}).done(function (data) {
clearInterval(timer); // timer 삭제
remaining_session_time(); // 남은 세션 시간 할당
timer = setInterval(session_timer, 1000); // timer 재시작
}).fail(function (xhr, status, errorThrown) {
console.log("error");
});
});
위 코드를 보면 주석도 달았지만 윗부분은 Django와 ajax를 사용할 때 필요한 csrftoken 설정 코드들이다.
remaining_session_time 함수는 세션종료까지 남은 시간을 가져오는 함수이다
ajax로 views.py의 remaining_session_time 함수를 호출하여 return 값을 time변수에 할당한다.
session_timer 함수는 time함수에 할당된 시간(초)을 분과 초로 나누어 아이디가 session_time인 요소에 표현시킨다.
맨 밑쪽 코드는 jquery로 작성했는데 아이디가 extend_submit이라는 버튼을 클릭하면 views.py의 extend_session함수를 호출하여 세션을 연장시킨다.
js에서만 남은 세션 시간이 0초가 된다면 로그아웃되게 했기에 누군가가 악의적으로 script를 끄고 접속하면 이 기능이 작동안할까봐 확인을 했는데 django에서도 expire_time을 갖고 있으므로 설정시간 이후에 동작을 한다면 로그아웃 후 로그인페이지로 redirect 된다
수정(2023.09.17)
해당 기능은 로그인하면은 메인페이지로 이동이 되고, 서버에 session.js의 remaining_session_time함수를 통해 ajax로 세션시간을 바로 요청한다. 그러면 django에서는 views.py의 remaining_session_time함수를 통해 ORM으로 DB에서 값을 가져와 반환하는 것이다.
session에 관한 정보는 로그인하면 자동으로 DB에 쌓이는데 기능이 조금씩 쌓이고 서버가 무거워짐으로써 어쩔때는 session.js의 remaining_session_time함수가 요청할때 DB에 session 정보가 쌓이지 않아 의도한대로 이루어지지 않았다.
그래서 time변수를 기준으로 session_timer함수의 분기문에서 재귀조건을 추가하였다
// session.js
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie !== '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = cookies[i].trim();
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
var time = null;
function remaining_session_time() {
$.ajax({
type: 'GET',
url: '/remaining_session_time/',
dataType: 'json'
}).done(function (data) {
time = data['remaining_session_time'];
console.log(time); // for testing
});
}
function session_timer() {
if (time > 0) {
time--;
var minute = Math.floor(time / 60);
var second = Math.floor(time % 60);
if (second < 10)
second = "0" + second;
$('#sesson_time').text(`${minute}:${second}`);
} else if(time == null){
remaining_session_time();
session_timer();
}else{
alert('세션이 만료되었습니다. 다시 로그인해주세요.');
clearInterval(timer);
window.location.href = "/logout/";
}
}
remaining_session_time();
timer = setInterval(session_timer, 1000);
$('#extend_submit').bind('click', function () {
$.ajax({
type: "GET",
url: "/extend_session/",
dataType: "json",
}).done(function (data) {
clearInterval(timer);
remaining_session_time();
timer = setInterval(session_timer, 1000);
}).fail(function (xhr, status, errorThrown) {
console.log("error");
});
});
'python, 파이썬' 카테고리의 다른 글
Django "Reverse for ‘password_reset_confirm’ not found" Error (3) | 2024.09.14 |
---|---|
Github Action을 이용한 CI/CD (0) | 2024.06.30 |
JWT (2) | 2024.04.09 |
Django DB 자동 삭제 문제 발견 (0) | 2023.07.18 |