[Spring-Framework] 14. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-XML) (2)
1부에 이어서 글을 작성하도록 하겠다.
1. [Spring-Framework] 14. Spring MVC, Spring Security 5.4, Oracle - 보안처리(로그인-XML) (1), 2020-09-26
11. Controller - HomeController.java
HomeController.java에 관한 것이다.
파일은 처음 프로젝트(이하 "Spring MVC Project")를 생성하면, 자동으로 만들어진다.
package com.web.springsecurity5.controller;
import java.text.DateFormat;
import java.util.Date;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
/**
* Simply selects the home view to render by returning its name.
*/
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome home! The client locale is {}.", locale);
Date date = new Date();
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale);
String formattedDate = dateFormat.format(date);
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
String username = null;
String password = null;
try {
UserDetails userDetails = (UserDetails)principal;
username = userDetails.getUsername();
password = userDetails.getPassword();
}catch(Exception e) {
e.getStackTrace();
}
model.addAttribute("username", username);
model.addAttribute("password", password);
model.addAttribute("serverTime", formattedDate );
return "home";
}
}
파일명: HomeController.java
[첨부(Attachments)]
비고: 의외로 Controller 코드는 간단하게 되어있는 것을 알 수 있다.
12. Controller - MemberController.java
MemberController에 관한 것이다.
자세히 코드를 살펴보면, "@RequestMapping"을 변경해봐도 되는 부분이 있다. (크게 무방하다.)
함수에 직접 경로를 입력한 형태로 servlet을 구성하였다.
package com.web.springsecurity5.controller;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class MemberController {
private static final Logger logger = LoggerFactory.getLogger(MemberController.class);
@RequestMapping(value = "/member/loginForm", method = RequestMethod.GET)
public String loginForm(Locale locale, Model model) {
logger.info("안녕 - 로그인 폼(Hello - Login Form");
// model.addAttribute("serverTime", formattedDate );
return "member/loginForm";
}
@RequestMapping(value = "/member/accessDenied")
public String accessDenied(Locale locale, Model model) {
logger.info("접근 금지 - 이동(Accessed Denied)");
// model.addAttribute("serverTime", formattedDate );
return "redirect:/member/accessDeniedView";
}
@RequestMapping(value = "/member/accessDeniedView")
public String accessDeniedView(Locale locale, Model model) {
logger.info("접근 금지 - 출력(Accessed Denied)");
// model.addAttribute("serverTime", formattedDate );
return "member/accessDenied";
}
}
파일명: MemberController.java
[첨부(Attachments)]
13. Controller - AdminController.java
관리자 페이지에 관한 Controller이다.
package com.web.springsecurity5.controller;
import java.util.Locale;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class AdminController {
private static final Logger logger = LoggerFactory.getLogger(AdminController.class);
@RequestMapping(value = "/admin/home", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
logger.info("Welcome - 관리자 페이지(Admin Home)!");
return "admin/home";
}
}
파일명: AdminController.java
[첨부(Attachments)]
14. View - 구성도
출력되는 화면에 관한 프로젝트 구성도이다.
그림 25. view 프로젝트 구성도
15. View - home.jsp
코드와 실제 디자인 화면을 동시에 소개하겠다.
경로: src/main/java/webapp/WEB-INF/views
그림 26. 로그인 페이지(home.jsp) - 로그인 전
그림 27. 로그인 페이지(home.jsp) - 로그인 후
그림 27. 로그인 페이지(home.jsp) - 로그인 후 - 비밀번호 생성 페이지
비고: UI(이하 "User Interface")설계하는데 도움이 되었으면 한다.
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page session="false" %>
<html>
<head>
<title>Spring-Security 5 (XML 방식)</title>
<meta charset="UTF-8">
<style>
body{
font-family:'Arial';
font-size:12px;
}
a{
text-decoration:none;
color:#666;
}
</style>
</head>
<body>
<h1>
Hello world!(Spring-Security 5(XML 방식)) - DB연동(Oracle)
</h1>
<hr />
<sec:authorize access="isAnonymous()">
<!-- 로그인 전 -->
<p>
<a href="<c:url value="/member/loginForm" />">로그인</a>
</p>
</sec:authorize>
<sec:authorize access="isAuthenticated()">
<!-- 로그인 성공 -->
<form:form action="${pageContext.request.contextPath}/logout" method="POST">
<input type="submit" value="로그아웃" />
</form:form>
<p>
${username} ${password}
</p>
</sec:authorize>
<h3>
<a href="<c:url value="/admin/home" />">관리자 홈</a>
<a href="<c:url value="/encode-password?password=pass" />">비밀번호</a>
</h3>
<!-- 비밀번호 생성기 -->
<c:set var="gene_pwd" value="${encode}" />
<c:if test="${gene_pwd != null}">
<c:out value="${gene_pwd}" />
</c:if>
</body>
</html>
파일명: home.jsp
[첨부(Attachments)]
16. View - admin/home.jsp
관리자 페이지에 관한 것이다.
경로: src/main/java/webapp/WEB-INF/views/admin
그림 28. 관리자 홈 화면 - (User-Interface) 설계
<%@ 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="form" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>관리자(ROLE_ADMIN) - 홈</title>
<style>
body{
font-family:'Arial';
font-size:12px;
}
a{
text-decoration:none;
color:#666;
}
</style>
</head>
<body>
<h1>관리자 홈 화면!</h1>
<hr />
<h3>[<a href="<c:url value="/" />">홈으로(Home)</a>]</h3>
</body>
</html>
파일명: home.jsp
[첨부(Attachments)]
17. View - member/loginForm.jsp
로그인 페이지에 대한 것이다.
경로: src/main/java/webapp/WEB-INF/views/member
그림 29. 로그인 폼 - 화면
그림 30. 로그인 폼 - 계정 불일치(아이디 또는 비밀번호)
<%@ 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="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>로그인 - 페이지(Login - Page)</title>
<style>
body{
font-family:'Arial';
font-size:12px;
}
a{
text-decoration:none;
color:#666;
}
</style>
</head>
<body>
<h1>아이디와 비밀번호를 입력해주세요.</h1>
<hr />
<c:url value="/login" var="loginUrl" />
<form:form name="f" action="${loginUrl}" method="POST">
<p>
<label for="username">아이디</label>
<input type="text" id="id" name="id" />
</p>
<p>
<label for="password">비밀번호</label>
<input type="password" id="password" name="password"/>
</p>
<%-- <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> --%>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<button type="submit" class="btn">로그인</button>
<!-- 에러 메시지 영역 -->
<c:if test="${param.error != null}">
<p>아이디와 비밀번호가 잘못되었습니다.</p>
</c:if>
<c:if test="${param.logout != null}">
<p>로그아웃 하였습니다.</p>
</c:if>
</form:form>
<h3>[<a href="<c:url value="/" />">홈으로(Home)</a>]</h3>
</body>
</html>
파일명: loginForm.jsp
[첨부(Attachments)]
18. View - member/accessDenied.jsp
인가되지 않은 화면 또는 오류 처리에 대한 것이다.
그림 31. Access Denied 페이지
<%@ 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="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<title>Access Denied</title>
</head>
<body>
<h1>Access Denied!</h1>
<h3>[<a href="<c:url value="/" />">홈</a>]</h3>
</body>
</html>
파일명: accessDenied.jsp
[첨부(Attachments)]
19. 공식 사이트에서 배포하고 있는 Spring-Boot 기반 - 예제
https://github.com/spring-projects/spring-security/tree/5.4.0/samples/boot/helloworld
Spring Security 5.4를 자바 파일 환경 설정 방식으로 구현한 것이다.
(구현 방식에는 크게 "XML 방식"과 "Java 파일" 방식이 있다.)
-> 구현하는데 있어서, 차이점이 있다.
그림 32. github - Spring Security Official 사이트
* 맺음글(Conclusion)
아무쪼록 Spring-Security 5 적용에 있어서 어려움이 해소되길 진심으로 기원한다.
* 참고자료(References)
1. 스프링프레임웍 - Spring Security(2) : 커스텀 로그인 화면 및 권한에 따른 접근 제어, https://offbyone.tistory.com/91, Accessed by 2020-09-26, Last Modified 2018-04-08.
-> 추천(50점): 잘 되어 있는 블로그 중 하나이다.
2. 스프링 시큐리티 5 - There is no PasswordEncoder mapped for the id "null", https://meaownworld.tistory.com/129, Accessed by 2020-09-26, Last Modified 2018-03-11.
3. [spring security/스프링 시큐리티] 비밀번호 암호화와 로그인 하기, https://simsimjae.tistory.com/36, Accessed by 2020-09-26, Last Modified 2017-08-28.
4. BCryptPasswordEncoder : 암호 해시, http://www.devkuma.com/books/pages/1124, Accessed by 2020-09-26, Last Modified 2017-12-30.
-> 비고: Spring Security 암호 처리에 대해서 잘 소개하고 있음.
5. Spring Security JdbcDaoImpl Example, https://www.concretepage.com/spring-5/spring-security-jdbcdaoimpl#XML, Accessed by 2020-09-26, Last Modified 2019-12-11.
-> 추천(35점): Java방법론, XML방법론 두 타입을 자세하고 잘 설명하고 있음.
6. [Spring Security] 현재 로그인한 사용자 정보 가져오기, https://itstory.tk/entry/Spring-Security-%ED%98%84%EC%9E%AC-%EB%A1%9C%EA%B7%B8%EC%9D%B8%ED%95%9C-%EC%82%AC%EC%9A%A9%EC%9E%90-%EC%A0%95%EB%B3%B4-%EA%B0%80%EC%A0%B8%EC%98%A4%EA%B8%B0, Accessed by 2020-09-26, Last Modified 2017-09-07.
7. [spring] 시큐리티 비밀번호 bcrypt 간단한 암호화, https://blog.naver.com/PostView.nhn?blogId=ljpark6&logNo=221578990976, Accessed by 2020-09-26, Last Modified 2019-07-06.
9. Spring Web MVC Security Basic Example Part 1 with XML Configuration, https://www.codejava.net/frameworks/spring/spring-web-mvc-security-basic-example-part-1-with-xml-configuration, Accessed by 2020-09-26, Last Modified 2019-06-24.
-> 비고: Spring Security 4를 기준으로 작성하였음.
Spring-Framework 3.2~4.x 이전의 경우에는 내장 로그인 인터페이스가 해당 사이트와 동일하거나 흡사함.
이전 인터페이스보다는 Spring-Framework 4.x~5 이후부터는 디자인이 있는 형태의 내장 로그인 인터페이스로 출력됨.
10. [SPRING] Controller에서 redirect하기, https://sime.tistory.com/119, Accessed by 2020-09-26, Last Modified 2016-11-17.
-> 비고: Spring-Security의 Access-error-page처리에 있어서 메시지만 출력하고, accessDenied.jsp화면이 출력되지 않는 문제를 해결하는데
redirect 방법을 참고하여 적용하였음.
11. Spring Security 5.4 - Docs, https://docs.spring.io/spring-security/site/docs/5.4.0/reference/html5/, Accessed by 2020-09-26, Last Modified 2020-09-09.
-> 비고: 공식 사이트이긴 하나, spring-boot을 주력으로 작성되어 있어서 크게 도움이 되지 않을 수도 있음.
12. Spring Security 5.4 - API, https://docs.spring.io/spring-security/site/docs/5.4.0/api/, Accessed by 2020-09-26, Last Modified .
-> 비고: API 사이트이니 구현해놓고 분석할 때 참고하면 될 것으로 보인다.
13. spring-security/samples/boot/helloworld at 5.4.0 · spring-projects/spring-security · GitHub, https://github.com/spring-projects/spring-security/tree/5.4.0/samples/boot/helloworld, Accessed by 2020-09-26, Last Modified .
-> 추천(15점): 간결하게 Java 환경설정 방식으로 예제를 소개하고 있다. (Spring-boot로 작성), Spring Security에서 공식 운영하는 github사이트이다.