페이지 별로 접근가능 권한을 확인하는 예제를 해보려고 한다
package org.conan.controller;
import java.util.ArrayList;
import java.util.Arrays;
import org.conan.domain.SampleDTO;
import org.conan.domain.SampleDTOList;
import org.conan.domain.TodoDTO;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import lombok.extern.log4j.Log4j;
@Controller // 컨트롤러라는 걸 알리기 위한 선언
@Log4j // 콘솔창에 log로 찍기 위해 선언하는 것
@RequestMapping("/sample/*") // 주소창에 /sample로 들어오는 건 다 처리
public class SampleController {
// @InitBinder
// public void initBinder(WebDataBinder binder) {
// SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
// binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(dateFormat,false));
// }
@GetMapping("/ex01")
public String ex01(SampleDTO dto) {
log.info("" + dto); // 콘솔창에 띄우기 위한 출력문
return "ex01";
}
@GetMapping("/ex02")
public String ex02(@RequestParam("name") String name, @RequestParam("age") int age) {
log.info("name : " + name);
log.info("age : "+ age);
return "ex02";
}
@GetMapping("/ex02List")
public String ex02List(@RequestParam("ids") ArrayList<String> ids) {
log.info("ids : " + ids);
return "ex02List";
}
@GetMapping("/ex02Array")
public String ex02Array(@RequestParam("ids") String[] ids) {
log.info("array ids : " + Arrays.toString(ids));
return "ex02Array";
}
@GetMapping("/ex02Bean")
public String ex02Bean(SampleDTOList list) {
log.info("list dtos : " + list);
return "ex02Bean";
}
@GetMapping("/ex03")
public String ex03(TodoDTO todo) {
log.info("todo : " + todo);
return "ex03";
}
@GetMapping("/ex04")
public String ex04(SampleDTO dto, @ModelAttribute("page")int page) {
// 강제로 전달받은 파라미터를 모델에 담아서 타입에 관계없이 전달
log.info("dto : " + dto);
log.info("age : " + page);
return "/sample/ex04";
}
@GetMapping("/ex05")
public void ex05() {
log.info("ex05........................");
}
@GetMapping("/ex06")
public @ResponseBody SampleDTO ex06() {
log.info("ex06........................");
SampleDTO dto = new SampleDTO();
dto.setAge(10);
dto.setName("conan");
return dto;
}
@GetMapping("/ex07")
public ResponseEntity <String> ex07(){
log.info("ex07....");
String msg = String.format("{\"name\":\"conan\"}");
HttpHeaders header = new HttpHeaders();
header.add("Content-Type", "application/json;charset=UTF-8");
return new ResponseEntity<>(msg,header,HttpStatus.OK);
}
@GetMapping("/exUpload")
public void exUpload() {
log.info("exUpload......");
}
@PostMapping("/exUploadPost")
public void exUploadPost(ArrayList<MultipartFile> files) {
for(MultipartFile file:files) {
log.info("name : " + file.getOriginalFilename());
log.info("size : " + file.getSize());
}
}
@GetMapping("/all")
public void doAll() {
log.info("누구나 접근 가능");
}
@GetMapping("/member")
public void doMember() {
log.info("로그인 한 회원들만 접근 가능");
}
@GetMapping("/admin")
public void doAdmin() {
log.info("관리자들만 접근 가능");
}
}
jsp만들고 페이지 이동 확인후에
security-context.xml에 추가하기
<security:http>
<security:intercept-url pattern="/sample/all" access="permitAll"/>
<security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')"/>
<security:form-login />
</security:http>
<security:authentication-manager></security:authentication-manager>
이걸 추가하면 /sample/member로 접근시에
자동으로 spring security 에서 만들어준 로그인화면이제공된다
근데 난안된다..
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="4.0" 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_4_0.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/security-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 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>
<!-- 파일 업로드 -->
<multipart-config>
<location>c:\\upload</location> <!-- 업로드되는 파일 저장 공간 -->
<max-file-size>20971520</max-file-size> <!-- 업로드되는 파일의 최대 크기 -->
<max-request-size>41943040</max-request-size> <!-- 한 번에 올릴 수 있는 최대 크기 -->
<file-size-threshold>20971520</file-size-threshold> <!-- 특정 사이즈의 메모리 사용 -->
</multipart-config>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<filter>
<filter-name>encoding</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>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<servlet-name>appServlet</servlet-name>
</filter-mapping>
<!-- spring security -->
<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>
</web-app>
security를 읽는걸 추가해놔야 security-context.xml을 읽을 수 있음
되는걸로 받아서 security-context.xml에 좀 더 추가함
그러면
<?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/security https://www.springframework.org/schema/security/spring-security-5.2.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<security:http>
<security:intercept-url pattern="/sample/all" access="permitAll" />
<security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')" />
<security:form-login/>
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="member" password="{noop}member" authorities="ROLE_MEMBER"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
member, member로만 로그인 가능
{noop}없으면 null값으로 들어감 (이게 encoding 해주는 기능임)
임시기능이라고 보면됨
그래서 member로 로그인 한 후 admin페이지에 접근하려고 하면
이렇게 나와야한당
그리고 이제 admin을 추가해줄것임\
<?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/security https://www.springframework.org/schema/security/spring-security-5.2.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<security:http>
<security:intercept-url pattern="/sample/all" access="permitAll" />
<security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')" />
<security:intercept-url pattern="/sample/admin" access="hasRole('ROLE_ADMIN')" />
<security:form-login/>
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="member" password="{noop}member" authorities="ROLE_MEMBER"/>
<security:user name="admin" password="{noop}admin" authorities="ROLE_MEMBER, ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
이렇게 하면 admin은 member 페이지도 접근할 수 있지만
member는 admin페이지에 접근불가함
CommonController를 만든다
package org.conan.controller;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.extern.log4j.Log4j;
@Controller
@Log4j
public class CommonController {
@GetMapping("/accessError")
public void accessDenied(Authentication auth, Model model) {
log.info("access Denied : "+auth);
model.addAttribute("msg", "Access Denied");
}
}
그다음
accessError.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="sec" uri="http://www.springframework.org/security/tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>Access Denied Page</h1>
<h2><c:out value="${SPRING_SECURITY_403_EXCEPTION.getMessage() }"/></h2>
<h2><c:out value="${msg }"/></h2>
</body>
</html>
에다가 코드 추가
전체코드임
<?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/security https://www.springframework.org/schema/security/spring-security-5.2.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/sample/all" access="permitAll" />
<security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')" />
<security:intercept-url pattern="/sample/admin" access="hasRole('ROLE_ADMIN')" />
<security:form-login/>
<security:access-denied-handler error-page="/accessError"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="member" password="{noop}member" authorities="ROLE_MEMBER"/>
<security:user name="admin" password="{noop}admin" authorities="ROLE_MEMBER, ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
</beans>
에러가 나면 context에서 먼저 읽고 컨트롤러로 보내줘서
컨트롤러에서 우리가 만든 에러페이지로 보내주는 것임
그다음
만들어준다
package org.conan.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import lombok.extern.log4j.Log4j;
@Log4j
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException{
log.error("Access Denied Handler");
log.error("Redirect");
response.sendRedirect("/accessError");
}
}
<?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/security https://www.springframework.org/schema/security/spring-security-5.2.xsd
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd">
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/sample/all" access="permitAll" />
<security:intercept-url pattern="/sample/member" access="hasRole('ROLE_MEMBER')" />
<security:intercept-url pattern="/sample/admin" access="hasRole('ROLE_ADMIN')" />
<security:form-login login-page="/customLogin"/>
<!-- 내가 만든 로그인 페이지(/customLogin) 를 쓰겠다고 하는거 -->
<security:access-denied-handler ref="customAccessDenied"/>
</security:http>
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="member" password="{noop}member" authorities="ROLE_MEMBER"/>
<security:user name="admin" password="{noop}admin" authorities="ROLE_MEMBER, ROLE_ADMIN"/>
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<bean id="customAccessDenied" class="org.conan.security.CustomAccessDeniedHandler"></bean>
</beans>
package org.conan.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import lombok.extern.log4j.Log4j;
@Log4j
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException{
log.error("Access Denied Handler");
log.error("Redirect");
response.sendRedirect("/accessError");
}
}
package org.conan.controller;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.extern.log4j.Log4j;
@Controller
@Log4j
public class CommonController {
@GetMapping("/accessError")
public void accessDenied(Authentication auth, Model model) {
log.info("access Denied : "+auth);
model.addAttribute("msg", "Access Denied");
}
@GetMapping("/customLogin")
public void loginInput(String error, String logout, Model model) {
log.info("error : "+error);
log.info("logout : "+error);
if(error != null) {
model.addAttribute("error", "Login Error Check Your Account");
}
if(logout != null) {
model.addAttribute("logout", "LogOut!");
}
}
}
검사기 켜서 확인후 응용프로그램-쿠키 지우고 다시 확인
csrf의 값이 다른것을 확인할 수 있음
매우잘되고있음