Spring Security가 적용된 프로젝트에서 사용자가 API를 호출했을 때 사용자의 정보가 필요한 때가 있다.

 

한 가지 예로 데이터 수정 시 테이블 updateBy 필드에 들어갈 사용자 ID 같은 것들?

그래서 @AuthenticationPrincipal 어노테이션을 사용해서 사용자 정보 조회하는 것을 알아보게 되었다.

 

인증 객체

Spring Security를 적용하면 인증 객체(Authentication)을 SecurityContextHolder 내부의 SecurityContext에 저장하고 있다.

그렇기 때문에 컨트롤러에서 @AuthenticationPrincipal을 사용해 인증 객체의 정보를 조회할 수 있는 것이다.

 

MemberInfo

@Getter
public class MemberInfo extends User {

    private String userId;

    public MemberInfo(String username, String password, Collection<? extends GrantedAuthority> authorities) {
        super(username, password, authorities);
        this.userId = username;
    }

}

Spring Security의 User를 상속받는 커스텀 클래스를 만들었다. 지금은 userId 필드만 존재하는데, 이후 필요하다면 추가 정보를 추가해서 사용해도 된다.

 

JwtFilter & TokenProvider

Authentication authentication = tokenProvider.getAuthentication(accessToken);
SecurityContextHolder.getContext().setAuthentication(authentication);

Jwt 필터에서 인증 객체를 조회해서 SecurityContext에 저장하는 부분이다.

토큰에서 인증 객체를 조회하는 메소드를 살펴보도록 하자.

 

public Authentication getAuthentication(String token) {
    Claims claims = Jwts.parserBuilder()
            .setSigningKey(this.secretKey)
            .build()
            .parseClaimsJws(token)
            .getBody();

    Object authoritiesCliam = claims.get("role");

    Collection<? extends GrantedAuthority> authorities = (authoritiesCliam == null) ?
            AuthorityUtils.NO_AUTHORITIES : AuthorityUtils.commaSeparatedStringToAuthorityList(claims.get("role").toString());

    // User를 상속받는 커스텀 클래스를 생성자 메소드 사용해서 객체 생성
    MemberInfo memberInfo = new MemberInfo(claims.getSubject(), "", authorities);

    return new UsernamePasswordAuthenticationToken(memberInfo, token, authorities);
}

Jwt 토큰에 저장된 데이터를 활용해 MemberInfo 객체의 필드를 채워서 인증 객체를 반환하게 되고, 이 인증 객체를 ContextHolder에 설정한다.

 

MemberController

@PutMapping("/{id}")
public ResponseEntity<Object> editMember(
        @PathVariable Long id,
        @RequestBody MemberEditDto memberEditDto,
        @AuthenticationPrincipal MemberInfo memberInfo) {
    return ResponseEntity.ok(memberService.editMember(id, memberEditDto, memberInfo));
}

멤버 컨트롤러의 멤버 수정 API이다. 파라미터 중 @AuthenticationPrincipal MemberInfo memberInfo를 받는 부분이 있는데, 간단하게 위의 Jwt 필터에서 설정한 MemberInfo 객체를 가져올 수 있다.

 

디버깅 시 memberInfo에 토큰에 담긴 userId가 잘 담기는 것을 확인할 수 있다.

 

끝.