본문 바로가기
1인 개발 노트

직원이 매장 PC를 돌려쓸 때 로그인은 어떻게 짜야 하나 — 1년 굴려보고 정한 인증 구조

by 사장J 2026. 5. 29.

지난 1편에서 직원 출퇴근 웹앱을 직접 만들어 운영하는 이야기를 했습니다.
이번 편은 그 안에서도 한참 고민했던 로그인 구조 이야기입니다.

매장에서 직원 출퇴근 앱을 쓰다 보니, 일반적인 웹사이트 로그인하고는 조건이
달랐습니다. 매장 PC 1대를 직원 여러 명이 돌려쓰는 환경이어서요. 그래서
로그인은 "비밀번호 맞히기" 만 잘 해서는 안 되고, 다음 세 가지가 같이 필요했습니다.

  1. 누가 어디서 로그인 중인지 관리자가 볼 수 있어야 한다
  2. 의심스러운 접속(예: 퇴사자, 계정 공유)은 관리자가 즉시 끊을 수 있어야 한다
  3. 매장 PC에 로그인한 채로 자리를 뜨면 다음 사람이 그대로 출근을 찍을 수 있으니,
    일정 시간 무활동 시 자동 로그아웃되어야 한다

이번 글은 이 세 가지를 어떻게 풀었는지에 대한 운영 노트입니다. 코드는 최소한만,
"왜 이렇게 했나"에 집중하겠습니다.

1. 보통 웹사이트 로그인이 어떻게 짜이는지

보안 강의 영상이나 입문서를 찾아보면 대개 이 흐름입니다.

  1. 회원가입 시 비밀번호를 그대로 저장하지 않고 해시해서 저장한다 (bcrypt가 표준)
  2. 로그인 시 입력값을 해시해서 저장된 해시랑 비교한다
  3. 맞으면 로그인 토큰(JWT 같은 것)을 발급해서 쿠키로 심는다
  4. 이후 요청마다 그 토큰을 보고 "맞다, 너 로그인된 사용자 맞아" 라고 통과시킨다

저도 처음엔 그대로 따라 만들었습니다. 동작은 잘 됐어요. 문제는 그 다음입니다.

2. JWT만 쓰면 "강제 로그아웃"이 안 된다

어느 날 직원 한 명이 본인 아이디·비밀번호를 다른 직원에게 잠깐 빌려준 일이
있었습니다. 그 자체는 별일 아니었지만, 회수하고 싶을 때 막막했습니다. 비밀번호를
바꿔도 이미 로그인된 토큰은 만료 전까지 계속 살아 있기 때문입니다.

이게 JWT의 본질입니다. 토큰을 한번 서명해서 발급하면 서버는 그 토큰을 "기억하지
않습니다". 만료 시각까지는 그냥 통과시킵니다. 그래서 "관리자가 특정 사람을
즉시 끊는다" 가 구조적으로 안 됩니다.

해결 방법은 두 가지였습니다.

  • A안: JWT 안 쓰고 처음부터 DB 기반 세션으로
  • B안: JWT는 그대로 두고, DB에 세션 ID 테이블을 따로 둬서 검증할 때마다 같이 본다

A안은 갈아엎는 작업이라 미뤘고, B안으로 갔습니다. 결과적으로 잘 됐다고
생각합니다.

3. B안 — JWT + 세션 테이블 같이 쓰기

JWT에 jti 라는 일종의 일련번호(랜덤 16바이트)를 같이 박고, 같은 번호로
DB에 한 줄을 만듭니다. 이후 모든 요청은:

  1. 쿠키에서 JWT 꺼내서 서명 검증
  2. JWT 안의 jti로 DB에서 그 행이 있는지 확인
  3. 없으면 즉시 로그아웃 처리

이렇게 두 단계입니다. DB에서 그 행을 지우면 그 순간부터 그 토큰은 죽습니다.

세션 테이블에는 jti, 사용자 ID, IP, UA(브라우저/OS 정보), 로그인 시각, 마지막
활동 시각이 들어갑니다. 관리자 화면에서 "지금 누가 어디서 로그인 중인지"
표로 보이는 게 이 데이터입니다.

