login register Sysop! about ME  
qrcode
    최초 작성일 :    2016년 07월 17일
  최종 수정일 :    2016년 07월 19일
  작성자 :    soggun
  편집자 :    soggun (송원석)
  읽음수 :    7,010

강좌 목록으로 돌아가기

필자의 잡담~

이번 컬럼은 ASP.NET Core MVC 강좌의 마무리 글입니다.

모든 컬럼은 http://docs.asp.net의 내용을 참고하여 번역한 것입니다. Windows 뿐만 아니라 Linxu, OS X에서도 동작하는 완전한 크로스 플랫폼 서버기술인 ASP.NET Core! 기대해 주세요.

본 번역문서는 개인적인 취지로 번역되어 제공되는 문서로, 원문을 비롯한 모든 저작권은 마이크로소프트사에 있습니다. 마이크로소프트사의 요청이 있을 경우, 언제라도 게시가 중단될 수 있습니다. 본 번역문서에는 오역이 포함되어 있을 수 있으며 주석도 번역자 개인의 견해일뿐입니다. 마이크로소프트사는 본 문서의 번역된 내용에 대해 일체의 보장을 하지 않습니다. 번역이 완료된 뒤에도 제품이 업그레이드 되거나 기능이 변경됨에 따라 원문도 변경되거나 보완되었을 수 있으므로 참고하시기 바랍니다.

원문: https://docs.asp.net/en/latest/tutorials/first-mvc-app/details.html

ASP.NET Core MVC : Details 메서드 및 Delete 메서드 살펴보기

먼저 Movie 컨트롤러를 열고 Details 메서드부터 살펴보겠습니다:

public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

이 액션 메서드의 주석에는 MVC 스캐폴딩 엔진이 코드를 생성하면서 메서드를 호출할 수 있는 한 가지 HTTP 요청의 사례를 기입해 놓았습니다. Movies 컨트롤러와 Details 메서드, 그리고 id 값, 이렇게 세 가지 URL 세그먼트들로 구성된 GET 요청이 그것입니다. 기억하시겠지만 이 세그먼트들은 Startup.cs 파일에서 설정됩니다.

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

Code First를 사용하면 SingleOrDefaultAsync 메서드를 통해서 손쉽게 데이터를 검색할 수 있습니다. Details 메서드에 보안과 관련해서 구현된 주목할 만한 특징 한 가지는, 영화 정보를 이용해서 무언가 작업을 수행하기 전에 항상 먼저 검색 메서드의 결과가 존재하는지부터 확인한다는 점입니다. 이 검사를 수행하지 않으면, 악의적인 사용자가 목록 페이지의 링크를 통해서 얻은 URL인 http://localhost:xxxx/Movies/Details/1http://localhost:xxxx/Movies/Details/12345 같은 URL로 변조해서 (즉, 실제로 존재하지 않는 유효하지 않은 영화 정보를 지정해서) 사이트에 오류를 만들어낼 수 있습니다. 따라서 영화 정보가 null인지 확인하지 않는다면 응용 프로그램이 예외를 던질 것입니다.

계속해서 이번에는 Delete 메서드와 DeleteConfirmed 메서드를 살펴봅니다.

public async Task<IActionResult> Delete(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

// POST: Movies/Delete/5
[HttpPostActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
    var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
    _context.Movie.Remove(movie);
    await _context.SaveChangesAsync();
    return RedirectToAction("Index");
}

이 코드의 HTTP GET Delete 메서드는 지정된 영화 정보를 삭제하는 것이 아니라, 단지 삭제 작업(HttpPost)을 승인할 수 있는 영화 정보 뷰를 반환할 뿐이라는 점에 주의하시기 바랍니다. GET 요청의 응답으로 삭제 작업을 수행하면 (또는 수정 작업이나 생성 작업을 비롯한 데이터 변경이 발생하는 모든 유형의 작업을 수행하면) 보안상의 취약점이 발생합니다.

그리고 데이터를 삭제하는 [HttpPost] 메서드의 이름이 DeleteConfirmed로 지정되어 있는 것을 볼 수 있는데, 이는 HTTP POST 메서드에 고유한 시그니처 및 이름을 부여하기 위한 것입니다. 두 메서드의 시그니처를 비교해보면 다음과 같습니다:

// GET: Movies/Delete/5
public async Task<IActionResult> Delete(int? id)

// POST: Movies/Delete/
[HttpPostActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)

공통 언어 런타임(CLR, Common Language Runtime)에서 오버로드 된 메서드의 시그니처는 유일해야합니다 (즉, 메서드의 이름이 같을 수는 있지만 매개변수들의 목록은 달라야 합니다). 그러나 현재 상황은 두 가지 Delete 메서드(GET 버전과 POST 버전)가 모두 필요한 경우임에 반해, 공교롭게도 두 메서드의 매개변수 시그니처가 동일합니다. (즉, 두 메서드 모두 하나의 정수형 매개변수를 받습니다.)

이 문제점을 해결할 수 있는 방법은 두 가지가 있습니다. 첫 번째 방법은 두 메서드의 이름을 서로 다르게 지정하는 것입니다. 본문의 예제에서 스캐폴딩 메커니즘 역시 이 방식을 따르고 있음을 확인할 수 있습니다. 그러나 여전히 사소한 문제점이 존재하는데, ASP.NET이 URL의 세그먼트들을 액션 메서드와 매핑할 때 메서드의 이름을 기준으로 처리하기 때문에, 지금처럼 메서드 이름을 변경해버리면 라우팅이 적절한 액션 메서드를 찾을 수 없게 됩니다. 이 문제의 해결방법은 예제 코드에서 볼 수 있는 것처럼 DeleteConfirmed 메서드에 ActionName("Delete") 어트리뷰트를 지정하는 것입니다. 이 어트리뷰트를 적용하면 /Delete/ 세그먼트가 포함된 URL에 대한 POST 요청을 라우팅 시스템을 통해서 DeleteConfirmed 메서드로 원활하게 매핑할 수 있습니다.

동일한 이름과 시그니처를 갖고 있는 메서드의 문제점을 해결할 수 있는 또 다른 일반적인 방법은 아예 POST 메서드의 시그니처에 인위적으로 사용하지 않는 추가적인 매개변수를 추가하는 것입니다. 검색 기능 추가하기 파트에서 notUsed 매개변수를 추가했던 이유가 바로 이 때문으로, [HttpPost] Delete 메서드도 동일한 방식으로 처리할 수 있습니다:

[ValidateAntiForgeryToken]
public async Task<IActionResult> Delete(int id, bool notUsed)
{
    var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
    _context.Movie.Remove(movie);
    await _context.SaveChangesAsync();
    return RedirectToAction("Index");
}

authored by

  jhjh0206
  2016-07-19(10:40)
캐릭 이미지
감사합니다.

 
 
.NET과 Java 동영상 기반의 교육사이트

로딩 중입니다...

서버 프레임워크 지원 : NeoDEEX
based on ASP.NET 3.5
Creative Commons License
{5}
{2} 읽음   :{3} ({4})