국비학원_65일차(Spring Security, Spring Boot)

써니·2022년 10월 25일
0

spring

목록 보기
7/23

🌞Spring MVC

🔻och07_MVCBoard


💬(정답)댓글 달기 2

[com.oracle.oMVCBoard.controller]

  • BController.java
@RequestMapping("/reply_view")
	public String reply_view(HttpServletRequest request, Model model) {
		System.out.println("reply_view start...");
		
		model.addAttribute("request", request);
		command = new BReplyViewCommand();
		command.execute(model);
		
		return "reply_view";
	}
	
	@RequestMapping(value = "/reply", method = RequestMethod.POST)
	public String reply(HttpServletRequest request, Model model) {
		System.out.println("reply()");
		
		model.addAttribute("request", request);
		command = new BReplyCommand();
		command.execute(model);
		return "redirect:list";
	}

[com.oracle.oMVCBoard.command]

  • BReplyCommand ( +interface )
package com.oracle.oMVCBoard.command;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.ui.Model;

import com.oracle.oMVCBoard.dao.BDao;

public class BReplyCommand implements BCommand {

	@Override
	public void execute(Model model) {
		Map<String, Object> map = model.asMap();
		HttpServletRequest request = (HttpServletRequest) map.get("request");
		
		String bId = request.getParameter("bId");
		String bName = request.getParameter("bName");
		String bTitle = request.getParameter("bTitle");
		String bContent = request.getParameter("bContent");
//		int bGroup = Integer.parseInt(request.getParameter("bGroup"));
//		int bStep = Integer.parseInt(request.getParameter("bStep"));
//		int bIndent = Integer.parseInt(request.getParameter("bIndent"));
		String bGroup = request.getParameter("bGroup");
		String bStep = request.getParameter("bStep");
		String bIndent = request.getParameter("bIndent");
		
		BDao dao = new BDao();
		dao.reply(bId, bName, bTitle, bContent, bGroup, bStep, bIndent);
	}

}

[com.oracle.oMVCBoard.dao]

  • BDao.java
public void reply(String bId, String bName, String bTitle, String bContent, 
			String bGroup, 	String bStep, String bIndent) {
		// TODO Auto-generated method stub
		// 홍해 기적 
		replyShape(bGroup, bStep);
		
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		
		try {
			connection = dataSource.getConnection();
			String query = "insert into mvc_board (bId, bName, bTitle, bContent, "
				     	+ " bGroup, bStep, bIndent)"
					    + " values (mvc_board_seq.nextval, ?, ?, ?, ?, ?, ?)";
			preparedStatement = connection.prepareStatement(query);
			
			preparedStatement.setString(1, bName);
			preparedStatement.setString(2, bTitle);
			preparedStatement.setString(3, bContent);
			preparedStatement.setInt(4, Integer.parseInt(bGroup));
			preparedStatement.setInt(5, Integer.parseInt(bStep) + 1);
			preparedStatement.setInt(6, Integer.parseInt(bIndent) + 1);
			
			int rn = preparedStatement.executeUpdate();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		} finally {
			try {
				if(preparedStatement != null) preparedStatement.close();
				if(connection != null) connection.close();
			} catch (Exception e2) {
				// TODO: handle exception
				e2.printStackTrace();
			}
		}
		
	}

	private void replyShape( String strGroup, String strStep) {
		// TODO Auto-generated method stub
		Connection connection = null;
		PreparedStatement preparedStatement = null;
		
		try {
			connection = dataSource.getConnection();
			String query = "update mvc_board set bStep = bStep + 1 "
				     	+ " where bGroup = ? and bStep > ?";
			preparedStatement = connection.prepareStatement(query);
			preparedStatement.setInt(1, Integer.parseInt(strGroup));
			preparedStatement.setInt(2, Integer.parseInt(strStep));
			
			int rn = preparedStatement.executeUpdate();
		} catch (Exception e) {
			// TODO: handle exceptionu
			e.printStackTrace();
		} finally {
			try {
				if(preparedStatement != null) preparedStatement.close();
				if(connection != null) connection.close(); 
			} catch (Exception e2) {
				// TODO: handle exception
				e2.printStackTrace();
			}
		}
	}



