수정 구현과 CSRF/메소드 스푸핑
edit 메소드 구현
이제 프로젝트 편집을 구현할 순서이며 이 기능은 편집 화면을 보여주는 edit() 메소드와 화면에서 반영을 클릭했을 때 호출되어 DB에 변경 내역을 반영하는 update() 두 가지 메소드를 구현해야 하며 먼저 edit() 메소드를 구현해 보겠습니다.
public function edit($id)
{
$proj = Project::findOrFail($id);
return view('project.edit')->with('proj', $proj);
}
모델을 찾아서 뷰에 전달만 하면 되므로 메소드는 매우 간단합니다. 하지만 이번 기능은 서버의 자원을 생성/수정하는 HTTP 메소드인 POST/PUT/PATCH/DELETE 를 사용하므로 뷰를 구현하기 전에 먼저 알아야 할 두 가지 중요한 라라벨의 특징이 있습니다.
CSRF 토큰 생성
미들웨어 항목에서 잠시 설명한 CSRF(Cross-Site Request Forgery)는 견고한 웹 서비스를 구현을 위해 서버의 자원을 생성/수정하는 기능에서 꼭 처리해야 하는필수 기능이며 라라벨은 백엔드 단에서 VerifyCsrfToken 미들웨어를 통해 자동으로 처리해 주므로 프론트엔드 단에서는 csrf 토큰만 삽입해 주면 됩니다.
이를 위해서는 폼 안에 이름이 _token 인 히든 필드를 만들고 csrf_token() 로 토큰을 설정해 주면 됩니다.
<input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
더 간단하게는 csrf_field() 헬퍼 메소드를 사용하면 위 코드와 동일한 결과를 출력합니다.
{{ csrf_field() }}
메소드 스푸핑
artisan route:list 를 통해 라우팅을 다시 한 번 확인해 보면 수정 기능은 HTTP 의 PUT 메소드를 사용하여 서버에 요청해야 하지만 HTML Form 은 PATCH, PUT, DELETE 메소드를 지원하고 않고 오직 GET/POST 만 지원합니다.
기능 | HTTP Method | URI | 라우트 | Action |
---|---|---|---|---|
수정 화면 표시 | GET | project/{project}/edit | project.edit | ProjectController@edit |
수정 반영 | PUT/PATCH | project/{project} | project.update | ProjectController@update |
삭제 | DELETE | project/{project} | project.destroy | ProjectController@destroy |
라라벨은 이를 해결하기 위해 메소드 스푸핑(method spoofing) 기능을 제공하며 다음과 같이 폼에 name이 _method 인 히든 값을 만들고 value 에 HTTP Method 명을 적어주면 라라벨의 라우팅 처리 로직이 자동으로 해당 메소드와 연결해 줍니다.
<input type="hidden" name="_method" value="PUT">
또는 간단하게 method_field() 헬퍼 함수의 파라미터로 HTTP 메소드를 지정하여 호출해도 동일한 결과를 얻을 수 있습니다.
{!! method_field('PUT') !!}
update 메소드 구현
브라우저가 보내온 수정된 데이타를 받아서 DB에 반영하는 update() 메소드를 구현할 순서입니다.
public function update(Request $request, $id)
{
$proj = Project::findOrFail($id);
$proj->update([ //1
'name' => $request->get('name'),
'description' => $request->get('description'),
]);
return redirect('/project')
->with('message', $proj->name . '프로젝트가 수정되었습니다.'); //2
}
- 1 : 브라우저가 보내온 데이타를 $request->get() 메소드를 사용하여 추출한후에 update() 로 반영합니다. 브라우저가 보낸 값을 모두 사용하지 말고 이렇게 필요한 항목을 뽑아서 사용하는게 보안 측면에서는 더 유리합니다.
- 2 : 성공하면 결과 메시지를 표시하기 위해 with() 메소드를 사용하여 세션에 담아서 /project 라우트에 전달합니다.
이제 컨트롤러 구현은 끝났고 뷰 작성을 할 순서입니다.
edit 뷰 구현
project.edit 뷰 파일을 생성하고 코드를 작성합니다.
@extends('layouts.app')
@section('title')
프로젝트 수정
@endsection
@section('content')
<div class="col-md-8">
<form class="form-horizontal" role="form" method="POST" action="{{ route('project.update', $proj->id) }}"> //1
{{ method_field('PUT') }} //2
{{ csrf_field() }} //3
<div class="form-group">
<label for="Project name">프로젝트 명</label>
<div>
<input type="text" class="form-control" name="name" value="{{ $proj->name }}">
</div>
</div>
<div class="form-group">
<label for="설명">설명</label>
<div>
<textarea class="form-control" rows="5" name="description">{{ $proj->description }}</textarea>
</div>
</div>
<div class="form-group">
<label for="생성일">생성일</label>
<div>
<input type="text" class="form-control" name="created_at" value="{{ $proj->created_at }}" readonly="true">
</div>
</div>
<div class="form-group">
<div>
<button type="submit" class="btn btn-primary">
수정
</button>
</div>
</div>
</form>
</div>
@endsection
- 1 : FORM의 액션을 POST 로 지정하고 route('project.update', $proj->id) 로 처리할 서버의 라우팅 이름과 리소스 id 를 지정합니다.
- 2 : 메소드 스푸핑을 사용하여 PUT 메소드를 지정합니다.
- 3: CSRF 토큰을 삽입합니다.
이제 뷰 작성이 완료되었고 브라우저를 열어서 수정 화면으로 들어가 봅시다.
데이타를 변경하고 수정 버튼을 클릭하여 서버에 반영하여 정상 동작하는지 확인해 봅시다.