Spring

Spring 23 - security (+ ajax에 csrf값 설정)

inderrom 2023. 2. 13. 17:42
1. Spring Security를 설치, 환경설정 및 활용
2. 인증(Authentication) : 로그인
3. 인가(Authorization) : 로그인 후 권환
<form action = "/login" method="post>
<input type="text" name="username">
< // name="password">
<sec:csrfInput> : 해킹 위협 대응
</form>
4. 위에 세가지가 폼태그 안에 있어야함
5. users 사용자 Auth 권한은 일대다 

 

mvn repository에서검색 

  •  spring-security-web  5.0.7
  • spring-security-config 5.0.7
  • spring-security-core 5.0.7
  • spring-security-taglibs 5.0.7

 

 

 

 

<pom.xml>

<!-- 스프링 시큐리티 라이브러리 의존관계 정의 시작 -->
<!-- 스프링 시큐리티를 웹에서 동작하도록 해줌 -->
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-web -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.0.7.RELEASE</version>
</dependency>

<!-- 스프링 시큐리트 설정을 도와줌 -->
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-config -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.0.7.RELEASE</version>
</dependency>

<!-- 스프링 시큐리티 일반기능 -->		
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-core -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-core</artifactId>
    <version>5.0.7.RELEASE</version>
</dependency>

<!-- 스프링 시큐리티와 태그라이브러리를 연결해줌 -->
<!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-taglibs -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>5.0.7.RELEASE</version>
</dependency>

<!-- 스프링 시큐리티 라이브러리 의존관계 정의 끝 -->

run as - maven build


 

<web.xml>

context-param - param-value 안에 security-context 추가

<!-- 
web.xml : tomcat 서버의 설정
-->
	<!-- 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>

 

Multipart filter 아래에 추가

<!-- 서블릿 필터 클래스를 서블릿 컨테이너에 등록함 -->
<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>

 

 

<security-context.xml>

  • <security:authentication-manager> : 나중에는 DB를 이용해 설정 , 지금은 이해하기 위해 익혀두자

<?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 http://www.springframework.org/schema/security/spring-security.xsd
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
    <!--  customAccessDenied를 자바빈(객체)으로 등록함 --> 
    <bean id = "customAccessDenied" 
    	class="kr.or.ddit.security.CustomAccessDeniedHandler"
    ></bean>
      
	<!-- xmlns : xml namespace의 약자  
		Role : 권한(authorization)
		permitAll : 누구나 접근 가능 / hasRole : 권한을 갖은자인가?
	-->
		
	<security:http>
	<!-- URI 패턴으로 접근 제한을 설정 -->
		<security:intercept-url pattern="/board/list" access="permitAll" />
		<security:intercept-url pattern="/board/register" 
						access="hasRole('ROLE_MEMBER')" />
		<security:intercept-url pattern="/notice/list" access="permitAll" />
		<security:intercept-url pattern="/notice/register" 
						access="hasRole('ROLE_ADMIN')" />
	
		<!-- 폼 기반 인증 기능을 사용 -->
		<!-- 접근 제한에 걸리면 시큐리티가 기본적으로 제공하는 로그인 페이지로 이동 -->
<!-- 		<security:form-login/> -->

		<!-- 사용자가 정의한 로그인 페이지의 URI를 지정함  -->
		<security:form-login login-page="/login"/>
		
		<!--
		로그인이 된 회원중에 권한이 없을 때..
		 접근access 거부 denided 처리자 handler 의 URI를 지정 -->
