게시판의 질문 또는 답변에 작성자를 표시하는 기능을 추가하려고 한다. Question, Answer 엔티티에 author
속성이 추가되었다고 가정한 상태로 진행한다.
스프링 시큐리티에서 제공하는 Principle
객체를 사용하면 현재 로그인한 사용자에 대한 정보를 알 수 있다.
답변을 등록하는 createAnswer
메서드에 Principle 객체를 매개변수로 지정한다.
principal.getName()
을 호출하면 현재 로그인한 사용자의 username(사용자 id)을 알 수 있다.
AnswerController.java
(... 생략 ...)
import java.security.Principal;
(... 생략 ...)
public class AnswerController {
(... 생략 ...)
@PreAuthorize("isAuthenticated()")
@PostMapping("/create/{id}")
public String createAnswer(Model model, @PathVariable("id") Integer id,
@Valid AnswerForm answerForm, BindingResult bindingResult, Principal principal) {
(... 생략 ...)
}
}
@PreAuthorize("isAuthenticated()")
이 어노테이션이 붙은 메서드를 로그인이 필요한 메서드를 의미하며, 로그아웃 상태에서 호출될 경우 로그인 페이지로 이동된다.
SecurityConfig.java
(... 생략 ...)
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
(... 생략 ...)
@RequiredArgsConstructor
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
(... 생략 ...)
}
@EnableGlobalMethodSecurity(prePostEnabled = true)
AnswerController에서 로그인 여부를 판별하기 위해 사용한@PreAuthorize
어노테이션을 사용하기 위해 반드시 필요하다.
UserService.java
(... 생략 ...)
import java.util.Optional;
import com.mysite.sbb.DataNotFoundException;
(... 생략 ...)
@Service
public class UserService {
(... 생략 ...)
public SiteUser getUser(String username) {
Optional<SiteUser> siteUser = this.userRepository.findByusername(username);
if (siteUser.isPresent()) {
return siteUser.get();
} else {
throw new DataNotFoundException("siteuser not found");
}
}
}
AnswerService.java
(... 생략 ...)
import com.mysite.sbb.user.SiteUser;
(... 생략 ...)
public class AnswerService {
(... 생략 ...)
public Answer create(Question question, String content, SiteUser author) {
Answer answer = new Answer();
answer.setContent(content);
answer.setCreateDate(LocalDateTime.now());
answer.setQuestion(question);
answer.setAuthor(author);
this.answerRepository.save(answer);
return answer;
}
}
AnswerController.java
principal 객체를 통해 사용자명을 얻은 후, 사용자명을 통해 SiteUser 객체를 얻어서 답변을 등록하는 AnswerService의 create 메서드에 전달하여 답변을 저장한다.
(... 생략 ...)
import com.mysite.sbb.user.SiteUser;
import com.mysite.sbb.user.UserService;
(... 생략 ...)
public class AnswerController {
private final QuestionService questionService;
private final AnswerService answerService;
private final UserService userService; // 추가된 부분
@PostMapping("/create/{id}")
public String createAnswer(Model model, @PathVariable("id") Integer id,
@Valid AnswerForm answerForm, BindingResult bindingResult, Principal principal) {
Question question = this.questionService.getQuestion(id);
SiteUser siteUser = this.userService.getUser(principal.getName()); // 추가된 부분
if (bindingResult.hasErrors()) {
model.addAttribute("question", question);
return "question_detail";
}
this.answerService.create(question, answerForm.getContent(), siteUser); // 수정된 부분
return String.format("redirect:/question/detail/%s", id);
}
}