JSP

[JSP] Authentication - 로그인/로그아웃

shb 2022. 4. 10. 20:56

로그인/로그아웃

URL : 로그인 폼 작성하기
UserController
GET/POST 방식

 

 /WEB-INF/views -> login.jsp 생성

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>

    <title>로그인</title>
</head>

<body>

    <div class="container mt-3 text-center">
        <div class="row mt-5">
            <div class="col-12 text-danger">
                <!-- 에러 메세지 -->
            </div>
        </div>
        <form action="${pageContext.request.contextPath }/user/login" method="POST">
            <h1 class="h3 mb-3 fw-normal">로그인 하세요</h1>
	        <div class="row mt-5">
	            <div class="col-12 text-danger">
	                ${REDIRECT_ATTR.error }
	            </div>
	        </div>
            <div class="form-floating">
                <input type="text" class="form-control" name="username" id="username" value="${REDIRECT_ATTR.username }" placeholder="name@example.com" required>
                <label for="username">Username</label>
            </div>
            <div class="form-floating mt-1">
                <input type="password" class="form-control" name="password" id="password" value="" placeholder="Password" required>
                <label for="password">Password</label>
            </div>

            <div class="mb-3">
                <label>
                    <input type="checkbox" value="remember-me"> Remember me
                </label>
            </div>
            <button class="w-100 btn btn-lg btn-primary my-1" type="submit">로그인</button>
            <a class="w-100 btn btn-lg btn-primary my-1" href="${pageContext.request.contextPath }/user/register">회원가입</a>
            <p class="mt-2 mb-3 text-muted">&copy; 2017–2022</p>
        </form>
    </div>

</body>

</html>


* UserController

package controller;

import java.io.IOException;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import command.Command;
import command.user.LoginCommand;
import command.user.RegisterCommand;
import common.C;

@WebServlet("/user/*")
public class UserController extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    public UserController() {
        super();
    }

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		doAction(request, response);
	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setCharacterEncoding("UTF-8");  // 한글 인코딩
		doAction(request, response);
	}

	protected void doAction(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		System.out.println("UserController.actionDo() 호출");
		
		String method = request.getMethod();
				
		// URL로부터 URI, ContextPath, Command 분리
		String uri = request.getRequestURI();
		String conPath = request.getContextPath() + "/user";
		String com = uri.substring(conPath.length());
		
		
		// 테스트 출력
		System.out.println("uri: " + uri);  
		System.out.println("conPath: " + conPath);  
		System.out.println("com: " + com);

		Command command = null;   // 어떠한 로직을 수행할지
		String viewPage = null;   // 어떠한 페이지(뷰)를 보여줄지
	
		switch(com) {
		case "/register":
			if(method.equals("GET")) {	// GET 방식의 경우 회원가입 폼	
				C.retrieveRedirectAttribute(request);
				viewPage = "/user/register.jsp";
			} else {  // POST 의 경우
				new RegisterCommand().execute(request, response);
				// redirect 가 진행되면 이미 response 가 commit 됨. 
				// response 가 commit 되지 않은 경우만 jsp forward 진행
				if(!response.isCommitted()) viewPage = "/user/registerOk.jsp";
					
			}
			break;
		case "/login":
			if(method.equals("GET")) {  // GET 의 경우 로그인 폼
				C.retrieveRedirectAttribute(request);
				viewPage = "/user/login.jsp";
			} else {  // POST 의 경우 로그인 처리
				new LoginCommand().execute(request, response);
				
				// 로그인이 실패되면 위에서 redirect 되었을것이다
				// 로그인이 성공하면
				if(!response.isCommitted()) {
					// 기본적으로 home 으로 redirect 한다
					String redirectUrl = request.getContextPath() + "/home";
					
					// 혹시 url prior (원래 가고자 했더 url) 존재했다면 url로 redirect 한다
					String urlPrior = C.retrieveUrlPrior(request);
					if(urlPrior != null) redirectUrl = urlPrior;
					
					response.sendRedirect(redirectUrl);
				}
				
			}
			break;
		case "/logout":
			if(method.equals("POST")) {
				request.getSession().removeAttribute(C.PRINCIPAL);
				// 혹은 session.invalidate();
				response.sendRedirect(request.getContextPath() + "/home");
			}
			break;		
		case "/rejectAuth": 
			C.retrieveRedirectAttribute(request);
			viewPage = "/common/rejectAuth.jsp";
			break;
		} // end switch
		
		// 위에서 결정된 뷰 페이지(viewPage) 로 forward 해줌
		if(viewPage != null) {
			RequestDispatcher dispatcher 
				= request.getRequestDispatcher("/WEB-INF/views" + viewPage);
			// request 에 담겨있는 Command 수행결과도 viewPage 에 전달되는 것이다
			dispatcher.forward(request, response);
		}

	} // end doAction()

	
}

 

 


* LoginCommand

로그인 처리 -> command/LoginCommand


1. 검증
- 존재하지 않는 아이디(username) 의 경우
- 패스워드가 다른 경우
2. 검증 통과시 로그인 진행
- session 에 로그인한 사용자 정보 저장.

package command.user;

import java.io.IOException;
import java.sql.SQLException;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import command.Command;
import common.C;
import domain.UserDAO;
import domain.UserDTO;

public class LoginCommand implements Command {

	@Override
	public void execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
		//입력한 값을 받아오기
		String username = request.getParameter("username");
		String password = request.getParameter("password");

		String conPath = request.getContextPath();
		
		// ※ 파라미터 유효성 검증 필요
		username = username.trim().toUpperCase(); // 대문자로 비교
		password = password.trim();
		
		UserDTO dto = new UserDTO();
		dto.setUsername(username);
		
