관련 포스팅 :# Spring - 미니쇼핑몰 상품관리 구현해보기(상품목록, 상세보기)
관련 포스팅 :# Spring - 미니쇼핑몰 상품관리 구현해보기(장바구니 담기, 목록, 수정, 삭제)
관리자 권한으로 로그인하여 상품의 정보를 추가, 수정, 삭제할 수 있도록 관리자 영역을 추가하고, 외부 사용자가 관리자 영역을 접근할 수 없도록 인터셉터로 처리해보았다.
이전 포스팅과 마찬가지로 전에 구현했던 내용과 유사하기 때문에 새로 알게된 내용 위주로 정리해보자.
DB(Oracle)
1. 관리자 테이블 생성
CREATE TABLE tbl_admin (
user_id VARCHAR(50) NOT NULL
, user_pw VARCHAR(50) NOT NULL
, user_name VARCHAR(50) NOT NULL
, user_email VARCHAR(100)
, user_regdate DATE DEFAULT SYSDATE
, user_updatedate DATE DEFAULT SYSDATE
PRIMARY KEY(user_id)
);
관리자와 사용자를 구분하는 방법에는 여러가지 방법이 있겠지만 지금까지 구현해본 방법은 두가지 이다.
- 사용자 테이블에서 권한 칼럼을 추가하여 0이면 사용자, 1이면 관리자로 구별하는 방법
- 회원 테이블, 관리자 테이블을 따로 관리하는 법
두가지 방법중에 2번을 선택!
그 이유는 첫번째 방법으로 하려면 지금까지 작성한 코드를 많이 수정해야되기 때문에 관리자 테이블을 추가하는 방법으로 진행
View(JSP)
1. 관리자 로그인 페이지(adminLogin.jsp)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>관리자 로그인페이지</title>
<%@ include file="../include/header.jsp" %>
<script>
$(document).ready(function(){
$("#btnLogin").click(function(){
// 태크.val() : 태그에 입력된 값
// 태크.val("값") : 태그의 값을 변경
var userId = $("#userId").val();
var userPw = $("#userPw").val();
if(userId == ""){
alert("아이디를 입력하세요.");
$("#userId").focus(); // 입력포커스 이동
return; // 함수 종료
}
if(userPw == ""){
alert("비밀번호를 입력하세요.");
$("#userPw").focus();
return;
}
// 폼 내부의 데이터를 전송할 주소
document.form1.action="${path}/admin/loginCheck.do"
// 제출
document.form1.submit();
});
});
</script>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>관리자 로그인</h2>
<form name="form1" method="post">
<table border="1" width="400px">
<tr>
<td>아이디</td>
<td><input name="userId" id="userId"></td>
</tr>
<tr>
<td>비밀번호</td>
<td><input type="password" name="userPw" id="userPw"></td>
</tr>
<tr>
<td colspan="2" align="center">
<button type="button" id="btnLogin">로그인</button>
<c:if test="${msg == 'failure'}">
<div style="color: red">
아이디 또는 비밀번호가 일치하지 않습니다.
</div>
</c:if>
<c:if test="${msg == 'logout'}">
<div style="color: red">
로그아웃되었습니다.
</div>
</c:if>
</td>
</tr>
</table>
</form>
</body>
</html>
<form name="form1" method="post">
- 로그인의 경우에는 항상 post방식으로 값을 전송 (get방식은 보안에 취약)
<c:if test="${msg == 'failure'}"></c:if>
- 컨트롤러로부터 리턴받은 문자열이
failure
이면 “아이디,비밀번호가 일치하지 않습니다.”라는 메시지를 출력
<c:if test="${msg == 'logout'}">
- 로그아웃 처리후 컨트롤러로부터 리턴받은 문자열이
logout
이면 “로그아웃되었습니다”라는 메시지 출력
2. 상단메뉴 및 관리자 메인페이지(menu.jsp, adminHome.jsp)
일반 사용자 로그인 상태 및 일반 메인페이지
관리자 권한 로그인 상태 및 관리자 메인페이지
상단메뉴(menu.jsp)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!-- 일반 메뉴 -->
<a href="${path}/board/list.do">게시판</a> |
<a href="${path}/upload/uploadForm">업로드</a> |
<a href="${path}/upload/uploadAjax">업로드(AJAX)</a> |
<a href="${path}/shop/product/list.do">상품목록</a> |
<a href="${path}/shop/cart/list.do">장바구니</a> |
<!-- 관리자 권한일 경우 -->
<c:if test="${sessionScope.adminId != null }">
<a href="${path}/shop/product/write.do">상품등록</a> |
</c:if>
<!-- 로그인, 로그아웃 -->
<c:choose>
<c:when test="${sessionScope.userId == null}">
<a href="${path}/member/login.do">로그인</a> |
<a href="${path}/admin/login.do">관리자 로그인</a>
</c:when>
<c:otherwise>
${sessionScope.userName}님이 로그인중입니다.
<a href="${path}/member/logout.do">로그아웃</a> |
</c:otherwise>
</c:choose>
<hr>
<c:if test="${sessionScope.adminId != null }">
- session에 저장된 ID가 관리자ID이면 상품등록 메뉴 출력
관리자 메인페이지(adminHome.jsp)
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<title>Home</title>
<%@ include file="../include/header.jsp" %>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<c:if test="${msg == 'success'}">
<h2>${sessionScope.adminName}
(${sessionScope.adminId})님 환영합니다.</h2>
</c:if>
${result}
</body>
</html>
<c:if test="${msg == 'success'}">
컨트롤러로부터 리턴받은 문자열이success
이면 관리자명과 관리자ID를 출력
Controller(흐름제어)
1. AdminController - 관리자 관련 컨트롤러
@Controller
@RequestMapping("admin/*")
public class AdminController {
@Inject
AdminService adminService;
// 1. 관리자 로그인페이지 매핑
@RequestMapping("login.do")
public String login(){
return "admin/adminLogin";
}
// 2. 관리자 로그인 체크
@RequestMapping("loginCheck.do")
public ModelAndView loginCheck(HttpSession session, MemberVO vo, ModelAndView mav){
String name = adminService.loginCheck(vo);
// 로그인 성공
if(name != null) {
session.setAttribute("adminId", vo.getUserId());
session.setAttribute("userId", vo.getUserId());
session.setAttribute("adminName", name);
session.setAttribute("userName", name);
mav.setViewName("admin/adminHome"); // 관리자 페이지 이동
mav.addObject("msg", "success");
// 로그인 실패
} else {
mav.setViewName("admin/adminLogin"); // 로그인 페이지 이동
mav.addObject("msg", "failure");
}
return mav;
}
// 3. 관리자 로그아웃
@RequestMapping("logout.do")
public ModelAndView logout(HttpSession session){
session.invalidate();
ModelAndView mav = new ModelAndView();
mav.setViewName("admin/adminLogin");
mav.addObject("msg", "logout");
return mav;
}
}
@RequestMapping("login.do")
: 관리자 로그인 페이지 매핑
- 로그인 페이지로 포워드
@RequestMapping("loginCheck.do")
- 관리자 로그인 성공하면 관리자 메인페이지로 포워딩하고,
success
문자열을 리턴- 로그인 실패하면 로그인 페이지로 포워딩하고,
failure
문자열을 리턴
@RequestMapping("logout.do")
session.invalidate()
로그아웃 처리후 로그인 페이지로 포워딩하고,logout
문자열을 리턴
Service(비지니스 로직, DB연동 이외의 핵심업무 처리)
1. AdminServiceImpl(AdminService인터페이스를 구현한 클래스)
@Service
public class AdminServiceImpl implements AdminService {
@Inject
AdminDAO adminDao;
// 관리자 로그인체크
@Override
public String loginCheck(MemberVO vo) {
return adminDao.loginCheck(vo);
}
}
loginCheck(MemberVO vo)
: adminDao의 로그인체크 메서드 호출
DAO(비지니스 로직, DB연동 작업처리)
1. AdminDAOImpl(AdminDAO인터페이스를 구현한 클래스)
@Repository
public class AdminDAOImpl implements AdminDAO {
@Inject
SqlSession sqlSession;
// 관리자 로그인체크
@Override
public String loginCheck(MemberVO vo) {
return sqlSession.selectOne("admin.loginCheck", vo);
}
}
loginCheck(MemberVO vo) : 관리자 테이블을 select조회한 결과를 리턴
MybatisMapper
1. 관리자 관련 mapper(adminMapper.xml)
<mapper namespace="admin">
<!-- 관리자 로그인 체크 -->
<select id="loginCheck" resultType="String">
SELECT user_name AS userName
FROM tbl_admin
WHERE user_id = #{userId} AND user_pw = #{userPw}
</select>
</mapper>
loginCheck
: 관리자 테이블에서 관리자이름(userName)을 select조회, WHERE조건 id, pw
관리자 영역 설정하기(Interceptor)
관리자 인증이 필요한 페이지는 관리자 이외의 외부 사용자는 접근하지 못하도록 interceptor를 이용하여 로그인페이지로 리다이렉트시킨다.
즉, 다시 말하자면 상품 등록, 수정, 삭제처리를 관리자 이외의 다른 사람이 요청할 수 없도록 처리하였다.
AdminInterceptor의 흐름은 위의 흐름과 같다.
- preHandle() —> return true —> write.do —> postHandle()
- preHandle() —> return false —> login.do
1. Interceptor설정
servlet-context.xml
<!-- 관리자 세션체크 bean등록 -->
<beans:bean id="adminInterceptor" class="com.example.spring02.interceptor.AdminInterceptor"/>
<interceptors>
<!-- 관리자 세션체크 매핑-->
<interceptor>
<mapping path="/shop/product/write.do"/>
<mapping path="/shop/product/insert.do"/>
<mapping path="/shop/product/update.do"/>
<mapping path="/shop/product/edit/**"/>
<mapping path="/shop/product/delete.do"/>
<beans:ref bean="adminInterceptor"/>
</interceptor>
</interceptors>
2. AdminInterceptor클래스
public class AdminInterceptor extends HandlerInterceptorAdapter{
// 요청 전 처리
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 세션객체 생성
HttpSession session = request.getSession();
// session에 관리자id가 null이면
if(session.getAttribute("adminId") == null){
response.sendRedirect(request.getContextPath()+"/member/login.do?msg=nologin"); //일반사용자 로그인화면으로 리다이렉트
return false; // 요청 실행 X
// null이 아니면
} else {
return true; // 요청 실행 O
}
}
// 요청 처리 후
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
super.postHandle(request, response, handler, modelAndView);
}
}
response.sendRedirect(request.getContextPath()+"/member/login.do?msg=nologin");
- session에 관리자id가 null일 경우, 일반사용자 로그인화면으로 리다이렉트하고, false를 리턴
- null이 아닐 경우는 true를 리턴
3. 구현화면
관리자 영역 설정 전
관리자 영역을 인터셉터로 설정안했을 경우, 미인증된 사용자가 상품등록 페이지 요청을 하면 그대로 요청이 실행된다.
관리자 영역 설정 후
관리자 영역을 인터셉터로 설정했을 경우, 미인증된 사용자가 상품등록 페이지 요청을 하면 로그인페이지로 리다이렉트 시키게된다.