로그인
인터셉터를 이용한 로그인 관리.
시큐리티사용시 사용자 유지등을 직접 작성하지 않아도 됨.
- LoginCheckInterceptor -
// 새 인터셉터 클래스를 만들어 인터페이스 HandlerInterceptor를 구현하여 인터셉터 만들기
// 로그인 후 컨트롤러를 거치는 페이지로 이동 시 계속해서 인증된 상태인지 확인
public class LoginCheckInterceptor implements HandlerInterceptor {
// preHandle메서드: 컨트롤러에 가기 전 Interceptor에서 캐치하여 작업수행
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session = request.getSession(); // 세션 불러오기
User user = (User) session.getAttribute("user");
if (user == null) {
// 로그인인증이 안된상태 => 로그인 화면으로 이동
String url = session.getServletContext().getContextPath() + "/login";
response.sendRedirect(url);
System.out.println("LoginInterceptor # preHandle() : 로그인 인증안됨");
return false;
}
// 인터셉터 메서드에서 리턴이 true이면 통과, false이면 차단
System.out.println("LoginInterceptor # preHandle() : 인증됨");
return true;
}
}
핸들러 인터셉터를 구현한 클래스를 만듦.
session.getServletContext().getContextPath()
: 현재 프로젝트의 주소(localhost:8080)에 /login 을 붙여 로그인 화면으로 이동시킴
if문에 걸리지 않으면 조건을 통과한 셈이므로 통과코드를 굳이 else문 아래에 작성할 필요는 없음.
- WebConfig -
모든 페이지에 적용시킬 예정이므로 bbs패키지 아래의 메인클래스와 함께 위치시킴.
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 인터셉터를 추가하는 메서드
registry
.addInterceptor(new LoginCheckInterceptor()) // 앞서 구현한 클래스를 사용
.addPathPatterns("/board/**") // 인터셉터를 적용할 컨트롤러 주소 (/board로 시작하는 모든 주소)
.excludePathPatterns("/board/list", "/board/get"); // 적용안할 주소(로그인 안해도 게시판 조회는 가능하도록)
}
}
WebMvcConfigurer
인터페이스의 기능을 구현하여 사용.
/board 페이지에 접근할때 로그인인증여부를 체크하여 권한을 주되, 예외패턴을 두어 게시글을 조회하는 기능(리스트 조회, 단일 조회)은 인증여부와 관계없이 모두 가능하도록 함.
로그인 인증이 안된 상태로 게시글 수정, 삭제 기능 사용 시 지정해둔 문구가 콘솔에 출력되며 로그인화면으로 이동함.
전체 컨트롤러에 적용시킬 Common클래스 생성
- Common -
@ControllerAdvice // 모든 컨트롤러에 적용
public class Common {
@ModelAttribute // 모든 컨틀로러의 모델에 추가
public void sharedData(Model model, HttpSession session) {
// 세션에 인증된 유저가 있으면 유저이름을 모든 페이지에 전달
User user = (User) session.getAttribute("user");
if (user != null) {
model.addAttribute("userName", user.getName()); // 유저객체가 있으면 username을 저장
}
}
}
@ControllerAdvice
@ModelAttribute
@ControllerAdvice, @ExceptionHandler를 이용한 예외처리
- LoginController -
@GetMapping("/logout")
public String getLogout(HttpSession session) {
session.invalidate(); // 모든 세션 삭제
// session.removeAttribute("user"); // 로그아웃 시 세션의 user객체 제거
attr.addFlashAttribute("message", "Logout됨!");
return "redirect:/login";
}
removeAttribute()
은 세션의 특정 값을 삭제
invalidate()
는 세션과 세션에 저장된 값 모두를 삭제
- nav.html -
로그인 인증이 되었을땐 로그아웃버튼을, 인증이 안되었을땐 로그인 버튼을 활성화
<ul class="ms-auto navbar-nav justify-content-end">
<li class="nav-item d-flex align-items-center" th:if="${userName != null}">
<form th:action="@{/logout}" method="get">
<span th:text="${'😆 안녕하세요!, ' + userName}"></span>
<button type="submit" class="badge bg-gradient-warning ms-3">로그아웃</button>
</form>
</li>
<li class="nav-item d-flex align-items-center" th:if="${userName == null}">
<a th:href="@{/login}" class="nav-link text-body font-weight-bold px-0">
<i class="fa fa-user me-sm-1"></i>
<span class="d-sm-inline d-none">로그인</span>
</a>
</li>
- aside.html -
<li class="nav-item" th:if="${userName}">
<a class="nav-link text-white" th:href="@{/profile}">
<div class="text-white text-center me-2 d-flex align-items-center justify-content-center">
<i class="material-icons opacity-10">person</i>
</div>
<span class="nav-link-text ms-1">프로파일</span>
</a>
</li>
<li class="nav-item" th:if="${userName == null}">
<a class="nav-link text-white" th:href="@{/login}">
<div class="text-white text-center me-2 d-flex align-items-center justify-content-center">
<i class="material-icons opacity-10">login</i>
</div>
<span class="nav-link-text ms-1">로그인</span>
</a>
</li>
<li class="nav-item" th:if="${userName}">
<a class="nav-link text-white" th:href="@{/logout}">
<div class="text-white text-center me-2 d-flex align-items-center justify-content-center">
<i class="material-icons opacity-10">logout</i>
</div>
<span class="nav-link-text ms-1">로그아웃</span>
</a>
</li>
<li class="nav-item" th:if="${userName == null}">
<a class="nav-link text-white" th:href="@{/register}">
<div class="text-white text-center me-2 d-flex align-items-center justify-content-center">
<i class="material-icons opacity-10">assignment</i>
</div>
<span class="nav-link-text ms-1">가입하기</span>
</a>
</li>
로그인o => 프로파일, 로그아웃 활성화
로그인x => 로그인, 가입하기 활성화
로그인인증이 안됐을때를 선택하려면 th:if="${userName == null}"
를 써야함.
th:if="${!userName}"
사용 시 에러발생