<!-- 		<security:access-denied-handler error-page="/accessError" /> -->
	
		<!-- 등록한 CustomAccessDeniedHandler를 접근 거부 처리자로 지정함 
		customAccessDenied 객체를 reference(참조-바라본다)함-->
		<security:access-denied-handler ref="customAccessDenied"/>
	</security:http>
	
	
	<!-- authentication : 인증(로그인)
	1) 회원 게시판(Board)
		가) 목록("/board/list") : 모두가 접근 가능
		나) 등록 ("/board/register"): 로그인한 회원만 접근 가능
	2) 공지사항 게시판(Notice)
		가) 목록 ("/notice/list"): 모두가 접근 가능	 
		나) 등록 ("/notice/register"): 로그인한 관리자만 접근 가능
		
		1  회원(USERS)테이블 : USERNAME, PASSWORD, ENABLED
		
		N 권한(AUTH)테이블 : USERNAME, AUTHORIZE
	-->
	<security:authentication-manager>
		<!-- 지정된 아이디와 패스워드로 로그인이 가능하도록 설정 -->
		<security:authentication-provider>
			<security:user-service>
			<!-- 메모리상에 아이디와 패스워드를 지정하고 로그인을 처리함
			스프링 시큐리티 5버전부터는 패스워드 암호화 처리기를 반드시 이용해야 함
			암호화 처리기를 사용하지 않도록 noop 문자열을 비밀번호 앞에 사용함  
				
			 -->
				<security:user name="member" password="{noop}1234" authorities="ROLE_MEMBER"/>
				<security:user name="admin" password="{noop}1234" authorities="ROLE_ADMIN"/>
			</security:user-service>
		</security:authentication-provider>
	</security:authentication-manager>
</beans>

 


 

<BoardController.java>

package kr.or.ddit.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping("/board")
@Controller
public class BoardController {
	
	// 요청 URI : /board/list : 모두가 접근 가능
	@GetMapping("/list")
	public String list() {
		//forwarding
		//board 폴더의 list.jsp를 포워딩
		return "board/list";
	}
	
	// 요청 URI : /board/register : 로그인한 회원만 접근 가능
	@GetMapping("/register")
	public String register() {
		//forwarding
		return "board/register";
	}
}

 

 

<NoticeController.java>

package kr.or.ddit.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@RequestMapping("/notice")
@Controller
public class NoticeControlelr {
	
	// 요청 URI : /notice/list : 모두 접근 가능
	@GetMapping("/list")
	public String list() {
		//forwarding
		return "notice/list";
	}
	
	// 요청 URI : /notice/register : 로그인한 관리자만 접근 가능
	@GetMapping("/register")
	public String register() {
		//forwarding
		return "notice/register";
	}
	
}

board

 

<list.jsp>

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<h3>Board List : 모두 접근 가능</h3>

 

<register.jsp>

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<h3>Board Register : 로그인한 회원만 접근 가능</h3>

 

 


notice

<list.jsp>

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<h3>Notice List : 모두 접근 가능</h3>

 

<register.jsp>

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<h3>Notice Register : 로그인한 관리자만 접근 가능</h3>

 

 


 

요청을 해보면

list는 접근 가능하지만

 

권한을 준 register는

login 페이지로 으로 넘어간다.
개발자 모드로 보면 form 태그에 input 세가지 요소가 들어감

 

security-context에서 설정해놓은 name과 password를 입력하면


 

접근 거부 처리자의 URI 지정

<CommonContoroller.java>

package kr.or.ddit.security;

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.slf4j.Slf4j;

@Slf4j
@Controller
public class CommonContoller {

	// 접근  거부 처리자의 URI를 지정
	// 요청 URI : /accessError
	@GetMapping("/accessError")
	public String accessDenied(Authentication auth, Model model) {
		log.info("access Denied : " + auth);
		
		model.addAttribute("msg", "Access Denied");
		
		//forwarding
		//security 폴더의 accessError.jsp를 forwarding함
		return "security/accessError";
	}
	
}

 

 

<accessError.jsp>

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<div class="text-center">
	<div class="error mx-auto" data-text="${msg}">${msg}</div>
	<p class="lead text-gray-800 mb-5">Server Error</p>
	<p class="text-gray-500 mb-0">
		${SPRING_SECURITY_403_EXCEPTION.getMessage()}
	</p>
	<a href="/lprod/list">← 처음으로</a>
