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" });
}