- 세션 기반 인증에서 권한 정보가 어떻게 저장되고 활용되는가
- 토큰 기반 인증(JWT)에서 권한 정보가 포함되는 방식
- 세션과 토큰 기반 인가 구현의 장단점
- 실제 애플리케이션에서 권한 정보를 안전하게 관리하는 방법
- 사례를 통해 실무에서 발생할 수 있는 문제 예방법
세션 기반 인가 구현
1. 세션에 권한 정보 저장
세션 기반 인증에서는 사용자가 로그인하면 서버는 세션 객체(Session Object)를 생성함
이 객체 안에는 사용자의 정보와 함께 권한(Role/Permission) 정보도 함께 저장할 수 있다
- 서버 메모리 또는 Redis같은 세션 저장소에 보관함
- 클라이언트는 JSESSIONID 같은 세션ID 쿠키만 전달한다
- 서버는 세션ID를 바탕으로 사용자와 권한 정보를 복원함
세션 저장 구조 예시
- SessionStore
- sessionId: abc123
- userId: B1uffer
- roles: ["USER", "EDITOR"]
- lastAccessTime: ...
- sessionId: abc123
2. 예제(세션 기반)
// HttpSession을 활용한 권한 확인 예시
public void updatePost(HttpSession session, Post post, String newContent) {
// HttpSession에서 가져옴
User user = (User) session.getAttribute("user");
if(!post.getOwner().equals(user.getUsername()) && !user.getRoles().contains("ADMIN")) {
throw new SecurityException("수정 권한이 없습니다.");
}
post.setContent(newContent);
}
// 비교를 위해
public void update(Post post, String newContent) {
// 인증 로직
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserPrincipal principal = (UserPrincipal) authentication.getPrincipal();
// 작성자 본인이거나 관리자일 때 업데이트 가능
if(!post.getOwner().equals(principal.getUsername()) || !principal.isAdmin()) {
log.info("게시글 수정 실패");
throw new IllegalArgumentException("수정 권한이 없습니다.");
}
post.setContent(newContent);
log.info("게시글 수정 완료");
}
세션에 저장된 사용자 정보에서 권한을 조회하고 검증한다
* 세션은 서버 자원을 소모하므로 확장성(Scalability)이 떨어질 수 있음
* 세션 저장소를 외부 서버 캐시(Redis, Memcached)로 구성하면 확장성 문제를 완화할 수 있음
* 세션이 만료되면 자동으로 권한도 무효화되게끔 해야한다
3. 정리
| 특징 | 설명 |
| 저장 위치 | 서버 메모리 또는 외부 세션 저장소 |
| 전달 방식 | 클라이언트는 세션 ID 쿠키만 전달함 |
| 장점 | 구현이 단순함, 서버에서 중앙 집중 관리가 가능함 |
| 단점 | 서버 확장시 세션 동기화 필요 |
토큰 기반 인가 구현(JWT)
1. JWT에 권한 정보 포함하기
JWT(Json Web Token)는 인증 정보를 클라이언트가 직접 보관하는 방식임
서버는 JWT를 검증하기만 하면 되므로 확장성이 높다
JWT 구조는 Header.Payload.Signature로 이루어져 있으며 Payload에 관한 정보(roles)를 포함시킬 수 있다
{
"sub": "B1uffer",
"roles": ["USER", "EDITOR"],
"iat": 1737072000,
"exp": 1737075600
}
2. 예제(JWT 기반)
build.gradle에 의존성 추가
// JWT 의존성 추가
implementation 'io.jsonwebtoken:jjwt-api:0.12.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5'
JwtUtils.java
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import javax.crypto.SecretKey;
public class JwtUtils {
private static final String SECRET = "mysecretkey123";
private static final SecretKey KEY = Keys.hmacShaKeyFor(SECRET.getBytes());
public static Claims parseToken(String token) {
return Jwts.parser()
.verifyWith(KEY)
.build()
.parseSignedClaims(token)
.getPayload();
}
}
JwtAuthorizationService.java
import com.b1uffer.sessiontest.entity.Post;
import com.b1uffer.sessiontest.security.jwt.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
@Slf4j
@Service
@NoArgsConstructor
public class JwtAuthorizationService {
// JWT를 활용한 인가 구현 예제
public void updateContent(String jwtToken, Post post, String newContent) {
Claims claims = JwtUtils.parseToken(jwtToken);
String userId = claims.getSubject();
List<String> roles = claims.get("roles", List.class);
if(!post.getOwner().equals(userId) && !roles.contains("ADMIN")) {
throw new SecurityException("수정 권한이 없습니다.");
}
post.setContent(newContent);
}
}
서버는 토큰을 해석해서 권한을 확인하고, 별도의 세션 저장소는 사용하지 않는다
3. JWT 동작 흐름 다이어그램
* JWT는 탈취되면 만료 전까지 무효화할 방법이 없다. 따라서 짧은 만료시간을 두고 Refresh Token과 함께 사용해야한다
* Payload는 Base64로 인코딩된 것이므로, 누구나 내용을 볼 수 있다. 민감한 정보는 절대 넣지 않기!
* 서버는 무상태성(stateless) 구조를 유지할 수 있기 때문에, 대규모 서비스에 적합하다
4. 정리
| 특징 | 설명 |
| 저장 위치 | 클라이언트(JWT 자체) |
| 전달 방식 | HTTP Header(Authorization: Bearer) |
| 장점 | 서버 확장에 유리, 무상태 유지 가능 |
| 단점 | 탈취시 위험, 만료전 무효화 어려움 |
권한 정보 관리의 모범 사례
1. 최소 권한 원칙(Principle of Least Privilege)
사용자가 업무 수행에 꼭 필요한 최소한의 권한만 가지도록 설계해야함
예 : 일반 사용자는 자기 글만 수정 가능, 관리자는 모든 글 수정 가능
2. 중앙 집중 관리
권한 정책은 코드 여러곳에 흩어지지 않고, 중앙 관리 모듈을 통해 관리해야함
예 : AuthorizationService 같은 클래스에서 모든 권한 검증을 수행함
3. 로그와 모니터링
권한 검증 실패는 보안 이벤트로 기록해야함
예 : 관리자 페이지 접근시 권한 부족으로 거절함 -> 보안 로그에 남기기
4. 계층적 권한 설계
USER < EDITOR < ADMIN 처럼 계층적 구조를 도입하면 권한 관리가 단순해짐
권한 설계를 초기에 잘못하면 유지보수가 어려워짐
정리
| 모범 사례 | 설명 |
| 최소 권한 원칙 | 꼭 필요한 권한만 부여 |
| 중앙 집중 관리 | 권한 검증 코드 일원화 |
| 로그와 모니터링 | 권한 실패 이벤트 기록 |
| 계층적 권한 설계 | 유지보수 용이성 확보 |
'Spring Boot > 유저 관리 기능' 카테고리의 다른 글
| OAuth와 OpenID Connect : OAuth 주체와 설정 (0) | 2026.03.23 |
|---|---|
| OAuth와 OpenID Connect : OAuth의 개념, 필요성 (0) | 2026.03.23 |
| 인가와 권한 관리 : 실제 인가 구현 사례 (0) | 2026.03.21 |
| 인가와 권한 관리 : Spring Security와 권한 검증 플로우 (0) | 2026.03.17 |
| 인가와 권한 관리 : 권한 기반 접근 제어 (0) | 2026.03.17 |