Categories
웹개발/Spring
session attribute에 loginUserVO 담고 꺼내기 정리
세션에 로그인 사용자 정보를 담는 이유
로그인에 성공하면 그 사용자의 정보를 매 요청마다 DB에서 다시 조회하기는 비효율적이다. 그래서 로그인 시점에 필요한 사용자 정보를 객체(VO)로 묶어 세션에 담아 두고, 이후 요청에서 꺼내 쓴다. 이 객체를 흔히 loginUserVO(또는 loginVO, sessionUser)라 부른다. session attribute loginUserVO 패턴의 핵심은 "무엇을 담고, 어떻게 꺼내며, 어디까지 담아야 하는가"다.
세션은 키-값 형태로 값을 저장한다. session.setAttribute("loginUser", vo)로 담고, session.getAttribute("loginUser")로 꺼낸다. 단순해 보이지만 형변환, 키 관리, 담을 정보 범위에서 실무 함정이 숨어 있다.
세션 attribute 기본 동작
| 메서드 | 역할 | 주의점 |
|---|---|---|
| setAttribute(key, value) | 값 저장 | 같은 key면 덮어씀 |
| getAttribute(key) | 값 조회 | 반환 타입이 Object → 형변환 필요 |
| removeAttribute(key) | 특정 값 제거 | 해당 key만 삭제 |
| invalidate() | 세션 전체 폐기 | 로그아웃 시 사용 |
loginUserVO 담고 꺼내기
1. 로그인 시 VO 저장
로그인 성공 시 사용자 정보를 VO로 만들어 세션에 담는다. 이때 VO에는 화면·권한 판단에 필요한 최소 정보만 담는 것이 원칙이다.
// 로그인 성공 후
@PostMapping("/login")
public String login(String userId, String password, HttpSession session) {
MemberVO member = memberService.login(userId, password);
if (member == null) {
return "login/fail";
}
// 세션에 담을 전용 VO (민감정보 제외)
LoginUserVO loginUser = new LoginUserVO();
loginUser.setUserId(member.getUserId());
loginUser.setUserName(member.getUserName());
loginUser.setRole(member.getRole());
session.setAttribute("loginUser", loginUser);
return "redirect:/main";
}
DB 조회용 MemberVO를 통째로 담기보다, 세션 전용 LoginUserVO를 따로 두고 필요한 필드만 옮기는 편이 안전하다. 비밀번호, 주민번호 같은 민감 정보가 세션에 섞여 들어가는 사고를 막을 수 있다.
2. getAttribute 형변환과 null 처리
getAttribute는 반환 타입이 Object라, 꺼낼 때 원래 타입으로 형변환해야 한다. 또 로그인 안 한 상태면 null이 나오므로 반드시 null 체크가 필요하다.
// 세션에서 꺼낼 때
HttpSession session = request.getSession(false);
LoginUserVO loginUser = null;
if (session != null) {
Object obj = session.getAttribute("loginUser");
if (obj instanceof LoginUserVO) { // 형변환 전 타입 확인
loginUser = (LoginUserVO) obj;
}
}
if (loginUser == null) {
// 비로그인 처리 (리다이렉트 등)
}
instanceof로 타입을 먼저 확인하면 형변환 예외(ClassCastException)를 피할 수 있다. null 체크 없이 바로 .getUserId()를 호출해 NullPointerException이 나는 실수가 가장 흔하다.
attribute 키를 상수로 관리하기
"loginUser" 같은 키 문자열을 코드 곳곳에 직접 적으면, 오타 하나로 값을 못 찾고 디버깅도 어렵다. 키는 상수로 모아 관리하는 것이 좋다.
// 세션 키를 상수로 모아두기
public class SessionKey {
public static final String LOGIN_USER = "loginUser";
private SessionKey() {}
}
// 사용
session.setAttribute(SessionKey.LOGIN_USER, loginUser);
LoginUserVO user = (LoginUserVO) session.getAttribute(SessionKey.LOGIN_USER);
이렇게 하면 키 이름이 한 곳에서 관리되어 오타가 줄고, 나중에 키를 바꿀 때도 한 군데만 고치면 된다. 유지보수가 잦은 SI/SM에서 특히 도움이 된다.
JSP와 공통 처리에서 꺼내 쓰기
1. JSP에서 세션 값 사용
JSP에서는 EL로 세션 값을 간단히 꺼낼 수 있다. ${sessionScope.loginUser.userName} 형태다.
<%-- JSP : 로그인 사용자 이름 표시 --%>
<c:if test="${not empty sessionScope.loginUser}">
<span>${sessionScope.loginUser.userName}님</span>
<a href="${pageContext.request.contextPath}/logout">로그아웃</a>
</c:if>
<c:if test="${empty sessionScope.loginUser}">
<a href="${pageContext.request.contextPath}/login">로그인</a>
</c:if>
EL은 VO의 getter를 통해 값을 읽으므로, userName 필드에 getUserName()이 있어야 한다. not empty로 로그인 여부를 판단해 화면을 분기하는 패턴이 자주 쓰인다.
2. 공통 유틸로 꺼내기
매번 형변환·null 체크를 반복하지 않도록 공통 메서드로 묶으면 코드가 깔끔해진다.
public class LoginUtil {
public static LoginUserVO getLoginUser(HttpSession session) {
if (session == null) return null;
Object obj = session.getAttribute(SessionKey.LOGIN_USER);
return (obj instanceof LoginUserVO) ? (LoginUserVO) obj : null;
}
private LoginUtil() {}
}
// 사용
LoginUserVO user = LoginUtil.getLoginUser(request.getSession(false));
이렇게 한곳에 모으면 형변환과 null 처리가 일관되게 적용되고, 호출부는 간결해진다. 인터셉터, 컨트롤러, 공통 모듈 어디서든 같은 방식으로 꺼낼 수 있다.
세션에 담을 정보와 보안 주의점
- 민감 정보 제외 — 비밀번호, 주민번호, 카드번호 등은 세션에 담지 않는다. 세션 전용 VO로 필드를 선별한다.
- 최소 정보 원칙 — 화면 표시, 권한 판단에 필요한 정보만 담는다. 무거운 객체를 통째로 담으면 메모리 부담이 커진다.
- 권한 정보 신뢰 — 세션의 role 등 권한 정보는 서버가 설정한 값이어야 한다. 클라이언트가 보낸 값을 그대로 권한으로 쓰지 않는다.
- 로그아웃 시 정리 —
invalidate()로 세션을 폐기해 남은 정보가 재사용되지 않게 한다. - 직렬화 고려 — 세션을 파일·외부 저장소로 직렬화하는 환경이라면 VO가
Serializable이어야 한다.
FAQ
Q1. getAttribute로 꺼낼 때 왜 형변환을 하나요?
반환 타입이 Object라서다. 담은 원래 타입(예: LoginUserVO)으로 캐스팅해야 한다. 캐스팅 전 instanceof로 타입을 확인하면 예외를 피할 수 있다.
Q2. 세션에 MemberVO를 통째로 담으면 안 되나요?
동작은 하지만 권장하지 않는다. 민감 정보가 섞이거나 객체가 무거울 수 있다. 세션 전용 VO에 필요한 필드만 담는 편이 안전하다.
Q3. JSP에서 세션 값은 어떻게 꺼내나요?
EL로 ${sessionScope.loginUser.userName}처럼 꺼낸다. 해당 필드의 getter가 있어야 하며, not empty로 로그인 여부를 판단할 수 있다.
Q4. attribute 키를 매번 문자열로 써도 되나요?
가능하지만 오타 위험이 크다. 상수 클래스에 키를 모아 관리하면 오타가 줄고 유지보수가 쉬워진다.
Q5. 세션 VO에 Serializable이 필요한가요?
세션을 직렬화해 저장·복제하는 환경(일부 클러스터링, 세션 저장소)에서는 필요하다. 환경에 따라 다르므로 운영 구성을 확인한다.
정리
session attribute loginUserVO 패턴은 "로그인 시 필요한 정보만 담은 전용 VO를 세션에 저장하고, 꺼낼 때 형변환·null 체크를 거쳐 일관되게 사용하는 것"으로 요약된다. setAttribute로 담고 getAttribute로 꺼내되, 반환 타입이 Object라 캐스팅이 필요하고 비로그인 시 null이 나오므로 방어 코드가 필수다. 키는 상수로 모아 오타를 줄이고, 형변환·null 처리는 공통 유틸로 묶으면 코드가 깔끔해진다. 무엇보다 세션에는 민감 정보를 담지 않고 최소 정보만 두는 것이 보안의 기본이다. 직렬화나 다중 서버 환경 같은 운영 조건은 별도로 확인하고 적용하는 것이 안전하다.
'웹개발 > Spring' 카테고리의 다른 글
| Spring Security 4.x XML 설정 정리 (공공 SI 기준) (0) | 2026.07.05 |
|---|---|
| 인터셉터 로그인 체크와 login.do 리다이렉트 처리 정리 (0) | 2026.07.04 |
| Session 기반 로그인 HttpSession 동작 흐름 정리 (0) | 2026.07.03 |
| Spring @Transactional 기본 정리 (propagation, isolation, rollback) (0) | 2026.07.03 |
| Spring @RequestParam으로 요청 파라미터 받기 정리 (0) | 2026.07.02 |