Springsecurityデフォルトの例

61269 ワード


ページごとにアクセス権を決定する例を作りたいです.

SampleController.java

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でアクセスする場合
springsecurityで自動的に作成されたログインが使用可能になりました
でも私はだめです.

web.xml

<?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-contextxmlを読み込むことができます
それでいい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>
メンバー、メンバーとしてしかログインできません

{noop}が存在しない場合は空の値に入ります(これは符号化機能です)
一時的な機能と見なす
したがって、メンバーとしてログインしてadminページにアクセスしようとすると、

このように出てくるはずです.
adminを追加します

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: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ページにもアクセスできます.
メンバーはadminページにアクセスできません

errorページのパブリッシュ


CommonController.java


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の作成

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>

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 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から読み込んでコントローラに送信します.
コントローラから作成したエラーページに送信

その他のエラーページの作成



次に

せいぞう

CustomAccessDeniedHandler.java

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");
	}
}

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 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>

作成したログインページにアクセス


CustomAccessDeniedHandler.java

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");
	}
}

CommonController.java

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!");
		}
		
	}
}

Loginページでcsrfトークンが作成されていることを確認します



インスペクタ確認を開くと、アプリケーション-Cookieをクリアして再確認します.

csrfの値が異なることがわかります
非常に順調である