</div>

 

 

  • localhost/notice/register 를 입력하고 로그인시
  • 관리자 권한이 아니라 member 권한을 입력하면
  • acessError 페이지가 나온다. ( (로그인 된 회원 중에 권한이 없을때)

 

 

 

<CustomAccessDenidehandler.java>

<!-- customAccessDenied를 자바빈(객체)으로 등록함 --> <bean id = "customAccessDenied" class="kr.or.ddit.security.CustomAccessDeniedHandler" ></bean>

package kr.or.ddit.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.slf4j.Slf4j;

@Slf4j
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
	@Override
		public void handle(HttpServletRequest request, HttpServletResponse response,
				AccessDeniedException accessDeniedException) throws IOException, ServletException {
			log.info("handle에 왔다");
			
		
			response.sendRedirect("/accessError");
		}
}

 

  • /localhost/notice/register 에서 member로 로그인하면
  • 콘솔에 log가 출력되는 것을 볼 수 있다.

 

 

<CustomAccessDeniedHandler.java> 추가

package kr.or.ddit.security;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

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.slf4j.Slf4j;

@Slf4j
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
	
	@Override	
	public void handle(HttpServletRequest request, HttpServletResponse response,
			AccessDeniedException accessDeniedException) throws IOException, ServletException {
		log.info("handle에 왔다");
		
		Map<String,Object> map = new HashMap<String, Object>();
		map.put("remoteAddr", request.getRemoteAddr());
		map.put("requestURI", request.getRequestURI());
		map.put("serverName", request.getServerName());
		map.put("serverPort",request.getServerPort());
		map.put("contextPath",request.getContextPath());
		
		log.info("map : " + map);
		
		response.sendRedirect("/accessError");
	}
	
	
	
}

 

 

<LoginContoller.java>

 

<!-- 폼 기반 인증 기능을 사용 -->
<!-- 접근 제한에 걸리면 시큐리티가 기본적으로 제공하는 로그인 페이지로 이동 -->
<!-- <security:form-login/> -->
<!-- 사용자가 정의한 로그인 페이지의 URI를 지정함 -->
<security:form-login login-page="/login"/>
package kr.or.ddit.security;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
public class LoginController {
	
	//<secutiry:form-login login-page="/login" />
	//요청 URI : /login
	//요청방식 : get
	//오류 메시지와 로그아웃 메시지를 파라미터로 사용해보자(없을 수도 있음)
	@GetMapping("/login")
	public String loginForm(String error, String logout, Model model) {
		log.info("error : " + error);
		log.info("logout : "+ logout );
		
		if(error != null) {
			model.addAttribute("error", "Login Error");
		}
		
		if(logout != null) {
			model.addAttribute("logout", "Logout!!");
		}
		
		//forwarding
		return "security/loginForm";
		
	}
}

 

<loginForm.jsp>

 

https://startbootstrap.com/previews/sb-admin-2

outerHTML로 로그인 창 가져오기

 

 

<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<div class="row justify-content-center">

<div class="col-xl-10 col-lg-12 col-md-9">

    <div class="card o-hidden border-0 shadow-lg my-5">
        <div class="card-body p-0">
            <!-- Nested Row within Card Body -->
            <div class="row">
                <div class="col-lg-6 d-none d-lg-block bg-login-image"></div>
                <div class="col-lg-6">
                    <div class="p-5">
                        <div class="text-center">
                            <h1 class="h4 text-gray-900 mb-4">Welcome Back!</h1>
                        </div>
                        <form class="user">
                            <div class="form-group">
                                <input type="email" class="form-control form-control-user"
                                    id="exampleInputEmail" aria-describedby="emailHelp"
                                    placeholder="Enter Email Address...">
                            </div>
                            <div class="form-group">
                                <input type="password" class="form-control form-control-user"
                                    id="exampleInputPassword" placeholder="Password">
                            </div>
                            <div class="form-group">
                                <div class="custom-control custom-checkbox small">
                                    <input type="checkbox" class="custom-control-input"
                                        id="customCheck"> <label class="custom-control-label"
                                        for="customCheck">Remember Me</label>
                                </div>
                            </div>
                            <a href="index.html" class="btn btn-primary btn-user btn-block">
                                Login </a>
                            <hr>
                            <a href="index.html" class="btn btn-google btn-user btn-block">
                                <i class="fab fa-google fa-fw"></i> Login with Google
                            </a> <a href="index.html"
                                class="btn btn-facebook btn-user btn-block"> <i
                                class="fab fa-facebook-f fa-fw"></i> Login with Facebook
                            </a>
                        </form>
                        <hr>
                        <div class="text-center">
                            <a class="small" href="forgot-password.html">Forgot
                                Password?</a>
                        </div>
                        <div class="text-center">
                            <a class="small" href="register.html">Create an Account!</a>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

