ASP.NET Web API : 401 / 무단 응답을 반환하는 올바른 방법


99

OAuth / 토큰 인증을 사용하여 요청을 인증하는 MVC 웹 API 사이트가 있습니다. 모든 관련 컨트롤러에 올바른 속성이 있으며 인증이 정상적으로 작동합니다.

문제는 모든 요청이 속성 범위에서 승인 될 수있는 것은 아니라는 것입니다. 일부 승인 검사는 컨트롤러 메소드에 의해 호출되는 코드에서 수행되어야합니다.이 경우 401 승인되지 않은 응답을 리턴하는 올바른 방법은 무엇입니까?

나는 시도 throw new HttpException(401, "Unauthorized access");했지만 이것을 할 때 응답 상태 코드는 500이고 스택 추적도 얻습니다. 로깅 DelegatingHandler에서도 응답이 401이 아니라 500임을 알 수 있습니다.


1
이 답변을 선택하는 사람에게는 a를 던질 적절한 시간 HttpResponseExceptionUnauthorized(). '예상 된'오류에 예외를 사용하는 것은 약간의 안티 패턴이므로 호출이 이러한 실수를 할 것으로 예상되는 경우 반환 Unauthorized()이 올바른 호출 일 수 있습니다. HttpResponseException정말로 예상치 못한 것을 위해 저장하십시오 .
Rikki

자세한 내용은 github.com/aspnet/Mvc/issues/5507 을 참조하십시오 .
Rikki

@Rikki, 401은 "예상 된"오류가 아닙니다. -워크 플로를 중단해야하는 예외적 인 상황입니다 (예외에 대해 이미 수행해야하는 로깅 제외 ...)-어쨌든, 컨트롤러에서 강력한 형식의 결과를 반환하려면 ( 예를 들어 단위 테스트의 용이함) 예외는 분명히 최선의 경로입니다.
BrainSlugs83

답변:


145

다음이 HttpResponseException아닌 API 메서드에서 던져야합니다 HttpException.

throw new HttpResponseException(HttpStatusCode.Unauthorized);

또는 사용자 지정 메시지를 제공하려는 경우 :

var msg = new HttpResponseMessage(HttpStatusCode.Unauthorized) { ReasonPhrase = "Oops!!!" };
throw new HttpResponseException(msg);

96

다음을 반환하십시오.

return Unauthorized();

2
나는 수락 된 것이 OP의 질문에 구체적으로 대답한다고 생각합니다. ": 401 / 승인되지 않은 응답을 반환하는 올바른 방법 ASP.NET 웹 API"내 대답은 질문의 제목에 응답
JohnWrensby

3
메시지와 함께 과부하 된 버전이없는 이유를 아는 사람 있나요?
Simon_Weaver

5
@Simon_Weaver 이유는 모르겠지만 a return Content<string>(HttpStatusCode.Unauthorized, "Message");를 사용 하여이 작업을 수행 할 수 있습니다 .
Rikki

2
정답이되어야합니다. 1 맞습니다. 2) 이후 프레임 워크에서 이것이 변경되면 코드를 변경할 필요가 없습니다. 3) 401에 이유를 제공 할 필요가 없습니다. 이는 서버가 아닌 클라이언트가 처리해야합니다.
Nick Turner

1
어떤 도서관에 있습니까?
Nae

19

다른 답변의 대안으로 IActionResultASP.NET 컨트롤러 내에서 를 반환하려는 경우이 코드를 사용할 수도 있습니다 .

ASP.NET

 return Content(HttpStatusCode.Unauthorized, "My error message");

업데이트 : ASP.NET Core

위 코드는 ASP.NET Core에서 작동하지 않으므로 대신 다음 중 하나를 사용할 수 있습니다.

 return StatusCode((int)System.Net.HttpStatusCode.Unauthorized, "My error message");
 return StatusCode(401, "My error message");

분명히 이유 문구는 매우 선택 사항입니다 ( HTTP 응답이 Reason-Phrase을 생략 할 수 있습니까? )