🌞Spring Security

🔻och09_security1

💻 Security 초기설정

  1. web.xml
    한글처리, security-context.xml, securityChain 추가
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

	<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/spring/root-context.xml
			/WEB-INF/spring/appServlet/security-context.xml
		</param-value>
	</context-param>
	
	<filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
	
	
	<!-- Creates the Spring Container shared by all Servlets and Filters -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<!--  한글처리       -->
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
	
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

	<!-- Processes application requests -->
	<servlet>
		<servlet-name>appServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
		
	<servlet-mapping>
		<servlet-name>appServlet</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>

  1. pom.xml
    security library 추가 + 버전 4.1.3 올리기

  1. 📂 WEB-INF - spring - appServlet
  • security-context.xml
    bean + security 추가

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:security="http://www.springframework.org/schema/security"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">
	
	<security:http auto-config="true">
		<security:intercept-url pattern="/login.html" access="ROLE_USER"/>
		<security:intercept-url pattern="/welcome.html" access="ROLE_ADMIN"/>
	</security:http>
	
	<security:authentication-manager>
		<security:authentication-provider>
			<security:user-service>
				<security:user name="user" password="123" authorities="ROLE_USER"/>
				<security:user name="admin" password="123" authorities="ROLE_ADMIN"/>
			</security:user-service>
		</security:authentication-provider>
	</security:authentication-manager>
	
</beans>

[com.oracle.security1]

  • HomeController.java
@RequestMapping("/login.html")
public String login(Model model) {
	logger.info("Welcome login.html");
	return "security/login";
}

@RequestMapping("/welcome.html")
public String welcome(Model model) {
	logger.info("Welcome welcome.html");
	return "security/welcome";
}

📂 security

  • login.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Login 성공</h1>
</body>
</html>

  • welcome.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Welcome 성공</h1>
</body>
</html>

🙆‍♀️user
⚙admin

❌로그인 후 페이지 이동을 했을 때?
로그인이 되어있는 상태라 이동불가

참고




🔻och09_security2(사용자지정폼)

web.xml, pom.xml 위와 동일

📂 WEB-INF - spring - appServlet

  • security-context.xml

admin은 유저페이지/관리자페이지 접근 권한 줌

