인증된 사용자 정보 조회

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

Related Posts

PointRee 프로젝트 3 - back 개발환경 셋팅과 db설계

PointRee 프로젝트 3 - back 개발환경 셋팅과 db설계

IntelliJ를 이용해서 pointRee폴더 내에 back폴더를 생성해주고 여기에 spring boot 2.4로 프로젝트를 시작했다. dependency는 위와 같이 추가해주었다. 1. db설계 포인트의 유효기간을 처음에 생각을 했었으나 db설계와 구현과정에 있어 많은 시간이 생각보다 소요될 것 같아 일단 유효기간이 없다고 생각하고 설계를 진행했다. 완성후 다른곳에 문제가 없다면 차차 추가할 생각이다....

Read More
Splay Tree

Splay Tree

Splaying이라는 기법이 사용되며, 이는 특정 노드에 대해 접근을 하면, 이를 루트로 위치하도록 재배치 하는 기법의 트리 1. 특징 구현이 단순 많이 접근한 노드에 대해서 빠른 접근이 가능하다 접근 빈도가 불균등하거나 비 랜덤 패턴의 경우 O(lgn)보다 더 유리하다. AVL-Tree와 RB-Tree와 달리 추가 데이터 저장 필요 없다. 최악의 경우 높이가 선형, 즉 O(n)이 나올 수 있다. 세그먼트 트리로 이용이 가능하다. k번째 원소 찾기, 구간 합, lazy Propagation, 구간 뒤집기 모두 쉽게 할 수 있다. x노드를 접근한다면, splay를 통해 root로 올라오면서 x보다 작은 노드들은 Left에, 큰 노드들은 Right에 모이는 특성을 이용...

Read More
AA Tree

AA Tree

RB-Tree를 응용한 트리로 RB-Tree의 많은 조건을 일부 제거하여 구현을 더 간단하게 만든 트리로 균형을 맞추기 위해 레벨의 개념을 사용한 트리이다. 부모와 레벨이 같은 자식 노드의 연결을 수평 링크라고 하며, 이 노드를 구분하기 위해 RED라는 개념을 이용한다. 1. 특징 왼쪽 자식은 RED가 될 수 없다. 연속으로 RED가 올 수 없다. (이중 RED 불가 == 이중 수평 링크) 루트에서 null가지 leafnode까지의 경로에는 동일한 수의 블랙 노드가 존재한다. (RB Tree의 규칙) 모든 leaf node의 레벨은 1이다. 모든 왼쪽 자식의 레벨은 부모의 레벨보다 1 낮다. 모든 오른쪽 자식의 레벨은 부모와 같거나 1 낮다. 모든 오른쪽 손자의 레벨은 할아버지 노드보다 낮다. 1보다 큰 레벨의 모든 노드들은 2개의 자식을 갖는다. 왼쪽 트리를 얼핏 보면 RB-Tree같지만 왼쪽 자식은 RED를 갖지 않는 AA-Tree이고, 이를 레벨을 기준으로 보면 오른쪽과 같이 그려 볼 수 있다....

Read More