728x90
반응형
어제에 이어서 권한 부여, 확인 작업을 진행하였습니다.
Security context에 AuthenticationToken을 만들어서 넣어주고
그것으로 인증을 하고, controller에서도 가져와서 활용할 수 있다는 것을 알았습니다.
그리고 권한을 확인 할때 @Secured를 이용하여
각 api 함수에 필요한 권한을 달아주었습니다.
🛡️ [Spring Security] SecurityContext 완벽 정리
1. SecurityContext란?
인증이 완료된 사용자의 상세 정보(Authentication)를 애플리케이션이 실행되는 동안 임시로 저장하는 보관함입니다.
- 핵심 역할: "누가 지금 우리 서비스를 이용 중인가?"에 대한 답을 들고 있습니다.
- 유효 범위: 하나의 HTTP 요청(Request)이 들어와서 응답(Response)이 나갈 때까지 유지됩니다. (ThreadLocal 기반)
2. 저장 구조 (계층도)
보안 정보는 마치 '러시아 인형(마트료시카)'처럼 겹겹이 쌓여 관리됩니다.
- SecurityContextHolder: 보안 정보의 가장 바깥쪽 가방. 어디서든 접근할 수 있는 통로입니다.
- SecurityContext: 가방 안에 든 지갑. Authentication 객체 하나를 품고 있습니다.
- Authentication: 지갑 안의 신분증. 유저의 ID(Principal), 권한(Authorities), 비번(Credentials) 등이 들어 있습니다.
3. 필터(Filter)에서의 동작 흐름
우리가 만든 JwtAuthorizationFilter가 하는 일이 바로 이 흐름을 타는 것입니다.
- 검사: 요청 헤더에서 JWT 토큰을 꺼내 유효성을 검사합니다.
- 생성: 토큰이 유효하면 DB를 조회해 유저 정보(UserDetails)를 담은 Authentication 객체를 만듭니다.
- 저장: 이 객체를 SecurityContext에 넣고, 최종적으로 SecurityContextHolder에 보관합니다.
-
예시 코드
- 활용: 이후 컨트롤러나 서비스 어디서든 SecurityContextHolder.getContext().getAuthentication()을 통해 현재 로그인한 유저 정보를 꺼내 쓸 수 있습니다.
// 인증 처리
public void setAuthentiaction(String username){
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = createAuthentication(username);
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
}
// 인증 객체 생성
private Authentication createAuthentication(String username){
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
}
** 필터 만든 후 꼭 추가해주어야함.
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// CSRF 설정 (H2 콘솔 사용을 위해 비활성화)
http.csrf(AbstractHttpConfigurer::disable);
// H2 콘솔의 iframe 허용
http.headers(headers -> headers
.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin)
);
// 기본 설정인 Session 방식은 사용하지 않고 JWT 방식을 사용하기 위한 설정
http.sessionManagement((sessionManagement) ->
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
http.authorizeHttpRequests(auth -> auth
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
.requestMatchers("/h2-console/**").permitAll()
.requestMatchers("/api/v1/auth/signup", "/api/v1/auth/login").permitAll()
.anyRequest().authenticated()
);
//필터 관리
http.addFilterBefore(jwtAuthorizationFilter(), JwtAuthenticationFilter.class); // <- 추가한 부분
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
🆔 [Spring Security] Authentication 객체 정리
1. Authentication이란?
현재 애플리케이션에 접근한 사용자가 **"누구인지(인증)"**와 **"무엇을 할 수 있는지(권한)"**를 증명하는 객체입니다.
- 저장소: SecurityContext 내부에 저장됩니다.
- 생성 시점: 로그인 성공 시(인증 필터) 또는 유효한 토큰 검증 완료 시(인가 필터) 생성됩니다.
2. Authentication의 3대 핵심 구성 요소
신분증에 적힌 항목들을 상상해 보세요.
- Principal (주체)
- 정체: 사용자의 ID나 유저 객체 자체.
- 실제 코드: 보통 우리가 만든 UserDetailsImpl 객체가 여기 담깁니다. "이 신분증의 주인"을 뜻합니다.
- Credentials (자격 증명)
- 정체: 사용자가 본인임을 증명하기 위해 제시한 비밀번호나 토큰.
- 특징: 보안을 위해 인증이 완료된 후에는 보통 null로 비워두는 경우가 많습니다. (유출 방지)
- Authorities (권한)
- 정체: 유저가 가진 역할 리스트 (ROLE_CUSTOMER, ROLE_MASTER 등).
- 형태: GrantedAuthority 객체의 컬렉션(Collection)으로 관리됩니다.
3. 인증 전과 후의 차이 (Authentication의 상태)
이 객체는 인증 과정에서 **'미인증 상태'**에서 **'인증 완료 상태'**로 진화합니다.
- 인증 전: 사용자가 아이디/비번만 보낸 상태. (아직 신뢰할 수 없는 가짜 신분증)
- 인증 후: AuthenticationManager가 "이 사람 진짜 맞음!" 하고 도장을 꽝 찍어준 상태. 이때 isAuthenticated = true가 되고 SecurityContext에 보관됩니다.
4. 코드에서 꺼내 쓰는 법
컨트롤러에서 @AuthenticationPrincipal을 썼던 이유가 바로 이 신분증의 Principal 부분을 바로 꺼내기 위해서입니다.
// 1. 수동으로 꺼내기
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl user = (UserDetailsImpl) auth.getPrincipal();
// 2. 어노테이션으로 우아하게 꺼내기
public ResponseEntity<?> getMyInfo(@AuthenticationPrincipal UserDetailsImpl loginUser) {
// loginUser가 바로 Authentication 내부의 Principal입니다.
}
🔒 [Spring Security] @Secured 간단 정리
1. @Secured란?
메서드 단위에서 **"이 기능을 쓸 수 있는 등급(Role)"**을 아주 직관적으로 지정하는 어노테이션입니다.
- 역할: 특정 메서드 실행 전, 현재 유저의 권한을 체크해서 입구 컷을 결정합니다.
- 활성화 방법: SecurityConfig에 @EnableMethodSecurity(securedEnabled = true) 설정이 반드시 필요합니다.
2. 사용법 (배달 앱 예시)
딱 보고 "아, 이 등급만 되는구나!" 알 수 있는 게 최대 장점입니다.
// 1. 단일 권한
@Secured("ROLE_MASTER")
public void deleteUser() { ... }
// 2. 다중 권한 (OR 조건)
@Secured({"ROLE_OWNER", "ROLE_MASTER"})
public void updateStore() { ... }
3. 핵심 포인트 (주의사항)
- 전통적인 방식: 스프링 시큐리티 초기부터 있던 방식이라 설정이 매우 단순합니다.
- 문자열 기반: 반드시 ROLE_ 이라는 접두사를 직접 붙여줘야 정확히 인식합니다. (예: ROLE_MASTER)
- OR 조건: 여러 권한을 넣으면, 그중 하나라도 가지고 있으면 통과됩니다.
4. @PreAuthorize와 차이점
- @Secured: "너 이 등급이야?" (단순 등급 확인용)
- @PreAuthorize: "너 이 등급이거나, 아니면 이 데이터 주인이니?" (SpEL을 사용한 복잡한 로직 확인용)
반응형
'Study' 카테고리의 다른 글
| [내일배움캠프 TIL] 14일차 - 2. @NotNull vs @Column(nullable = false) 차이점. (0) | 2026.04.23 |
|---|---|
| [내일배움캠프 TIL] 14일차 - 1. JPA 쿼리 메서드 주의할 점. (0) | 2026.04.22 |
| [내일배움캠프 TIL] 12일차 - JWT, Auth 구현(회원가입 로그인) (0) | 2026.04.21 |
| [내일배움캠프 TIL] 11일차 - Controller 단에서 로직 분리 실습 2 (0) | 2026.04.20 |
| [내일배움캠프 TIL] 10일차 - uuid, erd표기법, Transaction (1) | 2026.04.17 |