// 로그인 양식 열기
// @RequestParam(required = false) String redirect
// -> 사용자가 로그인한 후에 가고 싶어하는 페이지 주소 (이 요청이 필수는 아니야!)
@GetMapping("/sign-in")
public String signIn(HttpSession session
, @RequestParam(required = false) String redirect)
{
// redirect를 session에 저장 (로그인 후에 어디 갈지 기억함)
session.setAttribute("redirect", redirect);
log.info("/members/sign-in GET : forwarding to sign-in.jsp");
return "members/sign-in";
}
// 로그인 요청 처리
@PostMapping("/sign-in")
public String signIn(LoginDto dto,
RedirectAttributes ra,
HttpServletRequest request) {
log.info("/members/sign-in POST"); // 로그에 "로그인 요청이 들어왔어요"라고 기록
// LoginDto에 @Setter 없으면 에러! (로그의 중요성) 꼭 찍어보자
log.debug("parameter: {}", dto); // 사용자가 입력한 로그인 정보를 로그에 기록
// 세션 얻기
HttpSession session = request.getSession();
LoginResult result = memberService.authenticate(dto, session);
// 로그인 검증 결과를 수송객체를 통해 JSP에게 보내기
// Redirect시에 Redirect된 페이지에 데이터를 보낼 떄는
// Model객체를 사용할 수 없음
// 왜냐면 Model 객체는 request 객체를 사용하는데 해당 객체는
// 한 번의 요청이 끝나면 메모리에서 제거된다. 그러나 redirect는
// 요청이 2번 발생하므로 다른 request객체를 jsp가 사용하게 됨
// model.addAttribute("result", result); // (X)
ra.addFlashAttribute("result", result);
if(result == LoginResult.SUCCESS) {
// 혹시 세션에 저장된 리다이렉트 URL이 있다면
String redirect = (String) session.getAttribute("redirect");
if (redirect != null) {
session.removeAttribute("redirect");
return "redirect:" + redirect;
}
return "redirect:/index"; // 로그인 성공시
}
return "redirect:/members/sign-in"; // 로그인 실패시 다시 제자리
}
@GetMapping("/sign-out")
public String signOut(HttpSession session) {
// 세션구하기
// 스프링에서 HttpSession 파라미터로 하면 request에서 session 구해줌
// HttpSession session = request.getSession();
// 세션에서 로그인 기록 삭제
session.removeAttribute("login");
// 세션을 초기화
session.invalidate();
// 홈으로 보내기
return "redirect:/";
}
// 로그인 검증 처리
public LoginResult authenticate(LoginDto dto, HttpSession session) {
// 회원의 아이디를 통해 회원가입 여부 확인 (findOne)
String account = dto.getAccount();
Member foundMember = memberMapper.findOne(account);
// 회원가입이 안되었을 때
if (foundMember == null) {
log.info("{} = 회원가입이 필요합니다.", account);
return NO_ACC;
}
// 비밀번호 일치 검사
String inputPassword = dto.getPassword(); // 클라이언트에 입력한 비밀번호
String originPassword = foundMember.getPassword(); // DB에 저장된 비밀번호
// PasswordEncoder에서는 암호화된 비번을 내부적으로 비교해주는 기능을 제공
// 확인해주는 기능만 제공
if (!encoder.matches(inputPassword, originPassword)) {
log.info("비밀번호가 일치하지 않습니다.");
return NO_PW;
}
log.info("{}님 로그인 성공", foundMember.getName());
// 세션의 수명 : 설정된 시간 OR 브라우저를 닫기 전까지
int maxInactiveInterval = session.getMaxInactiveInterval();
session.setMaxInactiveInterval(60 * 60); // 세션 수명 1시간 설정
log.debug("sessiontime: {}", maxInactiveInterval);
// 로그인에 성공했을 때 클라이언트에 보낼 정보를 LoginUserInfoDto 객체에 담아서
// 로그인한 사용자의 정보를 세션에 저장! (비밀번호는 제외)
session.setAttribute(LOGIN, new LoginUserInfoDto(foundMember));
return SUCCESS;
}
public class LoginUserInfoDto {
// 클라이언트에 보낼 정보
private String account;
private String nickname;
private String email;
private String auth;
public LoginUserInfoDto(Member member) {
this.account = member.getAccount();
this.email = member.getEmail();
this.nickname = member.getName();
this.auth = member.getAuth().name();
}
}
${login.nickname}
추가true
이면 요청이 계속 진행되고, false
이면 요청이 중단됩니다.// 만들어 놓은 인터셉터들을 스프링 컨텍스트에 등록하는 설정 파일
@Configuration // 설정파일을 의미
@RequiredArgsConstructor
public class InterceptorConfig implements WebMvcConfigurer {
private final AfterLoginInterceptor afterLoginInterceptor;
private final BoardInterceptor boardInterceptor;
// 설정 메서드
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 로그인 인터셉터 등록
registry
.addInterceptor(afterLoginInterceptor)
// 해당 인터셉터가 동작할 URL을 설정
.addPathPatterns("/members/sign-up", "/members/sign-in")
;
// 게시판 인터셉터 등록
registry
.addInterceptor(boardInterceptor)
.addPathPatterns("/board/*")
.excludePathPatterns("/board/list", "/board/detail")
;
}
// 로그인한 회원은 회원가입페이지와 로그인페이지에 접근을 차단
@Configuration // 설정 파일
@Slf4j
public class AfterLoginInterceptor implements HandlerInterceptor {
// 클라이언트의 요청이 컨트롤러에 들어가기 전에 해야할 일을 명시
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.debug("after login interceptor execute!");
// 로그인이 되었다면 홈으로 redirect
// InterceptorConfig에 설정된 부분은 진입 차단 (false 이므로)
if (LoginUtil.isLoggedIn(request.getSession())) {
response.sendRedirect("/");
return false; // true일 경우 컨트롤러 진입 허용, false 진입 차단
}
return true;
}
}
@Configuration
@Slf4j
public class BoardInterceptor implements HandlerInterceptor {
// preHandle을 구현하여
// 로그인을 안한 회원은 글쓰기, 글수정, 글삭제 요청을 거부할 것!
// 거부하고 로그인 페이지로 리다이렉션할 것!
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 로그인 안한 회원
if(!LoginUtil.isLoggedIn(request.getSession())) {
String redirectURI = request.getRequestURI();
response.sendRedirect("/members/sign-in?message=login-required&redirect=" + redirectURI);
return false;
}
return true;
}
}
-> 로그인했을 때의 계정명을 불러와야 하므로 게시글 등록 요청할 때 session 추가
-> 여기서 DTO -> Entity의 과정을 거친다.
BoardWriteRequestDto에는 내가 게시글을 입력할 때 필요한 title, content, writer가 저장된다. 하지만 게시글을 저장할 때, 누가 이 게시글을 작성했는지를 알기 위해 사용자 계정 정보도 필요한데 이 정보는 세션에 저장되어있기 때문에 Entity로 바꿔서 DB와 연결되어서 로그인된 계정을 가지고와서 save한다.
B.account
추가