서버는 때때로 사용자로부터 요청을 받을 때마다 사용자의 정보를 확인할 필요가 있다.
JWT를 이용한다고 가정했을 때, 클라이언트는 요청 헤더에 JWT 값을 Authorization
에 넣어서 서버로 보낸다.
서버는 그럼 매번 요청을 받을 때마다 컨트롤러단에서 헤더에 존재하는 JWT를 가져온 다음, 디코드를 통해 사용자의 정보를 가져오는 것일까?
결론은 그렇지 않다. 물론, 그럴 수도 있지만, 더욱 간편한 방법이 존재한다.
그러한 방법들에 대해 알아보는 시간을 가져본다.
SecurityContextHolder
을 통해 SecurityContext
에 접근해서 사용자의 정보를 가져온다.@RequestMapping("/messages/inbox")
public ModelAndView findMessagesForUser() {
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
CustomUser custom = (CustomUser) authentication == null ? null : authentication.getPrincipal();
// .. find messages for this user and return them ...
}
Principal
을 가져올 수 있다.Authentication
토큰 또한 가져올 수 있다.@Controller
public class SecurityController {
@GetMapping("/username")
@ResponseBody
public String currentUserName(Principal principal) {
return principal.getName();
}
}
@Controller
public class SecurityController {
@GetMapping("/username")
@ResponseBody
public String currentUserToken(Authentication authentication) {
return authentication.toString();
}
}
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class FolderController {
private final FolderService folderService;
@GetMapping("/folders")
public List<FolderResponseDto> getFolders(
@AuthenticationPrincipal UserDetailsImpl userDetails) {
return folderService.getFolders(userDetails.getUser());
}
}
public class UserDetailsImpl implements UserDetails {
private final User user;
public UserDetailsImpl(User user) {
this.user = user;
}
public User getUser() {
return user;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
UserRoleEnum role = user.getRole();
String authority = role.getAuthority();
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(simpleGrantedAuthority);
return authorities;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
@AuthenticationPrincipal
를 설정받은 커스텀 어노테이션을 생성한다.@Target({ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface CurrentUser {
}
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class FolderController {
private final FolderService folderService;
@GetMapping("/folders")
public List<FolderResponseDto> getFolders(@CurrentUser UserDetailsImpl userDetails) {
return folderService.getFolders(userDetails.getUser());
}
}