[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
에 직접 접근해서 인증 객체를 가져오는 방법으로도 사용자 정보를 가져올 수 있습니다.