</div>

</div>

localhost/notice/register

주소창 입력하면 귀여운..(?) 강아지가 나온다~~

 

 

<loginForm.jsp> 수정

  • 불필요한 코드 삭제
  • action="/login" method="post"
  • <input type="text" class="form-control form-control-user"
    id="username" name="username" aria-describedby="username"
    placeholder="아이디를 입력해주세요">
  • password
  • <button type="submit" href="" class="btn btn-primary btn-user btn-block">
    Login </button>
  • <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<%@ page language="java" contentType="text/html;charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<div class="row justify-content-center">

<div class="col-xl-10 col-lg-12 col-md-9">

<div class="card o-hidden border-0 shadow-lg my-5">
    <div class="card-body p-0">
        <!-- Nested Row within Card Body -->
        <div class="row">
            <div class="col-lg-6 d-none d-lg-block bg-login-image"></div>
            <div class="col-lg-6">
                <div class="p-5">
                    <div class="text-center">
                        <h1 class="h4 text-gray-900 mb-4">Welcome Back!</h1>
                            <h2>${error}</h2>
                            <h2>${logout}</h2>
                    </div>
                    <form class="user" action="/login" method="post">
                        <div class="form-group">
                            <input type="text" class="form-control form-control-user"
                                id="username" name="username" aria-describedby="username"
                                placeholder="아이디를 입력해주세요" required="required">
                        </div>
                        <div class="form-group">
                            <input type="password" class="form-control form-control-user"
                                id="password" name="password" placeholder="비밀번호를 입력해주세요" required="required">
                        </div>
                        <div class="form-group">
                            <div class="custom-control custom-checkbox small">
                                <input type="checkbox" class="custom-control-input"
                                    id="customCheck"> <label class="custom-control-label"
                                    for="customCheck">Remember Me</label>
                            </div>
                        </div>
                        <button type="submit" class="btn btn-primary btn-user btn-block">
                            Login </button>
                        <hr />
                        <!-- 
                        CSRF(Cross-site request forgery)
                        크로스 사이트 요청 위조는 웹 사이트 취약점 공격의 하나로,
                        사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위
                        (수정, 삭제, 등록)를 웹사이트에 요청하게 하는 공격
                         -->
                        <sec:csrfInput/>
                    </form>
                    <hr>
                    <div class="text-center">
                        <a class="small" href="register.html">Create an Account!</a>
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

</div>

</div>

 

 

<security-context.xml> 추가

  • <bean id="customLoginSuccess"
        class="kr.or.ddit.security.CustomLoginSuccessHandler"></bean>
  • <!-- 사용자가 정의한 로그인 페이지의 URI를 지정함  -->
    <!-- customLoignSuccess를 인증(로그인) 성공 처리자로 지정함 -->
    <security:form-login login-page="/login"
    authentication-success-handler-ref="customLoginSuccess"
    />

