목표
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해줍시다.
<script src="https://code.jquery.com/jquery-3.4.1.js"></script>
<script>
//토큰 가져오기
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)
})
}
</script>
<input type="text" id ="value" placeholder="값">
<input type="button" onclick="get_token();">
값을 입력 후 버튼을 누르면 get_token() 함수 내부의 get_csrf함수가 실행되고 백엔드로부터 토큰 값을 받아옵니다.
그 후 ajax post방식으로 값을 전송할 때 토큰을 보내고 싶은 값과 함께 넣어서 전달해주면 됩니다. 그리고 전송하고 리턴 값을 받게 되면 프론트에서 재차 처리하고 싶은 코드를 작성하면 됩니다.
수정) VerifyCsrfToken 파일에서 except에 등록하는 건 csrf토큰이 없어도 허용하겠다는 것이다.
그래서 토큰이 존재하는지 안 하는지와 관계없다.
서버와 서버끼리의 통신에서 토큰으로 어떻게 인증할지에 대해서 좀 더 공부해봐야겠다.
하나의 서버에서 작업에서는 위의 코드가 되긴 하지만 라라벨에서 제공하는 {csrf_token} 사용하는 게 더 편할 거다.
'Web > PHP' 카테고리의 다른 글
[라라벨] 댓글 대댓글 DB설계하기 (3) | 2020.04.18 |
---|---|
[라라벨] 모델과 마이그레이션 (1) | 2020.04.11 |
[라라벨] 소셜라이트로 OAuth 로그인하기 (0) | 2020.04.11 |
[라라벨] POST방식 전달 (0) | 2020.03.22 |
GCP VM Instance(CentOS 7) PHP 라라벨프레임워크 설치하기 (0) | 2020.03.19 |