Spring Security : 사용자 인증 정보 추출 방법

2ㅣ2ㅣ·2024년 10월 31일

Spring

목록 보기
6/7
post-thumbnail

Spring Security로 로그인을 구현했다. 근데 서블릿을 통과한 스레드가 인증된 사용자 정보를 어떻게 가져와서 활용할 수 있을까?

방법1 : 별도의 메서드를 만든다

이건 참 1차원적인 방법인데 email을 추출하는 메서드를 만드는 것이다.
나는 사용자 요청을 담당하는 RequestParser라는 파일 내에 만들었다.
정확히는 username을 추출해야 한다. 나는 username을 email로 설정했기 때문에 email을 추출한 것이다.

RequestParser.java

/**
 * HTTP 요청에서 설정된 email 속성을 추출하는 메서드
 * @param request HTTP 요청 객체
 * @return 요청 속성에서 추출된 이메일 문자열, 속성이 없으면 null 반환
 */
public static String extractEmail(HttpServletRequest request){
    Object attribute = request.getAttribute(EMAIL);
    if (attribute == null){
        return null;
    }
    return attribute.toString();
}

그런 다음 사용자 인증이 필요한 메서드에서 검증을 하면 끝이다.

Controller.java

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/diary")
public class DiaryController {
    private final DiaryService diaryservice;

    @PostMapping("/write")
    public BaseResponse<DiaryResponseDto> writeDiary(
            @Validated @RequestBody DiaryRequestDto diaryRequestDto,
            HttpServletRequest request
    ){
        if (diaryRequestDto == null) {
            return new BaseResponse<>(BaseResponseStatus.BAD_REQUEST_DIARY_INPUT);
        }
        String email = RequestParser.extractEmail(request);
        return diaryservice.writeDiary(diaryRequestDto, email);
    }
}

특징

  • Spring Security를 처음 접했을 때 Spring Security의 내부 필터나 인증 흐름을 자세히 몰라도 쉽게 구현할 수 있다는 장점이 있다.
    • HttpServletRequset에서 속성으로 사용자 정보를 받아오는 방식이기 때문이다.

한계

  • 인증 정보를 추출한다는 것에 집중하면 문제 없지만 email이 컨트롤러에 노출된다는 점에서 보안에 취약하다고 할 수 있다.
  • Spring Security에서 제공하는 보안 방식이 아니기 때문에, 후에 Spring Security와 연계된 다른 로직과 충돌이 발생하거나 호환성이 좋지 못하다는 문제도 있다.

방법2 : Principal 객체를 주입한다

Spring Security의 Principal 객체를 사용하여 인증된 사용자 정보를 추출한다.
Spring Security의 @AuthenticationPrincipal 어노테이션을 사용하거나 Principal 객체를 주입하여 getName() 메서드를 호출해 이메일을 얻을 수 있다.

기존 RequestParser의 extractEmail을 제거하고 컨트롤러 코드를 변경한다.

Controller.java

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/diary")
public class DiaryController {
    private final DiaryService diaryservice;

    @PostMapping("/write")
    public BaseResponse<DiaryResponseDto> writeDiary(
            @Validated @RequestBody DiaryRequestDto diaryRequestDto,
            Principal principal 
    ){
        if (diaryRequestDto == null) {
            return new BaseResponse<>(BaseResponseStatus.BAD_REQUEST_DIARY_INPUT);
        }

        String email = principal.getName();
        return diaryservice.writeDiary(diaryRequestDto, email);
    }
}

특징

  • 코드를 간결하게 함과 동시에 보안적으로 더 안정되게 인증 정보를 추출할 수 있다.
  • Spring Security의 표준 방식을 준수한 방식이다.

한계

Principal 객체가 뭔데?

쓰는 건 쓰는건데 Principal이 뭔지는 알고 쓰자.
Principal은 사용자 식별 정보를 담은 객체로, Authentication 객체 안에 포함된 인증된 사용자 정보를 나타낸다.

public class Member implements UserDetails {

이렇게 되면 Member가 Principal로 작동한다.
후에 Member는 Principal로 주입되어 사용될 수 있다.

Authentication는 또 뭔데?

Authentication은 Spring Security에서 인증 및 권한 부여 작업을 담당하는 핵심 객체다.
사용자가 로그인하면 SecurityContext에 인증 객체로 저장되며, 각 요청을 처리하는 스레드에 따라 보안 설정을 적용한다.

  • Authentication 객체 구성
    • Principal: UserDetails의 구현체로, 사용자 식별 정보를 포함.
    • Credentials: 인증에 사용된 비밀번호나 토큰. 인증 완료 후 보안상 삭제됨.
    • Authorities: 사용자 권한 정보.

이렇게 구성된 Authentication 객체는 Spring Security의 SecurityContext에 저장되어 인증된 상태를 유지하며, 스레드가 특정 요청을 처리하는 동안 보안 컨텍스트를 공유한다.

결론

Spring Security를 사용하여 사용자 인증 정보를 추출할 때는, Spring Security의 표준 방식인 Principal 객체를 사용하는 것이 더 안전하다.

profile
https://sususoo.tistory.com/

0개의 댓글