주문을 처리하는 OrderController에 processOrder() 메서드가 주문을 저장하는 일을 수행한다고 가정하자.
이러한 과정에는 인증된 사용자가 누구인지 결정하고, 해당 주문과 사용자 간의 연관관계를 맺는 과정을 포함한다.
그렇다면 사용자가 누구인지 어떻게 결정할까?
사용자가 누구인지 결정하는 방법은 여러가지가 있는데, 그중 가장 많이 사용하는 방법은 아래와 같다.
- Principal 객체를 컨트롤러 메서드에 주입한다.
- Authentication 객체를 컨트롤러 메서드에 주입한다.
- SecurityContextHolder를 사용해서 보안 컨텍스트를 얻는다.
- @AutheticationPrincipal 어노테이션을 메서드에 지정한다.
Principal 객체
코드는 잘 동작하지만, 보안과 관련 없는 코드 혼재
@PostMapping
public String processOrder(@Valid Order order,
Errors errors,
SessionStatus sessionStatus,
Principal principal) {
User user = userRepository.findByUsername(principal.getName());
order.setUser(user);
}
Authentication 객체
@PostMapping
public String processOrder(@Valid Order order,
Errors errors,
SessionStatus sessionStatus,
Authentication authentication) {
User user = (User) authentication.getPrincipal();
order.setUser(user);
}
- Authentication 객체를 얻은 다음, getPrincipal()을 호출하여 Principal 객체를 얻는다.
- getPrincipal()은 Object 타입을 반환하므로 User 타입으로 형변환 해야 한다.
@AuthenticationPrincipal
@PostMapping
public String processOrder(@Valid Order order,
Errors errors,
SessionStatus sessionStatus,
@AuthenticationPrincipal User user) {
if (errors.hasErrors()) {
return "orderForm";
}
order.setUser(user);
orderRepo.save(order);
sessionStatus.setComplete();
return "redirect:/";
}
- 타입 변환이 필요 없고 Authentication과 동일하게 보안 특정 코드만 갖는다.
- User 객체가 processOrder()에 전달되면 해당 주문에서 사용할 수 있다.
SecurityContextHolder
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
User user = (User) authentication.getPrincipal();
- 보안 컨텍스트로부터 Authentication 객체를 얻은 후 Principal 객체(인증된 사용자)를 요청한다.
- 이때도 반환되는 객체를 User 타입으로 변환해야 한다.
- 보안 특정 코드가 많지만, 이 방법은 컨트롤러의 처리 메서드는 물론이고 애플리케이션의 어디서든 사용할 수 있다는 장점