로그인, 로그아웃 기능을 구현하고, 인터셉터를 이용해 로그인이 되어있지 않은 경우, 게시판에 접근 할 수 없게 구현할 것
- MemberService 로그인 메서드 추가
public MemberResponse findMemberByLoginId(final String loginId) {
return memberMapper.findByLoginId(loginId);
}
/**
* 회원 정보 수정
* @param params - 회원 정보
* @return PK
*/
@Transactional
public Long updateMember(final MemberRequest params) {
params.encodingPassword(passwordEncoder);
memberMapper.update(params);
return params.getId();
}
/**
* 회원 정보 삭제 (회원 탈퇴)
* @param id - PK
* @return PK
*/
@Transactional
public Long deleteMemberById(final Long id) {
memberMapper.deleteById(id);
return id;
}
회원정보 수정 : 로그인 페이지에 입력한 아이디와 비밀번호를 전달받아 회원 정보를 조회한다.
encodingPassword는 회원 테이블에 암호화된 비밀번호이다. member가 null인 경우에 member.getPassword()를 실행시 NPE가 발생하기 때문에 빈문자열(" ")로 처리한다
회원 정보 및 비밀번호 체크 :passwordEncoder의 matches()로 사용자가 입력한 비밀번호와 회원 테이블에 암호화된 비밀번호를 비교한다. 두 조건 모두 false인 경우가 정상적인 케이스이다.
회원 정보 삭제(회원 탈퇴) :member.clearPassword() 로 암호화된 회원의 비밀번호를 초기화 (" " ) 한 후 회원 응답 객체를 리턴한다.
-MemberController 로그인 로그아웃 메서드 추가하기
// 로그인
@PostMapping("/login")
@ResponseBody
public MemberResponse login(HttpServletRequest request) {
// 1. 회원 정보 조회
String loginId = request.getParameter("loginId"); //이 정보를 받아오기
String password = request.getParameter("password");
MemberResponse member = memberService.login(loginId, password);
// 2. 세션에 회원 정보 저장 & 세션 유지 시간 설정
if (member != null) {
HttpSession session = request.getSession();
session.setAttribute("loginMember", member); //사용자 정보 세션에 저장
session.setMaxInactiveInterval(60 * 30);
}
return member;
}
// 로그아웃
@PostMapping("/logout")
public String logout(HttpSession session) {
session.invalidate();
return "redirect:/login.do";
}
}
메서드
login : 1.request 객체의 getParameter() 사용자가 로그인 페이지에 입력한 아이디와 비밀번호를 변수에 담아 회원 정보를 조회한다.
logout() : session.invaildate() 로 세선을 무효화( 초기화) 한 후 사용자를 로그인 페이지로 이동시킵니다.
- 로그인(세션) 체크용 인터셉터 추가하기
로그인 상태를 확인할 인터셉터를 추가합니다.
package com.study.interceptor;
import com.study.domain.member.MemberResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginCheckInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 1. 세션에서 회원 정보 조회
HttpSession session = request.getSession();
MemberResponse member = (MemberResponse) session.getAttribute("loginMember");
// 2. 회원 정보 체크
if (member == null || member.getDeleteYn() == true) {
response.sendRedirect("/login.do");
return false;
}
return HandlerInterceptor.super.preHandle(request, response, handler);
}
}
1 : MemberController의 login() 에서세션에 저장한 회원 정보를 조회합니다
2 : member객체가 null이면 로그인이 되어있지 않음을 의미한다. 2번의 조건이 하나라도 true인 경우에는 사용자를 로그인 페이지로 이동시키는데 이를 통해 url을 입력해 강제로 게새판에 접근하는 사용자를 막을 수 있다.
-애플리케이션에 인터셉터 등록하기
package com.study.config;
import com.study.interceptor.LoggerInterceptor;
import com.study.interceptor.LoginCheckInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoggerInterceptor())
.excludePathPatterns("/css/**", "/images/**", "/js/**");
registry.addInterceptor(new LoginCheckInterceptor())
.addPathPatterns("/**/*.do")
.excludePathPatterns("/log*");
}
}
앞에 추가한 인터셉터 클래스도 스프링이 인식할 수 있도록 config클래스에 등록해준다.
메서드
addInterceptors() : 이전에 로그용 인터셉터를 처리하는 과정에서 구현한 오버라이드 메서드이다. 애플리케이션내의 모든 페이지 URI에 접근할 떄 LoginCheckInterceptor의 preHandle()이 작동한다. excludePathPatterns()을 이용해 로그인 페이지와 로그인, 로그아웃 URI인터셉터 실행에서 제외시킨다 만약 로그인, 로그아웃 관련 uri를 호출했을 때 인터셉터가 작동하게 되면 LoginCheckInterceptor의 preHandle()에 의해 계속해서 로그인 페이지를 호출하는 무한 루프에 빠지게 된다.
- login.html 로그인 함수 추가하기
// Enter 로그인 이벤트 바인딩
window.onload = () => {
document.querySelectorAll('#loginId, #password').forEach(element => {
element.addEventListener('keyup', (e) => {
if (e.keyCode === 13) {
login();
}
})
})
}
// 로그인
function login() {
const form = document.getElementById('loginForm');
if ( !form.loginId.value || !form.password.value ) {
alert('아이디와 비밀번호를 모두 입력해 주세요.');
form.loginId.focus();
return false;
}
$.ajax({
url : '/login',
type : 'POST',
dataType : 'json',
data : {
loginId: form.loginId.value,
password: form.password.value
},
async : false,
success : function (response) {
location.href = '/post/list.do';
},
error : function (request, status, error) {
alert('아이디와 비밀번호를 확인해 주세요.');
}
})
}
로그인 페이지에 MemberController의 login()을 호출할 onload()와 login()함수를 추가한다.
함수
onload() : 해당 함수 안의 로직은 로그인 페이지의 아이디와 패스워드 필드에서 엔터 입력 시 login()을 호출할 수 있도록 이벤트를 바인딩하는 역할을 합니다
login() : MemberController의 login()을 호출해서 로그인을 시도한다. 로그인에 성공ㅎ아면 게시글 리스트 페이지로 이동하고, 실패했을 땐 error()안 alert메시지를 보내준다.
이 함수는 로그인에 실패했을 때 에러가 발생하는데 @ResponseBody가 선언된 컨트롤러의 메소드가 null을 리턴하면 Ajax호출 시 에러가 발생하기 때문에 callAPi()를 사용하지 않고 Ajax 함수를 따로 선언해주었다.
- body.html 회원이름 출력, 로그아웃 폼 추가
<header>
<div class="head">
<h1>대림 게시판 </h1>
<div th:if="${session.loginMember != null}" class="top_menu">
<div class="login_user"><strong><i class="far fa-user-circle"></i> [[ ${session.loginMember.name} ]]</strong>님 반갑습니다.</div>
<div class="logout">
<form action="/logout" method="post">
<button type="submit"><span class="skip_info">로그아웃</span><i class="fas fa-sign-out-alt"></i></button>
</form>
</div>
</div>
</div>
</header>
태그
div.top_menu : 로그인된 경우에만 출력되는 태그,
form : 로그아웃action을 호출하는 폼 태그이다. MemberController의 logout을 호출해 세선을 초기화한다.
'JAVA > SpringBoot' 카테고리의 다른 글
게시판 프로젝트 - 첨부파일 추가, 수정, 삭제 및 기존 파일 유지 (1) | 2023.11.15 |
---|---|
게시판 프로젝트 - 다중 첨부 파일 업로드, 다운로드 구현 (0) | 2023.11.15 |
게시판 프로젝트 - 회원가입 기능 (1) | 2023.11.15 |
게시판 프로젝트 - Ajax(비동기) 페이징 새로고침시 페이지 번호 유지하기 (0) | 2023.11.15 |
게시판 프로젝트 - 댓글 페이징 처리 (0) | 2023.11.15 |