인증 / 인가
인증 Authentication
- 특정 인증 요청(로그인, 이메일 인증 등)
- 사용자 식별을 하기 위해서 필요
- ex) 뉴스피드 프로젝트: 로그인
인가 Authorization
- 이미 인증된 사용자에게 특정 자원에 대한 접근 권한 부여
- 특정 사용자가 접근 할 수 있는 범위를 정하는 것
- ex) 뉴스피드 프로젝트: 본인이 작성한 글만 삭제 가능 등
- RBAC: 역할을 기준으로 권한을 부여(관리자, 일반 사용자)
- ABAC: 특정 속성을 기준으로 권한을 부여(나이, 위치, 시간 등)
Session 방식과 JWT 방식 차이
Session 방식
인증 성공 시 서버가 세션 id를 발급하여 클라이언트에 저장
Session 방식의 flow
- 사용자(클라이언트)가 서버에 로그인 요청
- 서버에서 인증 절차 수행
- 인증이 유효하면 서버가 세션 객체 생성하고
- 해당 정보를 서버의 세션 저장소에 저장
- 서버는 응답헤더의 set-cookie에 Session Id를 담아 클라이언트에게 전달
- 클라이언트는 이후 모든 요청에 쿠키(Session Id)를 담아서 서버에 전송
- 서버는 요청이 올 때마다 세션 저장소에서 Session Id에 해당하는 정보를 조회하여 사용자 인증 및 인가 처리
Session 방식의 단점 및 서버 부하 문제
- 서버 메모리 부담 (In-Memory 저장소 사용 시)
- 세션 정보를 서버 메모리에 저장하면 사용자 수가 많아질수록 메모리 부족 문제 발생
- → 서비스가 커지면 더 심해짐
- Redis 등 인메모리 DB 사용 시 비용, 메모리 문제
- Redis 같은 인메모리 DB를 세션 저장소로 사용하면 메모리를 많이 차지하므로 메모리 부족 및 운영 비용 증가 문제
- 관계형 DB에 세션 저장 시 DB 부하
- 세션 정보가 자주 저장/조회 되면서 DB에 과부하 발생, 성능 저하 문제
JWT 방식
- 인증 성공 시 서버가 JWT를 발급하여 클라이언트에 저장
- 무상태성(Stateless) 유지 가능
- 로드 밸런싱과 분산 시스템에 적합
- MSA(마이크로서비스 아키텍처)에 적합
JWT의 flow
- 사용자(클라이언트)가 서버에 로그인 요청
- 서버에서 인증 절차 수행
- 인증이 유효하면 Base64로 인코딩된 JWT(Access Token)를 클라이언트에 발급
- 클라이언트는 이후 요청 시 HTTP 헤더에 JWT 포함
- Authorization: Bearer <JWT토큰> 형식으로 전송
- 서버는 요청을 받을 때마다 JWT를 검증
- JWT에 담긴 사용자 정보(예: userId)를 활용해 인증 및 인가 처리
- DB 조회 없이 토큰 내용만 보고 사용자 식별 가능 (Stateless)
장점
- 서버 상태 유지 불필요(Stateless) → 서버 자원 절약, 확장성 향상
- 별도 저장소 불필요
- 분산 시스템, MSA에 유용
- 모바일 환경에 적합
- 빠른 인증 및 검증(Signature를 검증)
- 다른 서비스에서도 인증 공유 가능 (SSO - Single Sign-On에 활용)
단점
- 토큰 크기가 커지면 네트워크 부하 발생
- PAYLOAD(Base64 인코딩) → 쉽게 디코딩되므로 민감 정보 저장 금지
- 토큰 탈취 시 대처 어려움
- 해결 방법: HTTPS 사용, 짧은 만료 시간 설정, Refresh Token 활용
JWT 구현을 위한 필수 요소
1) JWT Secret Key (서명에 사용)
- 서버에서 서명을 생성하여 변조되지 않도록 보장해야 함
- 환경 변수로 관리하는 것이 보안적으로 안전
2) JWT 토큰 생성(generateToken)
- 로그인 성공 시 사용자 정보를 담은 JWT 토큰을 생성
- setSubject(username) -> 사용자 식별 값 설정
- setExpiration(Date(...)) -> 만료 시간 지정(1시간)
- signWith(HS256, SECRET_KEY.toByteArray()) -> HMAC SHA256 알고리즘으로 서명
3) JWT 검증(validateToken)
- 요청이 들어올 때 JWT가 유효한지 검증하는 과정 필요
- Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token) -> 토큰 파싱
- claims.expiration.after(Date()) -> 만료 여부 체크
- SignatureException -> 서명이 조작되었는지 확인
4) JWT에서 사용자 정보 추출(getUsernameFromToken)
- JWT에서 사용자 정보를 가져오는 기능 필요
- 토큰을 해석하여 subject(사용자 id 또는 이메일)를 추출
5) JWT를 HTTP 요청 필터에서 검증
- Spring Security에서 OncePerRequestFilter를 사용하여 모든 요청에서 JWT를 검증하도록 설정
- 요청에서 Authorization: Bearer <TOKEN> 헤더를 가져와서 토큰을 추출
- validateToken(token) -> 토큰 검증
- getUsernameFromToken(token) -> 사용자 정보 추출
6) Spring Security 설정에서 필터 적용
참고:
https://80000coding.oopy.io/1f213f10-185c-4b4e-8372-119402fecdd0
https://hstory0208.tistory.com/entry/JWT란-장단점과-Session-인증-방식과의-차이점을-알아보자
'TIL (Today I Learned)' 카테고리의 다른 글
Spring JWT 인증 과정 뜯어보기 🔑 | Spring Security 없이 구현하는 방법 (0) | 2025.02.25 |
---|---|
git clone 후 build.gradle 빨간 줄❓ 해결 방법‼️ (0) | 2025.02.24 |
[Spring] JPA 연관관계 매핑 확실하게 알아보기❗ (0) | 2025.02.14 |
[Spring] @Transactional을 어디에 붙여야 할까🤔❔ (0) | 2025.02.12 |
[Spring] spring.jpa.hibernate.ddl-auto 설정과 각 옵션 (0) | 2025.02.12 |