세션 목록 (관리자 화면)
─────────────────────────────────────────────────
직원      IP            브라우저       마지막 활동
직원A     192.168.1.21  Chrome/Win    3분 전
직원B     192.168.1.22  Chrome/Win    1시간 전
관리자    192.168.1.10  Chrome/Mac    방금
─────────────────────────────────────────────────
                          [세션 끊기 버튼]

"세션 끊기" 버튼은 결국 한 줄짜리 SQL을 호출합니다.

DELETE FROM sessions WHERE jti = '...';

그 순간 그 직원은 다음 요청에서 자동 로그아웃됩니다. 비밀번호를 바꿀 필요도 없습니다.

4. 5분 자동 로그아웃 — 매장 PC 돌려쓰는 환경의 핵심

여기까지가 보안 측면이고, 운영 측면에서 결정적이었던 건 5분 무활동 자동
로그아웃
이었습니다.

이게 없었을 때 사고가 종종 났습니다. 직원 한 명이 출근 찍고 화면 그대로
켜둔 채로 자리 떴고, 다음 직원이 와서 그대로 "출근" 버튼을 눌러버린 거죠.
그 결과 한 명은 출근으로 찍히지만 실제로는 다른 사람이 들어와 일하고
있었습니다.

해결은 단순했습니다. 클라이언트에서 5분 동안 마우스·키보드 입력이 없으면
자동으로 로그아웃 API를 호출
하게 했습니다. 그러면 세션 행이 지워지고
쿠키도 비워져서, 다음 사람은 무조건 다시 로그인부터 해야 합니다.

이게 완벽한 보안 장치는 아닙니다. 클라이언트가 끄는 거라 우회하려면 우회할 수
있습니다. 다만 매장에서 실제로 일어나는 실수의 거의 전부는 "악의 없는 부주의" 라,
이 정도면 충분히 잡힙니다.

5. 모바일 직원 차단

부가적으로, 직원 계정은 모바일에서 로그인 자체를 거부합니다. 브라우저가 보낸
User-Agent에 iPhone이나 Android 같은 문자열이 들어있으면 서버가 403을 반환합니다.

이건 1편에서 잠깐 나왔던 정책인데, 매장 PC에서만 출퇴근을 찍게 하기 위해서입니다.
관리자 계정은 모바일 허용(외근 시 관리 필요).

6. 1년 운영하며 알게 된 것

  • 보안 강의에서 가르치는 "JWT + bcrypt" 만으로는 매장 운영 환경의 요구를 못
    맞춥니다. "관리자가 즉시 끊을 수 있어야 한다" 라는 조건이 추가되는 순간 DB
    기반 세션 테이블이 필요합니다.
  • 자영업 매장처럼 PC를 여러 명이 돌려쓰는 환경은 자동 로그아웃이 본질입니다.
    보안 항목이 아니라 운영 항목으로 봐야 합니다.
  • 함수 한도(Vercel 무료 12개)에 묶여 있으니, cron으로 세션 청소를 안 돌리고
    로그인할 때마다 7일 넘은 본인 세션을 같이 지우게 했습니다. 작은 매장이라면
    이 정도가 가장 비용 효율이 좋습니다.

다음 글 예고

이 시리즈는 5편으로 계획되어 있습니다.

  • (3편) 급여명세서 모듈 — 시급제·월급제·주휴수당 자동 계산, 한 사람이 호점
    여러 개에서 일할 때 명세서 1장으로 통합하기
  • (4편) Vercel 함수 12개 한도 — 어떻게 통합해서 살아남는가
  • (5편) Cron과 푸시 알림 — 자정에 미퇴근 직원 잡아내는 자동화

각 편의 상세 기술 노트는 자매 사이트 「주간 소식」의 개발일지 시리즈에도 올라갑니다 → https://weekly-postman.vercel.app/posts/dev-attendance-web-2-auth


다 읽어주셔서 감사합니다. 비슷한 환경(매장 PC 공유, 직원 여러 명) 운영하시는
분 계시면 댓글로 어떻게 풀고 계신지 알려주세요. 다음 편에 참고하겠습니다.