View에서 접근 가능한 유저정보를 컨트롤러에서 Model로 넘겨주는 이유 블로그 포스팅
그동안 상단 헤더바에 들어가는 사용자에 대한 정보를 컨트롤러에서 @Authentication Principal로 받아서 모델에 추가해서 뷰로 넘겨 사용했다.
그러다 보니 모든 컨트롤러에서 세션 정보를 받아와 있는지 없는지 확인하고 있으면 닉네임, 감정을 모델에 추가해주는 코드를 넣어서 사용해왔다. 그러다 baeldung에서 해결법을 찾아 해결했다.
일단 이전 코드 먼저 보겠다.
PostController, ControllerUtil
public class PostController {
private final PostService postService;
@GetMapping("/posts")
public String list(Model model, @PageableDefault(size = 2, sort = "id", direction = Sort.Direction.DESC)
Pageable pageable, @AuthenticationPrincipal CustomUserDetails userDetails) {
Page<PostResponse> posts = postService.getList(pageable);
PageDto<PostResponse> postPageResponse = PageDto.of(posts);
model.addAttribute("posts", postPageResponse);
if (userDetails != null) {
existsSession(model, userDetails); // 중복 코드
}
return "post/posts";
}
@GetMapping("/posts/read/{postId}")
public String get(@PathVariable Long postId, Model model, @AuthenticationPrincipal CustomUserDetails userDetails) {
if (userDetails != null) {
PostResponse postResponse = postService.getWithEmotion(postId, userDetails.getEmotion());
if (postResponse.getCommentResponses() != null) {
model.addAttribute("comments", postResponse.getCommentResponses());
}
existsSession(model, userDetails);
model.addAttribute("post", postResponse);
}
if (userDetails == null) {
PostResponse postResponse = postService.get(postId);
if (postResponse.getCommentResponses() != null) {
model.addAttribute("comments", postResponse.getCommentResponses());
}
model.addAttribute("post", postResponse);
}
model.addAttribute("commentCreate", new CommentCreate());
return "post/postView";
}
// ... 생략
private void userCheck(CustomUserDetails user, Long postId) {
if (!user.getUsername().equals(postService.get(postId).getUsername()))throw new Unauthorized();
}
}
public class ControllerUtil {
public static void existsSession(Model model, CustomUserDetails user){
model.addAttribute("nickname", user.getNickname());
model.addAttribute("emotion", user.getEmotion());
}
}
PostController 내에 게시글 상세보기에서 로그인 한 사용자의 감정에 따라 댓글을 필터링 할 때 외에는 사실 세션정보를 안가져와야 하지만 지금까지는 뷰로 넘겨주기 위해 생략된 모든 부분에 추가를 해줬었다.
UserDetails
@RequiredArgsConstructor
public class CustomUserDetails implements UserDetails {
private final User user;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
String[] authorities = new String[]{user.getRole().getAuth()};
return AuthorityUtils.createAuthorityList(authorities);
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
public String getNickname() {
return user.getNickname();
}
public Emotion getEmotion() {
return user.getEmotion();
}
public String getEmail() {
return user.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
Spring Security에서 세션으로 쓰이는 UserDetails Class에 Nickname, Emotion getter을 넣으면 타임리프에서 접근할 수 있다.
Thymeleaf 변경
변경 전
<sapn class="text-white" th:text="${nickname}">사용자</sapn>
<button class="btn btn-warning" th:text="${emotion}" sec:authorize="isAuthenticated()"
th:onclick="|location.href='@{/account/emotion}'|"></button>
모델로 넘어온 값 사용
변경 후
<sapn class="text-white" sec:authentication="principal.nickname">사용자</sapn>
<button class="btn btn-warning" sec:authentication="principal.emotion" sec:authorize="isAuthenticated()"
th:onclick="|location.href='@{/account/emotion}'|"></button>
Thymeleaf에서 UserDetials 접근해서 가져온 값 사용
Controller 중복 코드 삭제
변경 전
@GetMapping("/posts")
public String list(Model model, @PageableDefault(size = 2, sort = "id", direction = Sort.Direction.DESC)
Pageable pageable, @AuthenticationPrincipal CustomUserDetails userDetails) {
Page<PostResponse> posts = postService.getList(pageable);
PageDto<PostResponse> postPageResponse = PageDto.of(posts);
model.addAttribute("posts", postPageResponse);
if (userDetails != null) {
existsSession(model, userDetails);
}
return "post/posts";
}
변경 후
@GetMapping("/posts")
public String list(Model model, @PageableDefault(size = 2, sort = "id", direction = Sort.Direction.DESC)
Pageable pageable\) {
Page<PostResponse> posts = postService.getList(pageable);
PageDto<PostResponse> postPageResponse = PageDto.of(posts);
model.addAttribute("posts", postPageResponse);
return "post/posts";
}
배운점
UsernamePasswordAuthenticationToken으로 구현된 Authentication의 오버라이딩으로 타임리프에서 UserDetails에 접근할 수 있다는 걸 배웠다.
참조
https://www.baeldung.com/spring-thymeleaf-user-info