- 회원가입과 로그인 과정이 어떤 흐름으로 이루어지는가?
- 인증 상태 유지의 필요성과 구현 방법(세션, 토큰 등)
- 실제 워크플로우 다이어그램과 예제로 과정 이해
- 단순 기능 구현이 아닌 보안적 고려 사항까지 알기
- 실무에서 발생할 수 있는 문제상황, 대응법
회원가입(Registration) 워크플로우
회원가입은 새로운 사용자가 시스템에 계정을 등록하는 첫 단계임
올바른 회원가입 절차가 있어야 로그인과 인증이 올바르게 동작한다
1.회원가입의 전체 흐름
2. 디렉토리 구조 예시
- root/
- src/
- main/
- java/
- user/
- User.java
- UserRepository.java
- UserService.java
- UserController.java
- user/
- java/
- main/
- src/
3. 회원가입 예제
User.java
import java.time.LocalDateTime;
public class User {
private Long id;
private String email;
private String passwordHash;
private String nickname;
private LocalDateTime createdAt;
public User() {
}
public User(String email, String passwordHash, String nickname) {
this.email = email;
this.passwordHash = passwordHash;
this.nickname = nickname;
createdAt = LocalDateTime.now();
}
public String getEmail() {
return email;
}
public String getPasswordHash() {
return passwordHash;
}
}
UserRepository.java
import java.util.ArrayList;
import java.util.List;
public class UserRepository {
private List<User> users = new ArrayList<>();
public User findByEmail(String email) {
for(int i=0; i<users.size(); i++) {
User user = users.get(i);
if(user.getEmail().equals(email)) {
return user;
}
}
return null;
}
public void save(User user) {
if(user == null) {
throw new IllegalArgumentException("repository : 유저가 없음");
}
users.add(user);
}
}
UserService.java
public class UserService {
private UserRepository userRepository = new UserRepository();
public void register(String email, String rawPassword, String nickname) {
// 이메일 중복 검증
if(userRepository.findByEmail(email) != null) {
throw new IllegalArgumentException("이미 존재하는 이메일입니다.");
}
// 비밀번호 정책 검증
if(rawPassword.length() < 8) {
throw new IllegalArgumentException("비밀번호는 최소 8자리 이상이여야 합니다.");
}
// 비밀번호 해시 처리, BCrypt나 Argon2를 써야함
String passwordHash = Integer.toHexString(rawPassword.hashCode());
// 새로운 User 객체를 생성하고 저장함
User user = new User(email, passwordHash, nickname);
userRepository.save(user);
System.out.println("회원가입 성공");
}
}
* 비밀번호는 반드시 BCrypt, Argon2와 같은 강력한 해시 알고리즘을 써야한다
* 이메일 인증(Verification)을 통해 계정 활성화 절차를 두는게 안전함
* 비밀번호 분실 대비 기능(비밀번호 재설정 메일 발송)도 반드시 고려해야함, SSE
정리
| 단계 | 설명 |
| 입력 | 이메일, 비밀번호, 닉네임 |
| 검증 | 이메일 중복확인, 비밀번호 정책 검증 |
| 암호화 | 비밀번호를 해시처리하여 보관함 |
| 저장 | DB에 User 정보를 저장함 |
| 결과 | 회원가입 완료, 로그인 가능 |
로그인(Login) 워크플로우
회원가입된 사용자가 본인임을 증명하는 과정
1. 전체 흐름
사용자가 이메일, 비밀번호 입력 - > 서버에서 이메일로 사용자 조회
- > DB에서 사용자가 존재한다면 비밀번호 해시를 비교, 일치하면 로그인 성공, 토큰발급 / 일치하지 않으면 로그인 실패
- > DB에서 사용자가 존재하지 않는다면 로그인 실패
2. 로그인 예제
UserService.java
public class UserService {
private UserRepository userRepository = new UserRepository();
// 로그인 예제
public boolean login(String email, String rawPassword) {
User user = userRepository.findByEmail(email);
if(user == null) {
System.out.println("이메일 혹은 비밀번호가 틀렸음");
return false;
}
String password = Integer.toHexString(rawPassword.hashCode());
if(user.getPasswordHash().equals(password)) {
System.out.println("로그인 성공");
return true;
} else {
System.out.println("로그인 실패");
return false;
}
}
}
* 로그인 실패 횟수를 기록하여 계정 잠금 정책을 사용하기
* 로그인 성공시, 반드시 세션(Session) 또는 토큰(Token)을 발급하기
* 보안을 위해 로그인 로그를 남겨야하며, 이상 징후를 탐지하는게 중요함(짧은시간 내 다수의 로그인 실패 등등)
정리
| 단계 | 설명 |
| 입력 | 사용자가 이메일, 비밀번호 입력 |
| 조회 | DB에서 이메일로 사용자 찾기 |
| 검증 | 입력 비밀번호와 저장된 비밀번호의 해시 비교 |
| 결과 | 일치하면 성공, 불일치하면 실패 |
| 확장 | 세션 / 토큰 발급, 계정 잠금, 보안 로그 기록 |
인증 상태 유지의 필요성
인증 상태 유지는 HTTP 프로토콜의 속성(무상태성) 때문에 필수적이다
HTTP는 연결 유지가 보장되지 않는(connection agnostic) 무상태성 요청-응답 모델을 따른다
따라서 사용자가 한번 로그인에 성공했다고 해서 이후 요청에서도 자동으로 신원이 보장되는건 아니다
이러한 특성 때문에 세션 또는 토큰같은 메커니즘으로 "누가 요청했는가"를 매 요청마다 증명해줘야한다
1. HTTP의 속성에 대해
- 무상태성(Stateless) : 서버는 각 HTTP 요청을 독립적 사건으로 취급한다. 이전 요청의 맥락(로그인 여부, 사용자 정보)을 자동으로 기억하지 않는다.
- 연결 재사용과는 무관함 : HTTP 1.1에서 keep-alive가 있더라도, 이는 TCP 소켓 재사용일 뿐 응용 계층의 인증 상태를 보장하지 않는다. 로드밸런서가 요청을 다른 서버로 보낼수도 있고 연결이 끊어졌다가 재연결될 수도 있다.
- 분산 인프라의 특성 : 실제 서비스는 로드밸런서, 다수의 서버, 캐시, 프록시가 개입한다. 서버 로컬 메모리에만 의존하면 다른 서버로 라우팅되는 순간 인증 상태를 잃어버린다. 중앙 저장소(세션 스토어) 또는 클라이언트가 들고 다니는 토큰같은게 필요하다.
- 보안 경계의 일관성 : TLS 종료 시점, 역프록시, API 게이트웨이가 바뀌어도 요청 그 자체에 신원 증거가 포함되어 있어야 안전하다. 즉 매 요청 요청마다 신원 확인이 가능해야한다.
HTTP의 기본 철학은 "요청은 서로 무관하다" 라고 한다.
따라서 인증 상태는 프로토콜 바깥에서 별도 장치(세션, 토큰)로 명시적으로 유지해야함
2. 상태를 유지하는 대표 전략 두가지
(1) 세션 기반 방식(쿠키)
- 로그인 성공시 서버가 세션ID를 생성하고, 이를 쿠키로 클라이언트에 전달함. 이후 요청마다 쿠키로 세션을 찾아 사용자의 신원을 복원한다.
- 구성요소 : 세션 저장소(메모리, Redis, DB), 쿠키 설정(HttpOnly, Secure, SameSite)
- 장점 : 구현이 비교적 단순함, 서버가 세션을 제어하므로 즉시 강제 로그아웃이 가능함(세션 삭제)
- 단점 : 서버측에서 상태를 유지하므로 확장시 저장소 일관성이 필요함(공유 저장소 필수)
세션 쿠키 필수 옵션 예
| 옵션 | 설명 | 권장값 |
| HttpOnly | JS 접근 차단(XSS 완화) | true |
| Secure | HTTPS에서만 전송하기 | true |
| SameSite | 크로스 사이트 전송 제어하기 | Lax 또는 Strict(필요시 None + Secure) |
| Path | 쿠키가 전송될 경로 | / |
| Domain | 쿠키 적용 도메인 | 서비스 도메인으로 제한하기 |
* 확장성을 위해 다중 서버 환경에서는 스티키 세션 대신 공유 세션 저장소에 사용을 권장함(Redis 등)
(2) 토큰 기반 방식(JWT 등등)
- 로그인 성공시 서명이 포함된 토큰을 발급함. 클라이언트는 이후 요청마다 토큰을 Authorization 헤더로 전송하고, 서버는 서명 검증으로 신원을 확인하게 된다
- 구성 요소 : Access Token(짧은 수명), Refresh Token(긴 수명, 재발급용), 키 관리(비밀키 또는 공개키)
- 장점 : 서버가 인증 상태를 저장하지 않아서 수평 확장이 쉽다
- 단점 : 발급된 토큰은 유효기간동안 기본적으로 유효하다. 강제 만료가 필요하다면 블랙리스트나 토큰 버전 필드 등을 도입해야한다.
JWT의 핵심 클레임(외워야함)
| 클레임 | 의미 | 비고 |
| sub | 주체 ID(유저 식별자) | 필수에 가깝게 사용한다 |
| iss | 발급자 | 서비스 식별 |
| aud | 대상자 | 특정 클라이언트 제한 |
| exp | 만료시간 | 반드시 짧게 설정해야함(예 : 15분) |
| iat | 발급시간 | 토큰 생성 시각 |
| jti | 토큰 식별자 | 재사용 감지, 블랙리스트 키로 활용함 |
* Access Token은 짧게, Refresh Token은 회전(Rotation) 및 원장 기록으로 관리하는게 좋다고 한다
3. 기본 흐름 다이어그램
(1) 세션 기반 방식
클라이언트가 서버에게 로그인 이메일, 비밀번호 POST
서버에서 자격을 검증함
서버에서 세션스토어로 세션을 생성 요청, 세션스토어가 서버에게 전달
서버가 클라이언트에게 쿠키 set
클라이언트가 get요청 할때마다 서버쪽에 /me Cookie를 포함해서 줌, 서버가 세션스토어에서 세션을 조회한 뒤 데이터 반환
서버가 클라이언트에게 200ok
(2) 토큰 기반
클라이언트가 서버에게 로그인 이메일, 비밀번호 POST
서버가 자격 검증함
서버가 클라이언트에게 Access Token, Refresh Token 발급
클라이언트가 서버에게 GET요청 보낼때 Authorization를 위해 Access Token을 Bearer 형태로 보냄
서버가 토큰 서명 검증, 만료 확인함
서버가 클라이언트에게 200OK
클라이언트가 refreshToken을 POST 형태로 전송함
서버가 클라이언트에게 새 Access Token을 발급해줌
4. 세션 기반 인증 vs 토큰 기반 인증 비교
| 방식 | 설명 | 장점 | 단점 | 적용 사례 |
| 세션 기반 인증 | 서버 메모리에 인증 정보 저장 | 단순하고, 안정적임 | 서버 부하가 증가함 | 소규모 웹 서비스 |
| 토큰 기반 인증 | 클라이언트에 토큰 저장 후 매 요청마다 전달함 | 확장성이 높음 | 토큰 탈취시 위험함 | 모바일, 분산 환경 |
* HTTPS를 반드시 적용하여 세션 ID나 토큰이 탈취되지 않도록 해야함
* 토큰에는 민감한 정보를 직접 담지 말고, 필요한 최소한의 정보만 넣어야함
* 로그아웃시 세션 / 토큰을 무효화하는 절차를 반드시 포함해야한다
'Spring Boot > 유저 관리 기능' 카테고리의 다른 글
| 쿠키와 세션 기반 인증 : 쿠키와 세션 보안 설정 (0) | 2026.03.08 |
|---|---|
| 쿠키와 세션 기반 인증 : 세션 기반 인증 (0) | 2026.03.07 |
| 쿠키와 세션 기반 인증 : 쿠키의 개념과 특성 (0) | 2026.03.05 |
| 유저 기능의 이해, 인증 개념 : 인증(Authentication) (0) | 2026.03.02 |
| 유저 기능의 이해, 인증 개념 : 유저 기능의 필요성과 활용 (0) | 2026.02.28 |