본문 바로가기
Java/Spring

Spring) 로그인 / 로그아웃 처리 (Model 세션 저장, 만료 처리)

by 박채니 2022. 8. 22.

안녕하세요, 코린이의 코딩 학습기 채니 입니다.

 

개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.


로그인

 

viewName이 null인 경우, 요청 url을 기준으로 jsp위치를 추론

/member/memberLogin.do → member/memberLogin으로 추론

@GetMapping("/memberLogin.do")
public void memberLogin() {

}

 

memberLogin.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인</title>

<script src="http://code.jquery.com/jquery-latest.min.js"></script>

<!-- bootstrap js: jquery load 이후에 작성할것.-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>

<!-- bootstrap css -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">

<!-- 사용자작성 css -->
<link rel="stylesheet" href="${pageContext.request.contextPath }/resources/css/style.css" />
<c:if test="${not empty msg}">
<script>
alert("${msg}");
</script>
</c:if>
</head>
<body>

	<!-- Modal시작 -->
	<!-- https://getbootstrap.com/docs/4.1/components/modal/#live-demo -->
	<div class="modal fade" id="loginModal" tabindex="-1" role="dialog"
		aria-labelledby="loginModalLabel" aria-hidden="true">
		<div class="modal-dialog" role="document">
			<div class="modal-content">
				<div class="modal-header">
					<h5 class="modal-title" id="loginModalLabel">로그인</h5>
					<button type="button" class="close" data-dismiss="modal" aria-label="Close">
						<span aria-hidden="true">&times;</span>
					</button>
				</div>
				<!--로그인폼 -->
				<!-- https://getbootstrap.com/docs/4.1/components/forms/#overview -->
				<form
					action="${pageContext.request.contextPath}/member/memberLogin.do"
					method="post">
					<div class="modal-body">
						<input 
							type="text" class="form-control" name="memberId"
							placeholder="아이디" required> 
						<br /> 
						<input
							type="password" class="form-control" name="password"
							placeholder="비밀번호" required>
					</div>
					<div class="modal-footer">
						<button type="submit" class="btn btn-outline-success">로그인</button>
						<button type="button" class="btn btn-outline-success" data-dismiss="modal">취소</button>
					</div>
				</form>
			</div>
		</div>
	</div>
	<!-- Modal 끝-->
<script>
$(loginModal).modal().on("hide.bs.modal", (e) => {
	location.href = "${pageContext.request.contextPath}/";
});
</script>
</body>
</html>

 

Controller

MemberController

matches() - 일치 여부 검사

@SessionAttributes - session scope에 속성 저장

@Controller
@RequestMapping("/member")
@Slf4j
@SessionAttributes({"loginMember"})
public class MemberController {
	@Autowired
	private MemberService memberService;
	
	@Autowired
	private BCryptPasswordEncoder bcryptPasswordEncoder;
	
	@PostMapping("/memberLogin.do")
    public String memberLogin(@RequestParam String memberId, @RequestParam String password, Model model, RedirectAttributes redirectAttr) {
        // 1. memberId로 조회
        Member member = memberService.selectOneMember(memberId);

        String location = "/";
        // 2. member가 null이 아니면서, 비밀번호가 일치하면 로그인 성공
        if(member != null && bcryptPasswordEncoder.matches(password, member.getPassword())) {
            // model을 통해 session scope에 속성 저장 : 클래스레벨에 @SessionAttributes로 등록
            model.addAttribute("loginMember", member);
        }	
        // 로그인실패
        else {
            redirectAttr.addFlashAttribute("msg", "아이디 또는 비밀번호가 일치하지 않습니다.");
            location += "member/memberLogin.do";
        }

        return "redirect:" + location;
    }
}

BcryptPasswordEncoder의 matches() 메소드를 이용하여 입력한 비밀번호와 일치하는 지 검사를 했습니다.

만일 일치하다면 model을 통해 session scope에 속성으로 저장되도록 하였습니다.

 

Model은 기본적으로 request scope에 저장되지만 @SessionAttributes로 등록을 함으로써 session scope에 저장할 수도 있습니다.

 

Service

MemberService interface 생략

MemberServiceImpl

@Override
public Member selectOneMember(String memberId) {
    return memberDao.selectOneMember(memberId);
}

 

Dao

MemberDao interface

Member selectOneMember(String memberId);

 

member-mapper.xml

<mapper namespace="com.ce.spring2.member.model.dao.MemberDao">
  <select id="selectOneMember" resultType="member">
  	select * from member where member_id = #{memberId}
  </select>
</mapper>

 

로그인 실패 시

 

로그인 성공 시


로그아웃

 

Controller

MemberController

SessionStatus#setComplete - 세션을 다 사용했다는 의미, 만료처리 (세션객체는 유지하되, 안에 내용만 제거)

/**
 * @SessionAttributes로 세션 관리를 한다면, SessionStatus#setComplete으로 만료처리! 
 */
@GetMapping("/memberLogout.do") 
public String memberLogout(SessionStatus sessionStatus) {

    if(!sessionStatus.isComplete()) {
        // 세션을 다 사용했다는 의미 - 만료 처리(세션 객체는 유지하되, 안에 내용만 제거)
        sessionStatus.setComplete();
    }

    return "redirect:/";
}

@SessionAttributes로 세션관리를 하기 때문여 SessionStatus#setComplete로 만료처리를 해주었습니다.

세션 객체는 그대로 유지하되, 안에 내용(속성)만 제거하는 것이므로 로그아웃 처리가 되어도 세션 아이디는 동일할 것입니다.

 

로그인 - 세션 아이디 : 2DA5597...

 

로그아웃 - 세션 아이디 : 2DA5597...

로그아웃 처리가 되어도 세션아이디가 그대로 유지 되고 있는 것을 확인할 수 있습니다.

- 세션 객체를 효율적으로 관리!