<?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 http://www.springframework.org/schema/security/spring-security.xsd
      http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
      
    <!--  customAccessDenied를 자바빈(객체)으로 등록함 --> 
    <bean id = "customAccessDenied" 
    	class="kr.or.ddit.security.CustomAccessDeniedHandler"></bean>
    	
    <bean id="customLoginSuccess"
    class="kr.or.ddit.security.CustomLoginSuccessHandler"></bean>	
      
	<!-- xmlns : xml namespace의 약자  
		Role : 권한(authorization)
		permitAll : 누구나 접근 가능 / hasRole : 권한을 갖은자인가?
	-->
		
	<security:http>
	<!-- URI 패턴으로 접근 제한을 설정 -->
		<security:intercept-url pattern="/board/list" access="permitAll" />
		<security:intercept-url pattern="/board/register" 
						access="hasRole('ROLE_MEMBER')" />
		<security:intercept-url pattern="/notice/list" access="permitAll" />
		<security:intercept-url pattern="/notice/register" 
						access="hasRole('ROLE_ADMIN')" />
	
		<!-- 폼 기반 인증 기능을 사용 -->
		<!-- 접근 제한에 걸리면 시큐리티가 기본적으로 제공하는 로그인 페이지로 이동 -->
<!-- 		<security:form-login/> -->

		<!-- 사용자가 정의한 로그인 페이지의 URI를 지정함  -->
		<!-- customLoignSuccess를 인증(로그인) 성공 처리자로 지정함 -->
		<security:form-login login-page="/login"
			authentication-success-handler-ref="customLoginSuccess"
		/>
		
		<!--
		로그인이 된 회원중에 권한이 없을 때..
		 접근access 거부 denided 처리자 handler 의 URI를 지정 -->
<!-- 		<security:access-denied-handler error-page="/accessError" /> -->
	
		<!-- 등록한 CustomAccessDeniedHandler를 접근 거부 처리자로 지정함 
		customAccessDenied 객체를 reference(참조-바라본다)함-->
		<security:access-denied-handler ref="customAccessDenied"/>
	</security:http>
	
	
	<!-- authentication : 인증(로그인)
	1) 회원 게시판(Board)
		가) 목록("/board/list") : 모두가 접근 가능
		나) 등록 ("/board/register"): 로그인한 회원만 접근 가능
	2) 공지사항 게시판(Notice)
		가) 목록 ("/notice/list"): 모두가 접근 가능	 
		나) 등록 ("/notice/register"): 로그인한 관리자만 접근 가능
		
		1  회원(USERS)테이블 : USERNAME, PASSWORD, ENABLED
		
		N 권한(AUTH)테이블 : USERNAME, AUTHORIZE
	-->
	<security:authentication-manager>
		<!-- 지정된 아이디와 패스워드로 로그인이 가능하도록 설정 -->
		<security:authentication-provider>
			<security:user-service>
			<!-- 메모리상에 아이디와 패스워드를 지정하고 로그인을 처리함
			스프링 시큐리티 5버전부터는 패스워드 암호화 처리기를 반드시 이용해야 함
			암호화 처리기를 사용하지 않도록 noop 문자열을 비밀번호 앞에 사용함  
				
			 -->
				<security:user name="member" password="{noop}1234" authorities="ROLE_MEMBER"/>
				<security:user name="admin" password="{noop}1234" authorities="ROLE_ADMIN"/>
			</security:user-service>
		</security:authentication-provider>
	</security:authentication-manager>
</beans>

 

 

<CustomLoginSuccessHandler.java>

package kr.or.ddit.security;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
	
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request,
			HttpServletResponse response, Authentication auth )
			throws ServletException, IOException {
		// ~했을 때 로그인을 성공
		log.info("onAuthemticationSuccess");
		
		User costomUser = (User) auth.getPrincipal();
		
		log.info("username : " + costomUser.getUsername());
		
		super.onAuthenticationSuccess(request, response, auth);
		
	}
}

실행하면 콘솔로 출력됨

 

 


ajax 데이터 전송 전 헤더에 csrf값 설정

$.ajax({
url : "/project/syncPromemProfile",
data : JSON.stringify(altVO),
contentType: "application/json;charset=utf-8",
type : "post",
beforeSend : function(xhr) {   // 데이터 전송 전  헤더에 csrf값 설정
                xhr.setRequestHeader("${_csrf.headerName}", "${_csrf.token}");
},
success : function(res) {
}
});

 


폼태그 안에 꼭 다 csrf까지 다 써줘야 완성됨! 기억하자!