[Spring Security] 인증된 사용자 정보 조회

Spring Security의 Filter들을 모두 거쳐 인증에 통과한 User가 특정 Controller에 도달했을 때, User의 정보가 필요할때가 있습니다. 이때, Url의 도메인으로 id를 표시하거나 param/body로 계속 전달하기도 무리이며, Filter를 통한 인증시에 이미 한번 유저 정보를 조회하는 로직을 수행하게 됩니다. 그런데 한번더 select로 조회시 두번 조회하게 되는 비효율적인 상황이 발생하기 때문에 Spring Security의 Context Holder에 들어있는 인증 정보를 가져다 사용하면 Filter에서 인증을 수행한 User의 정보(Details)에 접근할 수 있습니다.

이 Context Holder에 접근하는 방법은 다음과 같은 방법이 존재합니다.


1. @Controller의 메서드에서 매개변수로 입력받기

@Controller
public class UserController{}
  @GetMapping
  public String getMyInfo(Authentication authentication){
    JwtAuthenticationToken authentication = (JwtAuthenticationToken) authentication;
    User user = (User)authentication.getDetails();
    return user.toString();
  }
}

@Controller로 등록된 Bean의 메서드들은 메서드에서 추가 매개변수 인자로 Authentication타입을 받을 수 있습니다. 위와같이 선언하면 Container가 인증객체를 메서드에 추가해주게 됩니다.

인증처리과정에서 Custom Authenticaion 객체를 사용하고 있다면 Authentication을 이용해서 명시적 형변환을 이용하거나 처음부터 매개변수타입으로 지정을 할 수 있습니다.

@Controller
public class UserController{}
  @GetMapping
  public String getMyInfo(JwtAuthenticationToken authentication){
    User user = (User)authentication.getDetails();
    return user.toString();
  }
}


@Controller
public class UserController{}
  @GetMapping
  public String getMyInfo(Principal principal){
    return principal.toString();
  }
}

또한 Authentication 객체 뿐만이 아닌 Principal객체도 주입받아 사용할 수 있습니다.



2. @AuthenticationPrincipal

@Controller
public class UserController{}
  @GetMapping
  public String getMyInfo(@AuthenticationPrincipal Object principal){
    return principal.toString();
  }
}

//Custom principal
@Controller
public class UserController{}
  @GetMapping
  public String getMyInfo(@AuthenticationPrincipal UserInfo principal){
    return principal.toString();
  }
}

위와같이 어노테이션을 선언 후 통해 현재 사용자의 인증 주체를 주입받을수도 있습니다. 이때 보통 principal은 Object로 선언되어있기 때문에 Object타입을 주입해주어야하고 Custom한 Principal객체가 있다면 그것을 주입해주어도 가능합니다.

다른 타입을 주입시에 null값이 들어가게 됩니다.



3. SecurityContext

@Controller
public class UserController{}
  @GetMapping
  public String getMyInfo(){
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    //Authentication authentication =  SecurityContextHolder.getContext().getAuthentication();
    UserInfo userInfo = (UserInfo)principal;
    String id = principal.getId();

    return id;
  }
}

가장 원초적인 방법으로는 Container가 주입시켜주는 것이 아닌 SecurityContextHolder에 직접 접근해서 인증 객체를 가져오는 방법으로도 사용자 정보를 가져올 수 있습니다.