라라벨 미들웨어를 통한 다른도메인(주소) CORS 허용하기

라라벨 미들웨어를 통한 다른도메인(주소) CORS 허용하기

목표

CORS를 허용하지않았다면 same-origin Policy 정책에 근거하여 CORS 문제가 발생합니다.

CORS를 허용이 되었는지 확인하다보면 콘솔창에서 엄청나게 보게될 아래의 문구..

서로 다른 도메인(주소)은 AJAX통신을 하기위해서 CORS(Cross-Origin Resource Sharing)설정이 필요합니다.

특히 라라벨은 CSRF를 적용되어있어 토큰이 없으면 비동기 통신이 불가능합니다.

하나의 도메인에서 라라벨로 프론트 백엔드 둘 다 작업한다면 라라벨에서 제공해주는 {{ csrf_token() }} 같이 프론트에서 바로 토큰생성해서 보내줄수 있겠지만 이 글은 다른 도메인끼리 통신할 때 해결법 입니다.

환경

백엔드 : php 7.3, laravel framework 5.5

프론트 : php사용하지않음 (너무 당연한 소린걸?)

STEP1. 미들웨어에 CORS.php 파일 만들기 및 설정 (백엔드)

// CMD내부 라라벨 파일에서 파일 생성입력(클래스 설정 역시 자동으로 다 만들어줌) php artisan make:middleware CORS // 위와같이 만들지않고 파일을 app/http/Middleware 내부에 직접 파일 만드셔도 됩니다.

# CORS내부 파일 설정 public function handle($request, Closure $next) { header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS'); header('Access-Control-Allow-Credentials: false'); return $next($request); }

설명

어떤 url을 허용할것인지에 대한 헤더

header('Access-Control-Allow-Origin: *');

어떤 요청메소드를 허용할것인지

header('Access-Control-Allow-Methods: GET, PUT, POST, DELETE, OPTIONS');

인증정보를 포함한 요청 ex) 쿠키

header('Access-Control-Allow-Credentials: false');

커널 파일 설정

app/Http 디렉터리 내부의 kernel.php를 여시고 파일 내부 하단의 $routeMiddleware 내부에 코드 작성해주시면 됩니다.

# CORS 클래스 파일을 'cors'로 간략화해주는겁니다. 나중에 왜 앞에 따로 설정했는지 확인할수있습니다.. protected $routeMiddleware = [ 'cors' => \App\Http\Middleware\CORS::class, : :(기존의 클래스들) : ];

라우터 설정

# 라우터 내부에 선언해주면됩니다.(web.php) # url 참조할때 cors와 상관없이 기존의 url과 동일하게 사용하던대로 사용하면 됩니다. Route::middleware(['cors'])->group(function(){ Route::get('/csrf_token', function(){ return csrf_token(); }); Route::post('example','Controller@example'); });

설명

csrf_token을 가져오기(CORS 허용)

Route::get('/csrf_token', function(){

return csrf_token();

});

토큰과 함께 post 요청(CORS)

Route::post('/example','Controller@example');

첫번째 인자는 url주소이고 두번쨰는 어떤 컨트롤러를 참조할것인지입니다.

CSRF 보호로부터 회피하기위해서 VerifyCsrfToken 파일에 코드를 넣어줘야합니다.

작성을 안하면 get방식으로 된 토큰가져오기는 되는데 post 전송이 안됩니다.

# App/Http/Middleware 디렉터리 내부의 VerifyCsrfToken 폴더 내부에 작성하면 됩니다. protected $except = [ '/example' ];

$except 내부에 post로 전송할 url 주소를 넣어주면됩니다.

STEP2. AJAX 전송하기 (프론트)

// 코드 작성전 헤더부분에 jquery import해줍시다. //토큰 가져오기 function get_csrf(callback){ $.ajax({ type: 'get' ,url: 'http://example.com/csrf_token' ,data: '' ,xhrFields: { withCredentials: false } ,success: function(data){ console.log(data) callback(data) // 받아온 csrf_token을 반환해주는 부분 } ,error: function(xhr, status, msg){ console.log(xhr) } }); } // ajax 통신하여 post전송 function ajax_example(csrf_token){ var data = $('#value').val(); //입력한 값 var object = { '_token': csrf_token, 'data':data, } $.ajax({ type: 'post' ,url: 'http://example.com/example' ,data: object ,xhrFields: { withCredentials: false } ,success: function(data){ data = JSON.parse(data); //json 해체 console.log(data); } ,error: function(xhr, status, msg){ console.log(xhr); } }); } function get_token(){ get_csrf(function(csrf_token){ ajax_example(csrf_token) }) }

값을 입력후 버튼을 누르면 get_token()함수 내부의 get_csrf함수가 실행되고 백엔드로부터 토큰값을 받아옵니다.

그후 ajax post방식으로 값을 전송할때 토큰을 보내고 싶은 값과 함께 넣어서 전달해주면 됩니다. 그리고 전송하고 리턴값을 받게되면 프론트에서 재차 처리하고 싶은 코드를 작성하면됩니다.

수정) VerifyCsrfToken 파일에서 except에 등록하는건 csrf토큰이 없어도 허용하겠다는것이다.

그래서 토큰이 존재하는지 안하는지와 관계없다.

서버와 서버끼리의 통신에서 토큰으로 어떻게 인증할지에 대해서 좀더 공부해봐야겠다.

하나의 서버에서 작업에서는 위의 코드가 되긴하지만 라라벨에서 제공하는 {csrf_token}사용하는게 더 편할거다.

from http://xerar.tistory.com/40 by ccl(A) rewrite - 2020-03-31 22:59:47