<security:user name="admin" password="123" authorities="ROLE_ADMIN, ROLE_USER"/>```

security:form-login을 사용하면 사용자가 지정한 로그인 폼으로 이동한다.


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:security="http://www.springframework.org/schema/security"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd">

	<security:http auto-config="true">
		<security:form-login login-page="/loginForm.html" authentication-failure-url="/loginForm.html?error"/>
		<security:intercept-url pattern="/login.html" access="ROLE_USER"/>
		<security:intercept-url pattern="/welcome.html" access="ROLE_ADMIN"/>
	</security:http>
	
	<security:authentication-manager>
		<security:authentication-provider>
			<security:user-service>
				<security:user name="user" password="123" authorities="ROLE_USER"/>
				<security:user name="admin" password="123" authorities="ROLE_ADMIN, ROLE_USER"/>
			</security:user-service>
		</security:authentication-provider>
	</security:authentication-manager>
</beans>

[com.oracle.security2]

  • HomeController.java
package com.oracle.security2;

import java.text.DateFormat;
import java.util.Date;
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;

/**
 * Handles requests for the application home page.
 */
@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);
		
		model.addAttribute("serverTime", formattedDate );
		
		return "home";
	}
	
	@RequestMapping("/login.html")
	public String login(Model model) {
		System.out.println("HomeController login.html Start...");
		return "security/login";
	}
	
	@RequestMapping("/welcome.html")
	public String welcome(Model model) {
		System.out.println("HomeController welcome.html Start...");
		return "security/welcome";
	}
	
	@RequestMapping("/loginForm.html")
	public String loginForm(Model model) {
		System.out.println("HomeController loginForm.html Start...");
		return "security/loginForm";
	}
	
}

📂 security

  • welcome.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Welcome 성공</h1>
</body>
</html>

  • login.jsp
    내부적으로 session을 사용하며 j_spring_security_logout를 통해 session을 빠져나간다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>Login 성공</h1>
	<c:if test="${not empty pageContext.request.userPrincipal}">
		${pageContext.request.userPrincipal}
		<p> is Log-In</p>
	</c:if>
	
	<c:if test="${empty pageContext.request.userPrincipal}">
		<p> is Log-Out</p>
	</c:if>
	
	USER ID : ${pageContext.request.userPrincipal.name} </br>
	<a href="${pageContext.request.contextPath}/j_spring_security_logout">Log Out</a></br>
</body>
</html>

  • loginForm.jsp

j_spring_security_check -> spring security 예약어, spring 내부에서 해결

j_username, j_password 약속이자 강제

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>내가 만드는 Security Login Form</h1>
	<c:url value="j_spring_security_check" var="loginUrl"/>
	<h5>loginUrl : ${loginUrl}</h5>
	
	<form action="${loginUrl}" method="post">
		<c:if test="${param.error != null}">
			<p>
				LogIn Error!<br/>
				<c:if test="${SPRING_SECURITY_LAST_EXCEPTION != NULL}">
					message : <c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message }"></c:out>
				</c:if>
			</p>
		</c:if>
		ID : <input type="text" name="j_username"><br/>
		PW : <input type="text" name="j_password"><br/>
		<input type="submit" value="LOGIN"><br/>
	</form>
</body>
</html>

💻로그인페이지
❌잘못 입력했을 시
⭕정상입력 + /login.html -> 로그아웃도 가능

⛔유저가 관리자페이지로 이동하면?

👉로그아웃하고 url를 누르면 다시 로그인 페이지로 들어감

⚙관리자로 로그인 후 유저페이지를 들어가면?


🤔Security의 단점

xml을 사용할 때마다 사용자의 아이디와 비번을 입력을 해줘야하는 걸까?
-> spring-boot에서 DB에서 받아와서 할 예정이다 + 암호화도 배울 예정
참고페이지

🔑암호화 종류

  1. 대칭 암호화 : 발신자와 수신자가 동일한 개인 암호화 키(비공키)
  2. 비대칭 암호화 : 개인정보를 보호하기 위해 대칭 암호화보다 더 고차원적이고 안전한 방법, 발신자와 수신자의 암호화키가 다르다(공개키)
  3. 해쉬(Hash) : SHA-256, SHA-512 고도화해서 사용 권장
  • bcrypt : 패스워드를 위해 탄성해서 아주 강력한 해시 알고리즘이 적용됨.
    👉Spring security에서 사용



🍃Spring Boot


💻스프링부트 초기설정

  1. File - Spring Starter Project

  1. Spring Web - MVC / template - Thymeleaf

🤔 spring initializr를 사용하는 경우 spring initializr

요즘엔 legacy를 많이 사용하지 않기 때문에 maven보단 gradle를 더 많이 사용
⭐add dependencies 에서 spring web+thymeleaf 추가


🔻oBootHello

  • build.gradle
    pom.xml == build.gradle
  • group : 회사이름
  • sourceCompatibility : java 버전
  • dependencies : 프로젝트에서 사용할 디펜던시 묘듈을 정의 ( 요즘에는 프로젝트 Test가 중요해졌다
  • 오른쪽 마우스 -> gradle -> Refresh Gradle Project하면 실행됨
plugins {
	id 'org.springframework.boot' version '2.7.5'
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
	id 'java'
}

group = 'com.oracle'
version = 'version1.0'
sourceCompatibility = '11'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
	implementation 'org.springframework.boot:spring-boot-starter-web'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
	useJUnitPlatform()
}

application.properties == web.xml

📂 src/main/resources

  • appliction.properties
server.port=8381

[com.oracle.oBootHello.controller]

  • HelloController.java
package com.oracle.oBootHello.controller;

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;

@Controller
public class HelloController {
	private static final Logger logger = LoggerFactory.getLogger(HelloController.class);
	
	@RequestMapping("hello")
	public String hello(Model model) {
    	//	prefix -> templates
		//	suffix -> .html
		logger.info("start...");
		model.addAttribute("parameter", "boot start...");
		return "hello";
	}
}

📂 src/main/resource - templates
templates -> view

  • hello.html
    <html xml:th="http://www.thymeleaf.org"> -> 타임리프 가져오기
    <p th:text="안녕+${parameter}"> -> 텍스트 입력
<!DOCTYPE html>
<html xml:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>hello.html</h1>
	<p th:text="안녕+${parameter}">
</body>
</html>



📂 src/main/resource - static

  • index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>나 Index야</h1>
</body>
</html>

🤔만약 kkk.html을 만든다면?

❌index가 아니기 때문에 오류남❌
📂 src/main/resource - static

  • kkk.html

📂 src/main/resource - static

  • index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h1>나 Index야</h1>
	<a href="/hello">Hello</a>
</body>
</html>

앵커로 hello연결



🔎 리런칭



⭐JSON

🔹 Spring boot

  • 내장 탐캣을 가지고 있다
  • @ResponseBody : view Resolver를 타지 않고 HttpMessageConverter를 탄다.
  • HttpMessageConverter : String타입을 받으면 StringConverter를 타고 객체타입을 받으면 JsonConverter를 탄다.

✍클라이언트와 서버의 비동기 통신

클라이언트에서 서버로 통신하는 메시지를 요청(request) 메시지라고 하며, 서버에서 클라이언트로 통신하는 메시지를 응답(response) 메시지라고한다.
웹에서 화면전환 없이 이루어지는 동작들을 대부분 비동기 통신으로 이루어진다.
비동기 통신을 하기 위해서는 클라이언트에서 서버로 요청 메시지를 보낼 때, 본문에 데이터를 담아서 보내야 하고, 서버에서 클라이언트로 응답을 보낼때에도 본문에 데이터를 담아서 보내야한다.
여기서 본문이랑 Body 이다.
즉 요청본문 requestBody. 응답본문 responseBody을 담아서 보내야 한다.

이때 본문에 담기는 데이터 형식은 여러가지 형태가 있겠지만 가장 대표적으로 사용되는 것이 JSON이다. 즉 비동기식 클라이언트 - 서버 통신을 위해 JSON형식의 데이터를 주고받는 것이다.


📝StringConverter

[com.oracle.oBootHello.controller]

  • HelloController.java
package com.oracle.oBootHello.controller;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class HelloController {
	private static final Logger logger = LoggerFactory.getLogger(HelloController.class);
	
	@RequestMapping("hello")
	public String hello(Model model) {
		//	prefix -> templates
		//	suffix -> .html
		logger.info("start...");
		model.addAttribute("parameter", "boot start...");
		return "hello";
	}
	
	@ResponseBody
	@GetMapping("ajaxString")
	public String ajaxString(@RequestParam("ajaxName") String aName) {
		System.out.println("HelloController ajaxString aName->"+aName);
		return aName;
	}
}




📋JsonConverter

[com.oracle.oBootHello.domain]

  • Emp.java
package com.oracle.oBootHello.domain;

public class Emp {
	private String empno;
	private String ename;
	
	public String getEmpno() {
		return empno;
	}
	public void setEmpno(String empno) {
		this.empno = empno;
	}
	public String getEname() {
		return ename;
	}
	public void setEname(String ename) {
		this.ename = ename;
	}
}

[com.oracle.oBootHello.controller]

객체로 들어오면 Json Converter가 처리를 한다.

	@ResponseBody
	@GetMapping("ajaxEmp")
	public Emp ajaxEmp(@RequestParam("empno") String empno, @RequestParam("ename") String ename) {
		System.out.println("HelloController ajaxEmp empno->"+empno);
		logger.info("ename -> {}", ename);
		Emp emp = new Emp();
		emp.setEmpno(empno);
		emp.setEname(ename);
		return emp;
	}

JSON 형식의 requestBody

❗ @Responsebody 어노테이션을 사용하면 http요청 Body를 자바 객체로 전달 받을 수 있다.

참고

0개의 댓글