[asp.net-mvc] 인증 및 권한 부여 실패로 AuthorizeAttribute가 로그인 페이지로 리디렉션되는 이유는 무엇입니까?

ASP.NET MVC에서 다음과 AuthorizeAttribute같이 컨트롤러 메소드를 마크 업할 수 있습니다 .

[Authorize(Roles = "CanDeleteTags")]
public void Delete(string tagName)
{
    // ...
}

즉, 현재 로그인 한 사용자가 “CanDeleteTags”역할이 아닌 경우 컨트롤러 메소드가 호출되지 않습니다.

불행히도, 실패에 대해서는을 AuthorizeAttribute리턴 HttpUnauthorizedResult하며, 이는 항상 HTTP 상태 코드 401을 리턴합니다. 이로 인해 로그인 페이지로 경로 재 지정됩니다.

사용자가 로그인하지 않은 경우 완벽하게 이해됩니다. 그러나 사용자가 이미 로그인했지만 필요한 역할이 아닌 경우 로그인 페이지로 다시 보내는 것이 혼란 스럽습니다.

AuthorizeAttribute인증 및 권한 부여 가 혼란스러워 보입니다 .

이것은 ASP.NET MVC에서 약간의 감독처럼 보입니까, 아니면 뭔가 빠졌습니까?

나는 DemandRoleAttribute둘을 분리 하는 것을 요리해야했습니다 . 사용자가 인증되지 않으면 HTTP 401을 반환하여 로그인 페이지로 보냅니다. 사용자가 로그인했지만 필요한 역할이 NotAuthorizedResult아닌 경우 대신 생성 됩니다. 현재 이것은 오류 페이지로 리디렉션됩니다.

분명히 나는 ​​이것을 할 필요가 없었습니까?



답변

처음 개발되었을 때 System.Web.Mvc.AuthorizeAttribute는 올바른 작업을 수행했습니다. HTTP 사양의 이전 버전은 “권한 없음”및 “인증되지 않은”상태 코드 401을 사용했습니다.

원래 사양에서 :

요청에 이미 인증 자격 증명이 포함 된 경우 401 응답은 해당 자격 증명에 대한 인증이 거부되었음을 나타냅니다.

사실, 혼란을 볼 수 있습니다. “인증”을 의미 할 때 “권한 부여”라는 단어가 사용됩니다. 그러나 일상적인 연습에서는 사용자가 인증되었지만 권한이없는 경우 403 Forbidden을 반환하는 것이 더 합리적입니다. 사용자에게 액세스 권한을 부여하는 두 번째 자격 증명 세트가 없을 것 같습니다.

대부분의 운영 체제를 고려하십시오-액세스 권한이없는 파일을 읽으려고하면 로그인 화면이 표시되지 않습니다!

고맙게도, 모호성을 제거하기 위해 HTTP 사양이 업데이트되었습니다 (2014 년 6 월).

“Hyper Text Transport Protocol (HTTP / 1.1) : 인증”(RFC 7235)에서 :

401 (인증되지 않음) 상태 코드는 요청이 대상 리소스에 대한 유효한 인증 자격 증명이 없기 때문에 적용되지 않았 음을 나타냅니다.

“하이퍼 텍스트 전송 프로토콜 (HTTP / 1.1) : 의미 및 컨텐츠”(RFC 7231)에서 :

403 (금지됨) 상태 코드는 서버가 요청을 이해했지만 승인을 거부 함을 나타냅니다.

흥미롭게도 ASP.NET MVC 1이 출시 될 당시 AuthorizeAttribute의 동작은 정확했습니다. 이제 동작이 잘못되었습니다. HTTP / 1.1 사양이 수정되었습니다.

ASP.NET의 로그인 페이지 리디렉션을 변경하지 않고 소스에서 문제를 해결하는 것이 더 쉽습니다. 웹 사이트의 기본 네임 스페이스에 동일한 이름 ( AuthorizeAttribute) 으로 새 속성을 만들 수 있습니다 (매우 중요합니다). 그러면 컴파일러는 MVC의 표준 네임 스페이스 대신 자동으로이를 선택합니다. 물론 그 접근 방식을 취하고 싶다면 항상 속성에 새로운 이름을 지정할 수 있습니다.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAuthenticated)
        {
            filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}


답변

이것을 Login Page_Load 함수에 추가하십시오 :

// User was redirected here because of authorization section
if (User.Identity != null && User.Identity.IsAuthenticated)
    Response.Redirect("Unauthorized.aspx");

사용자가 리디렉션되었지만 이미 로그인하면 권한이없는 페이지가 표시됩니다. 로그인하지 않으면 로그인 페이지가 표시됩니다.


답변

나는 항상 이것이 의미가 있다고 생각했다. 로그인 한 상태에서 가지고 있지 않은 역할이 필요한 페이지를 누르려고하면 해당 역할이있는 사용자로 로그인하라는 로그인 화면이 나타납니다.

사용자가 이미 인증되었는지 확인하는 논리를 로그인 페이지에 추가 할 수 있습니다. 그들이 왜 다시 부딪 쳤는지 설명하는 친절한 메시지를 추가 할 수 있습니다.


답변

불행히도 ASP.NET 폼 인증의 기본 동작을 다루고 있습니다. 여기에 설명 된 해결 방법이 있습니다 (시도하지 않았습니다).

http://www.codeproject.com/KB/aspnet/Custon401Page.aspx

(MVC에만 국한되지 않음)

대부분의 경우 가장 좋은 해결책은 사용자가 접근하기 전에 무단 리소스에 대한 액세스를 제한하는 것입니다. 이 승인되지 않은 페이지로 연결될 수있는 링크 또는 버튼을 제거 / 회색 처리합니다.

권한이없는 사용자를 리디렉션 할 위치를 지정하기 위해 속성에 추가 매개 변수가있는 것이 좋습니다. 그러나 그 동안 AuthorizeAttribute를 안전망으로 봅니다.


답변

Global.ascx 파일의 Application_EndRequest 핸들러에서이를 시도하십시오.

if (HttpContext.Current.Response.Status.StartsWith("302") && HttpContext.Current.Request.Url.ToString().Contains("/<restricted_path>/"))
{
    HttpContext.Current.Response.ClearContent();
    Response.Redirect("~/AccessDenied.aspx");
}


답변

aspnetcore 2.0을 사용하는 경우 다음을 사용하십시오.

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Core
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public class AuthorizeApiAttribute : Microsoft.AspNetCore.Authorization.AuthorizeAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var user = context.HttpContext.User;

            if (!user.Identity.IsAuthenticated)
            {
                context.Result = new UnauthorizedResult();
                return;
            }
        }
    }
}


답변

필자의 경우 문제는 “HTTP 인증에”인증되지 않은 “및”인증되지 않은 “상태 코드 401을 사용하는 것”이었습니다. ShadowChaser가 말했듯이.

이 솔루션은 저에게 효과적입니다.

if (User != null &&  User.Identity.IsAuthenticated && Response.StatusCode == 401)
{
    //Do whatever

    //In my case redirect to error page
    Response.RedirectToRoute("Default", new { controller = "Home", action = "ErrorUnauthorized" });
}