정수원님의 강의 스프링 시큐리티 완전 정복 [6.x 개정판] 보면서 공부한 내용입니다.
💡 authenticatioManager, logoutHandlers, securityContextRepository 등의 api를 사용하고 있는데, 이는 인증 수행/인증 상태 유지/로그인/로그아웃 등의 인증 관련 기능들을 제공하고 있다
💡 setLogoutHanders, setTrustResolver, setAuthenticationManger 등의 메소드에 SecurityContextHolderAwareRequestFilter가 전달해준 객체들을 넘겨받아 인증을 수행할 수 있도록 준비한다
💡 logout, isAuthenticated, login 등의 보안 메소드를 통해 인증을 수행할 때 서블릿에서 사용할 수 있는 객체가 되어 서블릿에서 인증 관련 수행을 처리할 수 있다
Spring Security에서는 entication.getPrincipal()을 자동으로 해결 할 수 있는 AuthenticationPrincipalArgumentResolver 를 제공한다
그렇기에 Spring MVC에서 @AuthenticationPrincipal 을 메서드 인수에 선언하게 되면 Spring Security와 같은 기능을 독립적으로 사용할 수 있다
Spring Security 버전
@RequestMapping("/user")
public void findUser() {
Authentication authentication = SecurityContextHolder.getContextHolderStrategy().getContext().getAuthentication();
CustomUser custom = (CustomUser) authentication == null ? null : authentication.getPrincipal();
}
AuthenticationPrincipalArgumentResolver
클래스는 해당 어노테이션이 선언되면 authentication으로부터 principal을 꺼내와서 인자를 전달해주는 역할을 한다@GetMapping("/user")
public User user(@AuthenticationPrincipal User user){
return user;
// User principal 자체를 의미한다
// 그러므로 authentication 인증 객체 안에
// principal 속성에 User 객체가 저장되어 있어야 한다
}
@GetMapping("/user2")
public String user2(@AuthenticationPrincipal(expression = "username") String user){
// User 객체 안에 들어있는 username 필드 가져오기
return user;
}
@AuthenticationPrincipal
어노테이션 추가 부여하여 자체적으로 메타 주석처리 할 수 있다// CurrentUser 어노테이션 생성
@Target({ ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface CurrentUser {
}
// CurrentUser 어노테이션 사용
@GetMapping("/currentUsername")
public String currentUser(@CurrentUser String user){
// CurrentUser 어노테이션으로 @AuthenticationPrincipal 어노테이션 메타 주석 처리 진행
return user;
}
// CurrentUsername 어노테이션 생성 (표현식 사용)
@Target({ ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : username")
// #this : principal 자체를 의미
// 익명이면 null 전달, 아니면 username 전달
public @interface CurrentUsername {
}
// CurrentUsername 어노테이션 사용
@GetMapping("/currentUsername")
public String currentUsername(@CurrentUsername String user){
return user;
}
@GetMapping("/callable")
public Callable<Authentication> call(){
// 메인 부모 쓰레드의 SecurityContext가 전달됨
SecurityContext context = SecurityContextHolder.getContextHolderStrategy().getContext();
System.out.println("부모 쓰레드 " + Thread.currentThread().getName());
System.out.println("context = " + context);
// 비동기 자식 쓰레드
// 부모의 SecurityContext에 접근 가능한지 확인
return new Callable<Authentication>() {
@Override
public Authentication call() throws Exception {
SecurityContext context = SecurityContextHolder.getContextHolderStrategy().getContext();
System.out.println("자식 쓰레드 " + Thread.currentThread().getName());
System.out.println("context = " + context);
return context.getAuthentication();
}
};
}