1
이것은 더 이상 ASP.NET Core에서 작동하지 않으며, ControllerBase클래스 (ASP.NET Core WebAPI에서 사용됨)는 더 이상 ContentHTTP 상태 코드를 허용하는 오버로드가 없습니다.
Dai는

이것은 잘못되었습니다. 콘텐츠 응답은 200 Ok 상태입니다. 서버는 401을 보내야하고 클라이언트는 그에 따라 처리해야합니다. 200을 401로 보낼 수 없습니다. 말이되지 않습니다. 의뢰인이 401을 받으면 웁스가 아니라 법을 위반 한 것입니다.
Nick Turner

이 코드는 HttpStatusCode.Unauthorized200이 아닌 401 상태 코드 ( )를 전송합니다. Content(...)단순히 주어진 HTTP 상태 코드로 주어진 콘텐츠를 반환하는 약어입니다. 200을 보내려면 다음을 사용할 수 있습니다.Ok(...)
Alex AIT

@NickTurner-이것은 잘못된 대답이 아니라 webapi2 Content () 메서드의 이름이 잘못 지정되었다는 주장입니다. (status, message) 메서드는 NetCore에서 이름이 변경되었으므로 개발자는 이름이 잘못되었다는 데 동의합니다.
Chris F Carroll

9

HttpException일종의 서버 오류를 나타내는 예외 ( )를 던지기 때문에 500 응답 코드 가 표시됩니다. 이것은 잘못된 접근 방식입니다.

응답 상태 코드를 설정하십시오.

Response.StatusCode = (int)HttpStatusCode.Unauthorized;

예외가 HTTP 상태 코드를 매개 변수로 사용하고 intellisense 문서에서는 이것이 클라이언트에 전송 된 상태 코드라고 말합니다. 오류가 발생하기 쉬운 것처럼 보이므로 직접 응답을 변경하지 않기를 바랬습니다. 글로벌 상태
GoatInTheMachine

1
기본 Web API 컨트롤러는 Response속성을 노출하지 않습니다 .
LukeH 2015-07-03

3

ASP.NET Core> = 1.0의 기존 답변에 추가하려면 다음을 수행 할 수 있습니다.

return Unauthorized();

return Unauthorized(object value);

클라이언트에 정보를 전달하려면 다음과 같이 호출 할 수 있습니다.

return Unauthorized(new { Ok = false, Code = Constants.INVALID_CREDENTIALS, ...});

401 응답 외에 클라이언트에서도 전달 된 데이터가 있습니다. 예를 들어 대부분의 클라이언트 await response.json()에서 얻을 수 있습니다.


3

.Net Core에서 사용할 수 있습니다.

return new ForbidResult();

대신에

return Unauthorized();

이는 곧바로 401을 제공하지 않고 기본 무단 페이지 (Account / AccessDenied)로 리디렉션하는 이점이 있습니다.

기본 위치를 변경하려면 startup.cs를 수정하십시오.

services.AddAuthentication(options =>...)
            .AddOpenIdConnect(options =>...)
            .AddCookie(options =>
            {
                options.AccessDeniedPath = "/path/unauthorized";

            })

질문은 웹 API에 관한 것입니다. 그래서 이것은 틀리지 않다면 잘못된 대답이 될까요? API는 '작업'을 반환하지 않아야하며 결과 만 반환해야합니다.
Niels Lucas

1

asp.net core 2.0에서 다음 코드를 사용할 수 있습니다.

public IActionResult index()
{
     return new ContentResult() { Content = "My error message", StatusCode = (int)HttpStatusCode.Unauthorized };
}

1

또한 다음 코드를 따릅니다.

var response = new HttpResponseMessage(HttpStatusCode.NotFound)
{
      Content = new StringContent("Users doesn't exist", System.Text.Encoding.UTF8, "text/plain"),
      StatusCode = HttpStatusCode.NotFound
 }
 throw new HttpResponseException(response);

생성자에게 전달하면 StatusCode를 다시 설정할 필요가 없습니다. 둘 중 하나를 사용해도 괜찮습니다
Jon Story
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.