[TIL] Spring Security - 요청 사용자 정보를 컨트롤러단에서 접근하는 방법

phdljr·2023년 11월 14일
0

TIL

목록 보기
30/70
post-custom-banner

서버는 때때로 사용자로부터 요청을 받을 때마다 사용자의 정보를 확인할 필요가 있다.

JWT를 이용한다고 가정했을 때, 클라이언트는 요청 헤더에 JWT 값을 Authorization에 넣어서 서버로 보낸다.

서버는 그럼 매번 요청을 받을 때마다 컨트롤러단에서 헤더에 존재하는 JWT를 가져온 다음, 디코드를 통해 사용자의 정보를 가져오는 것일까?

결론은 그렇지 않다. 물론, 그럴 수도 있지만, 더욱 간편한 방법이 존재한다.

그러한 방법들에 대해 알아보는 시간을 가져본다.


SecurityContextHolder에서 직접 뽑아내기

  • 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();
    }
}

@AuthenticationPrincipal

  • 사용자 객체를 매개변수로 받아올 수 있게 해주는 어노테이션
@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());
    }
}

참조

https://docs.spring.io/spring-security/reference/servlet/integrations/mvc.html#mvc-authentication-principal

profile
난 Java도 좋고, 다른 것들도 좋아
post-custom-banner

0개의 댓글