인가

인가(Authorization)란 인증된 사용자가 특정 리소스나 기능에 접근할 수 있는 권한이 있는지 확인하는 과정입니다.

인증 vs 인가

[인증 Authentication — "너 누구야?"]
사용자: "저 홍길동입니다" (아이디/비밀번호, 토큰 등)
서버:   "확인됐습니다. 홍길동 맞네요" O

[인가 Authorization — "너 이거 해도 돼?"]
홍길동: "관리자 페이지 보여주세요"
서버:   "홍길동은 일반 회원이라 안 됩니다" X 403

인증이 먼저 이루어지고, 그 다음에 인가가 수행됩니다.

요청 → 인증 (누구인가?) → 인가 (권한이 있는가?) → 리소스 접근
       실패 시 401        실패 시 403

인가의 대표적 방식

1. 역할 기반 접근 제어 (RBAC)

사용자에게 역할(Role) 을 부여하고, 역할에 따라 접근을 제어하는 가장 보편적인 방식입니다.

[역할 구조]
ADMIN  → 모든 기능 접근 가능
MANAGER → 게시글 관리 가능
USER   → 본인 게시글만 조회/수정 가능
GUEST  → 공개 게시글 조회만 가능
// Spring Security RBAC 설정
@Configuration
public class SecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .requestMatchers("/manage/**").hasAnyRole("ADMIN", "MANAGER")
                .requestMatchers("/mypage/**").hasRole("USER")
                .anyRequest().permitAll()
            );
        return http.build();
    }
}
// 메서드 레벨 인가
@PreAuthorize("hasRole('ADMIN')")
@DeleteMapping("/members/{id}")
public ResponseEntity<Void> deleteMember(@PathVariable Long id) {
    memberService.delete(id);
    return ResponseEntity.noContent().build();
}

2. 리소스 기반 접근 제어

역할이 아니라 해당 리소스의 소유자인지 확인하는 방식입니다.

// "본인의 주문만 조회 가능"
@GetMapping("/orders/{orderId}")
public ResponseEntity<Order> getOrder(@PathVariable Long orderId,
                                       @AuthenticationPrincipal UserDetails user) {
    Order order = orderService.findById(orderId);

    // 역할과 무관하게, 본인 주문인지 확인
    if (!order.getMemberId().equals(user.getId())) {
        throw new AccessDeniedException("본인의 주문만 조회 가능합니다");
    }

    return ResponseEntity.ok(order);
}

3. 권한 기반 접근 제어

역할보다 세분화된 개별 권한(Permission) 을 부여하는 방식입니다.

[RBAC — 역할 단위]
ADMIN 역할 → 모든 권한

[권한 기반 — 기능 단위]
사용자 A → POST_READ, POST_WRITE
사용자 B → POST_READ, POST_WRITE, POST_DELETE
사용자 C → POST_READ, USER_MANAGE
// 권한 기반 인가
@PreAuthorize("hasAuthority('POST_DELETE')")
@DeleteMapping("/posts/{id}")
public ResponseEntity<Void> deletePost(@PathVariable Long id) {
    postService.delete(id);
    return ResponseEntity.noContent().build();
}

RBAC vs 권한 기반 비교

항목RBAC (역할 기반)권한 기반
단위역할 (ADMIN, USER 등)개별 권한 (POST_READ 등)
유연성역할 추가/변경 시 영향 큼권한을 세밀하게 조합 가능
복잡도단순권한 수가 많아지면 관리 복잡
적합 규모소~중규모대규모, 복잡한 권한 체계

JWT에서의 인가

// JWT Payload에 역할/권한 정보 포함
{
  "sub": "1",
  "role": "ADMIN",
  "permissions": ["POST_READ", "POST_WRITE", "USER_MANAGE"],
  "exp": 1700000000
}
// JWT 기반 인가 필터
@Component
public class JwtAuthFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                     HttpServletResponse response,
                                     FilterChain chain) throws Exception {
        String token = extractToken(request);
        Claims claims = jwtProvider.parse(token);

        String role = claims.get("role", String.class);

        // 인증 + 권한 정보를 SecurityContext에 설정
        List<GrantedAuthority> authorities =
                List.of(new SimpleGrantedAuthority("ROLE_" + role));

        Authentication auth = new UsernamePasswordAuthenticationToken(
                claims.getSubject(), null, authorities);

        SecurityContextHolder.getContext().setAuthentication(auth);

        chain.doFilter(request, response);
    }
}

인가 처리 흐름 요약

1. 클라이언트 → 서버: 요청 + 인증 정보 (토큰/세션)
2. 서버: 인증 확인 → "홍길동(USER)" 확인
3. 서버: 인가 확인 → "이 API는 ADMIN만 접근 가능"
4. 서버: 홍길동은 USER → 권한 없음 → 403 Forbidden

면접 포인트

CSLOG에서 보기