@3/17/2023
프론트단에서 해싱을 해야할까?
결론은 https에서는 비밀번호가 평문전송되지 않으니 굳이 해싱할 필요가 없다는 것
ERD 수정
•
password와 loginId 필드 추가
•
엔티티 다이어그램
•
DB 테이블 ERD
•
그 외 엔티티, DTO 등 필드 추가 및 코드 변경
로그인 화면 띄우기
•
타임리프
<form action="/users/login" method="post" class="container login"
th:object="${loginForm}">
<div class="row d-flex flex-column justify-content-between align-items-center gap-4">
<h4 class="h1 text-center">로그인</h4>
<th:block th:if="${#fields.hasGlobalErrors()}">
<div th:each="err : ${#fields.globalErrors()}" th:text="${err}" class="alert alert-danger mb-0" role="alert">
에러 메시지
</div>
</th:block>
<div class="input-group input-group-lg p-0">
<span class="input-group-text w-25 fs-6">아이디</span>
<input type="text" class="form-control" aria-label="Sizing example input"
th:field="*{loginId}">
</div>
<div class="input-group input-group-lg p-0">
<span class="input-group-text w-25 fs-6">비밀번호</span>
<input type="password" class="form-control" aria-label="Sizing example input"
th:field="*{password}">
</div>
<button type="submit" class="btn btn-primary btn-lg">로그인</button>
<button type="button" class="btn btn-outline-secondary btn-lg">회원가입</button>
</div>
</form>
JavaScript
복사
•
User 컨트롤러
◦
타임리프에서 th:object를 사용했기 때문에 폼을 건네주는 컨트롤러에도 ModelAttribute를 받아서 뷰에 넘겨줘야 함
package dev.gyuray.forum.controller;
...
@Controller
@RequestMapping("/users")
@RequiredArgsConstructor
@Slf4j
public class UserController {
private final UserService userService;
@GetMapping("/login")
public String loginForm(
@ModelAttribute LoginForm loginForm,
Model model
) {
model.addAttribute("hideLoginButtons", "true");
return "users/loginForm";
}
@PostMapping("/login")
public String login(
@ModelAttribute LoginForm loginForm,
BindingResult bindingResult,
Model model
) {
User loginUser = userService.login(loginForm.getLoginId(), loginForm.getPassword());
if (loginUser == null) {
bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다.");
model.addAttribute("hideLoginButtons", "true");
return "users/loginForm";
}
return "redirect:/posts";
}
}
Java
복사
•
UserService
◦
로그인 서비스를 따로 만들지 않고 일단 유저 서비스에 만듦
public User login(String loginId, String password) {
return userRepository.findByLoginId(loginId).stream()
.filter((user) -> user.getPassword().equals(password))
.findAny().orElse(null);
}
Java
복사
•
UserRepository
public List<User> findByLoginId(String loginId) {
return em.createQuery("select u from User u where u.loginId = :loginId", User.class)
.setParameter("loginId", loginId)
.getResultList();
}
Java
복사
◦
김영한님은 UserRepository의 findByLoginId를 아래처럼 구현함
public Optional<Member> findByLoginId(String loginId) {
return findAll().stream()
.filter(m -> m.getLoginId().equals(loginId))
.findAny();
}
Java
복사
▪
하지만 나는 findBy~ 의 반환형을 List<User>로 통일하기 위해 Repository단에서 Optional로 변환하지 않음(일관성 중시)
결과 화면
•
실패 시 아이디 데이터가 유지되면서 경고차 발생. 성공 시 홈화면으로 이동