		try {
			// 존재하지 않는 아이디(username) 의 경우
			List<UserDTO> list = new UserDAO().selectByUsername(dto);			
			if(list.size() == 0) {
				response.sendRedirect(conPath + "/user/login");
				C.addRedirectAttribute(request, "error", "존재하지 않는 아이디(username)");
				C.addRedirectAttribute(request, "username", username);
				return;  // 종료
			}			
			
			// 패스워드가 다른 경우
			dto = list.get(0);
			if(!dto.getPassword().equals(password)) {
				response.sendRedirect(conPath + "/user/login");
				C.addRedirectAttribute(request, "error", "password 가 다릅니다");
				C.addRedirectAttribute(request, "username", username);
				return;  // 종료				
			}
			
			
			// 위 검증을 전부 통과하면 로그인 진행
			// session 에 로그인한 사용자 정보 저장.
			HttpSession session = request.getSession();
			session.setAttribute(C.PRINCIPAL, dto);  // 로그인한 회원의 정보를 세션에 저장
			
			
		} catch(SQLException e) {
			e.printStackTrace();
		}

	}

}

 

C.java에 가서 public static final String PRINCIPAL = "PRINCIPAL"; 만들기

-> 로그인 하면 저장되는 session name

로그인한 회원의 정보를 세션에 저장 C.PRINCIPAL


로그인 헤더 작성 header.jsp

/views/common/header.jsp 작성
home.jsp 에 include 하고 확인

로그인 여부,  권한여부에 따른 header 표시
header.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="fn" uri="http://java.sun.com/jsp/jstl/functions" %> 
   
    
<!DOCTYPE html>
<html lang="ko">

<head>
  <title>NavBar</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
</head>

<body>

  <nav class="navbar navbar-expand-sm navbar-dark bg-dark">
    <div class="container-fluid">
      <a class="navbar-brand" href="javascript:void(0)">Security</a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mynavbar">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="mynavbar">
        <ul class="navbar-nav me-auto">
          <!-- 누구에게나 보이는 메뉴 -->
          <li class="nav-item" TODO="">
            <a class="nav-link" href="javascript:void(0)">Anonymous</a>
          </li>
          
          <c:if test="${not empty sessionScope.PRINCIPAL }">
          <!-- 로그인한 사람에게만 보이는 메뉴 -->
          <li class="nav-item" TODO="">
            <a class="nav-link" href="javascript:void(0)">Authenticated</a>
          </li>          
          </c:if>
          
          <c:if test="${fn:contains(sessionScope.PRINCIPAL.authorities, 'ROLE_MEMBER') }">
          <!-- 로그인한 사람중 ROLE_MEMBER 권한 있는 사람에게만 보이는 메뉴 -->
          <li class="nav-item" TODO="">
            <a class="nav-link" href="javascript:void(0)">Member</a>
          </li>
          </c:if>
                    
          <c:if test="${fn:contains(sessionScope.PRINCIPAL.authorities, 'ROLE_ADMIN') }">
          <!-- 로그인한 사람중 ROLE_ADMIN 권한 있는 사람에게만 보이는 메뉴 -->
          <li class="nav-item" TODO="">
            <a class="nav-link" href="javascript:void(0)">Admin</a>
          </li>
          </c:if>
          
        </ul>
        
        
        <c:choose>
        	<c:when test="${empty sessionScope.PRINCIPAL }">
		        <!-- 로그인 안했을때는 로그인 form 보여주기 -->
		        <a class="btn btn-primary" type="submit" href="${pageContext.request.contextPath }/user/login">Login</a>
        	</c:when>
        	<c:otherwise>
		        <!-- 로그인 했을때는 username 과 로그아웃 form 보여주기 -->
		        <form action="${pageContext.request.contextPath }/user/logout" method="POST" TODO="">
		          <!--TODO : 로그아웃후 다시 돌아오기 -->
		          <span class="d-flex">
		            <span class="text-light p-2"><span TODO="">${sessionScope.PRINCIPAL.username }(${sessionScope.PRINCIPAL.name })</span> 님 환영합니다</span>
		            <span><button class="btn btn-danger" type="submit">Logout</button></span>
		          </span>
		        </form>
        	</c:otherwise>
        </c:choose>
        

      </div>
    </div>
  </nav>

  <div class="container-fluid mt-3">    
  	<c:choose>
  		<c:when test="${empty sessionScope.PRINCIPAL }">
		    <!-- 로그인 하지 않았을때 보여주는 화면 -->
		    <div TODO="" class="alert alert-warning alert-dismissible">
		      <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
		      로그인하지 않은 상태입니다 <br>
		    </div>  		
  		</c:when>
  		<c:otherwise>
		    <!-- 로그인 했을때 보여주는 화면 -->
		    <div TODO="" class="alert alert-info alert-dismissible">
		      <button type="button" class="btn-close" data-bs-dismiss="alert"></button>
		      <c:out value="${sessionScope.PRINCIPAL }"/><br>
		      로그인 하셨습니다 <br>
		    </div>  		
  		</c:otherwise>
  	</c:choose>
  	
  </div>

</body>

</html>

sessionScope.PRINCIPAL 이 존재하면 로그인한 것
empty sessionScope.PRINCIPAL -> sessionScope.PRINCIPAL이 비어있으면 = 로그인하지 않으면

 


로그아웃 구현하기

 

 

'JSP' 카테고리의 다른 글

[JSP] Pagination  (0) 2022.04.11
[JSP] Authentification - 회원제 게시판  (0) 2022.04.10
[JSP] Authentication - 회원가입  (0) 2022.04.07
[JSP] JSTL(JSP Standard Tag Library)  (0) 2022.04.06
[JSP] EL : Expression Language  (0) 2022.04.06