스프링시큐리티 환경에서 회원 정보 수정 기능을 구현하던 중
회원 정보 수정을 완료하고 DB에 최신 데이터가 반영되었음에도 회원 정보페이지에 다시 접속하면 수정하기 전의 정보가 출력되는 현상이 발생하였습니다.
변경할 회원 정보를 입력하고 회원정보 수정 버튼을 클릭 시 정상 알림창이 출력되고
DB에도 정상적으로 수정된 정보가 반영된 것을 확인할 수 있습니다.
하지만,, 변경 후 다시 회원 정보를 요청하면
수정하기 전의 정보가 출력되는데
첫 번째 해결 방법 ❌
이는 현재의 코드가 아래 예시 처럼 스프링 시큐리티 세션의 정보를 #authentication.principal
로 가져와 사용자에게 출력하는 구조이기 때문에 일어나는 현상이었습니다.
<form>
<div class="mb-3 mt-3">
<label for="username" class="form-label">UserName:</label>
<input type="text" class="form-control" id="username"
th:value="${#authentication.principal.user.username}"
name="username" readonly>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password:</label>
<input type="text" class="form-control" id="password"
placeholder="Enter password" name="password">
</div>
<div class="mb-3 mt-3">
<label for="email" class="form-label">Email:</label>
<input type="email" class="form-control" id="email"
th:value="${#authentication.principal.user.email}"
placeholder="Enter email" name="email">
</div>
</form>
DB의 데이터가 정상적으로 변경이 되었더라도 스프링 시큐리티의 세션의 정보는 변경되지 않고, 재 로그인 시 최신 정보로 변경되게 됩니다. 따라서 정보 변경 이전의 데이터가 출력되는 것입니다.
해당 문제를 해결하기 위해 사용자가 회원정보 폼을 요청할 시 회원 정보를 DB에서 Select
한 이후 model
에 담아 최신화된 정보를 출력할 수 있도록 변경하였습니다.
@GetMapping("/user/updateForm")
public String updateForm(Authentication authentication, Model model){
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
model.addAttribute("userInfo", userService.findByName(userDetails.getUsername()));
return "user/updateForm";
}
컨트롤러에서 스프링시큐리티의 로그인 정보를 바탕으로 DB
의 User
정보를 Select
해줍니다.
해당 정보를 Model
에 담아 updateForm
으로 보내줍니다.
<form>
<div class="mb-3 mt-3">
<label for="username" class="form-label">UserName:</label>
<input type="text" class="form-control" id="username" th:value="${userInfo.username}" name="username" readonly>
</div>
<div class="mb-3">
<label for="password" class="form-label">Password:</label>
<input type="text" class="form-control" id="password" placeholder="Enter password" name="password">
</div>
<div class="mb-3 mt-3">
<label for="email" class="form-label">Email:</label>
<input type="email" class="form-control" id="email" th:value="${userInfo.email}" placeholder="Enter email" name="email">
</div>
</form>
이렇게 회원 정보를 수정한 이후 다시 회원 수정 페이지에 진입해도 최신화된 정보를 출력할 수 있게 수정 되었습니다.
다시 한 번 생각해보니 게시글 작성과 이후 구현할 댓글 기능도 스프링 시큐리티 세션의 정보를 기반으로 DB에 등록되기 때문에 해당 방법으로 변경하게되면 불필요한 코드가 많아집니다.
따라서 두 번째 해결 방법으로 코드를 수정합니다.
두 번째 해결 방법
불필요한 코드를 줄이기 위해 스프링 시큐리티 세션의 값을 강제로 최신의 정보로 변경시켜 어디에서든 최신화된 정보가 전달될 수 있도록 변경시키려 합니다.
회원 정보를 수정했을 시 스프링시큐리티 내부에서 새로운 정보를 토대로 재로그인이 실행되고 최신의 정보가 세션에 저장될 수 있도록 코드를 변경시켰습니다.
@Autowired
private AuthenticationManager authenticationManager;
@PutMapping("/user")
public ResponseDTO<Integer> update(@RequestBody User user){
userService.update(user);
// 서비스가 종료되면서 트랜잭션도 종료되어 DB의 값은 변경되지만
// 시큐리티 세션의 정보는 변경 되지 않은 상태이기 때문에 직접 세션의 값 변경이 필요하다.
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
user.getUsername(), user.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
return new ResponseDTO<Integer>(HttpStatus.OK.value(), 1);
}
'트러블슈팅' 카테고리의 다른 글
[Git] PR을 메인 브랜치로 잘못 머지한 상황 (0) | 2023.06.30 |
---|---|
[DB] JPA 무한참조 문제 (0) | 2023.03.18 |
[oAuth 2.0] 카카오 로그인 기능구현 시 고려할 점 (0) | 2023.03.18 |
[oAuth 2.0] 카카오 DB정보와 일치하지만 로그인에 실패하는 상황 (0) | 2023.03.18 |
[SpringSecurity, Thymeleaf] authorize메서드가 인식 되지 않는 상황 (0) | 2023.03.18 |