면도기보기에서 호출 된 webapi 메소드가 인증되지 않은 경우 로그인 페이지를 반환하지 않도록 mvc / webapi 프로젝트를 어떻게 구성합니까?
Javascript를 통한 호출을위한 WebApi 컨트롤러가있는 MVC5 애플리케이션입니다.
아래 두 가지 방법
[Route("api/home/LatestProblems")]
[HttpGet()]
public List<vmLatestProblems> LatestProblems()
{
// Something here
}
[Route("api/home/myLatestProblems")]
[HttpGet()]
[Authorize(Roles = "Member")]
public List<vmLatestProblems> mylatestproblems()
{
// Something there
}
다음 각도 코드를 통해 호출됩니다.
angular.module('appWorship').controller('latest',
['$scope', '$http', function ($scope,$http) {
var urlBase = baseurl + '/api/home/LatestProblems';
$http.get(urlBase).success(function (data) {
$scope.data = data;
}).error(function (data) {
console.log(data);
});
$http.get(baseurl + '/api/home/mylatestproblems')
.success(function (data) {
$scope.data2 = data;
}).error(function (data) {
console.log(data);
});
}]
);
그래서 로그인하지 않았고 첫 번째 방법은 성공적으로 데이터를 반환합니다. 두 번째 메소드는 로그인 페이지에 해당하는 데이터를 성공 함수로 리턴합니다. 즉, [Authorize]로 스탬프 처리되고 로그인하지 않은 컨트롤러 작업을 요청한 경우 mvc에 표시되는 내용입니다.
401을 무단으로 반환하여 로그인했는지 여부에 따라 사용자에 대해 다른 데이터를 표시 할 수 있기를 원합니다. 이상적으로 사용자가 로그인 한 경우 해당 회원의 특정 데이터를 반환 할 수 있도록 컨트롤러의 사용자 속성에 액세스 할 수 있기를 원합니다.
업데이트 : 아래 제안 중 더 이상 작동하지 않는 것처럼 보이므로 (Identity 또는 WebAPI 변경) github 에서 원시 예제를 작성 하여 문제를 설명해야합니다.
답변
AuthorizeAttribute 구현에는 두 가지가 있으며 웹 API에 맞는 것을 참조하고 있는지 확인해야합니다. 이 System.Web.Http.AuthorizeAttribute 웹 API의 사용되며, System.Web.Mvc.AuthorizeAttribute 전망 컨트롤러에 사용됩니다. Http.AuthorizeAttribute는 인증이 실패 할 경우 401 오류를 반환하고 Mvc.AuthorizeAttribute는 로그인 페이지로 리디렉션됩니다.
2013 년 11 월 26 일 업데이트
따라서 브록 앨런 이 그의 기사에서 지적한 것처럼 MVC 5에서는 상황이 크게 변화 한 것으로 보입니다 . OWIN 파이프 라인이 대신하여 새로운 동작을 소개합니다. 이제 사용자에게 권한이 부여되지 않으면 HTTP 헤더에 다음 정보와 함께 상태 200이 리턴됩니다.
X-Responded-JSON: {"status":401,"headers":{"location":"http:\/\/localhost:59540\/Account\/Login?ReturnUrl=%2Fapi%2FTestBasic"}}
클라이언트 측의 논리를 변경하여 오류 분기에서 401 상태를 찾는 대신 헤더에서이 정보를 확인하여이를 처리하는 방법을 결정할 수 있습니다.
OnAuthorization 및 HandleUnauthorizedRequest 메서드 의 응답 상태를 설정하여 사용자 지정 AuthorizeAttribute 에서이 동작을 재정의하려고했습니다 .
actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
그러나 이것은 효과가 없었습니다. 새 파이프 라인은이 응답을 나중에 가져 와서 이전과 동일한 응답으로 수정해야합니다. 500 오류 상태로 변경되어 HttpException이 발생하지 않았습니다.
Brock Allen의 솔루션을 테스트했으며 jQuery ajax 호출을 사용할 때 작동했습니다. 그것이 당신을 위해 작동하지 않으면 내 추측은 각도를 사용하고 있기 때문입니다. Fiddler로 테스트를 실행하고 헤더에 다음이 있는지 확인하십시오.
X-Requested-With: XMLHttpRequest
그렇지 않으면 이것이 문제입니다. 나는 각도에 익숙하지 않지만 자신의 헤더 값을 삽입 할 수 있다면 이것을 아약스 요청에 추가하면 아마 작동하기 시작할 것이다.
답변
Brock Allen은 쿠키 인증 및 OWIN을 사용할 때 ajax 호출에 대해 401을 반환하는 방법에 대한 멋진 블로그 게시물을 보유하고 있습니다.
http://brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/
이것을 Startup.Auth.cs 파일의 ConfigureAuth 메소드에 넣습니다.
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnApplyRedirect = ctx =>
{
if (!IsAjaxRequest(ctx.Request))
{
ctx.Response.Redirect(ctx.RedirectUri);
}
}
}
});
private static bool IsAjaxRequest(IOwinRequest request)
{
IReadableStringCollection query = request.Query;
if ((query != null) && (query["X-Requested-With"] == "XMLHttpRequest"))
{
return true;
}
IHeaderDictionary headers = request.Headers;
return ((headers != null) && (headers["X-Requested-With"] == "XMLHttpRequest"));
}
답변
asp.net MVC 웹 사이트에 asp.net WebApi를 추가하는 경우 일부 요청에 대해 무단으로 응답하려고합니다. 그러나 ASP.NET 인프라가 작동하고 응답 상태 코드를 HttpStatusCode로 설정하려고하면 302가 로그인 페이지로 리디렉션됩니다.
여기에 asp.net ID 및 owin 기반 인증을 사용하는 경우 해당 문제를 해결하는 데 도움이되는 코드가 있습니다.
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider()
{
OnApplyRedirect = ctx =>
{
if (!IsApiRequest(ctx.Request))
{
ctx.Response.Redirect(ctx.RedirectUri);
}
}
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
}
private static bool IsApiRequest(IOwinRequest request)
{
string apiPath = VirtualPathUtility.ToAbsolute("~/api/");
return request.Uri.LocalPath.StartsWith(apiPath);
}
답변
OWIN이 WebApi의 401 응답을 항상 로그인 페이지로 리디렉션 할 때와 같은 상황이 발생했습니다. 우리의 웹 API는 Angular의 ajax 호출뿐만 아니라 Mobile, Win Form 호출도 지원합니다. 따라서 요청이 아약스 요청인지 확인하는 솔루션은 실제로 우리의 경우에 따라 정렬되지 않습니다.
Suppress-Redirect
webApi에서 응답이 오는 경우 새로운 헤더 응답을 삽입하는 또 다른 방법을 선택 했습니다. 구현은 핸들러에 있습니다.
public class SuppressRedirectHandler : DelegatingHandler
{
/// <summary>
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return base.SendAsync(request, cancellationToken).ContinueWith(task =>
{
var response = task.Result;
response.Headers.Add("Suppress-Redirect", "True");
return response;
}, cancellationToken);
}
}
그리고이 핸들러를 글로벌 레벨의 WebApi에 등록하십시오.
config.MessageHandlers.Add(new SuppressRedirectHandler());
따라서 OWIN 시작시 응답 헤더에 다음이 있는지 여부를 확인할 수 있습니다 Suppress-Redirect
.
public void Configuration(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AuthenticationType = DefaultApplicationTypes.ApplicationCookie,
ExpireTimeSpan = TimeSpan.FromMinutes(48),
LoginPath = new PathString("/NewAccount/LogOn"),
Provider = new CookieAuthenticationProvider()
{
OnApplyRedirect = ctx =>
{
var response = ctx.Response;
if (!IsApiResponse(ctx.Response))
{
response.Redirect(ctx.RedirectUri);
}
}
}
});
}
private static bool IsApiResponse(IOwinResponse response)
{
var responseHeader = response.Headers;
if (responseHeader == null)
return false;
if (!responseHeader.ContainsKey("Suppress-Redirect"))
return false;
if (!bool.TryParse(responseHeader["Suppress-Redirect"], out bool suppressRedirect))
return false;
return suppressRedirect;
}
답변
이전 버전의 ASP.NET에서는 많은 작업 을 수행해야했습니다. 이 작업 하기 위해 했습니다.
좋은 소식은 ASP.NET 4.5를 사용하고 있기 때문입니다. 새로운 HttpResponse.SuppressFormsAuthenticationRedirect를 사용하여 양식 인증 리디렉션을 비활성화 할 수 있습니다. 속성을 .
에서 Global.asax
:
protected void Application_EndRequest(Object sender, EventArgs e)
{
HttpApplication context = (HttpApplication)sender;
context.Response.SuppressFormsAuthenticationRedirect = true;
}
편집 : 이 기사를 살펴볼 수도 있습니다. 보다 세련되게하는 Sergey Zwezdin 를 .
관련 코드 스 니펫 및 작성자 설명이 아래에 붙여졌습니다. 코드 및 내레이션의 원저자-Sergey Zwezdin .
먼저 – 현재 HTTP 요청이 AJAX 요청인지 확인합니다. 그렇다면 HTTP 401을 HTTP 302로 바꾸지 말아야합니다.
public class ApplicationAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var httpContext = filterContext.HttpContext;
var request = httpContext.Request;
var response = httpContext.Response;
if (request.IsAjaxRequest())
response.SuppressFormsAuthenticationRedirect = true;
base.HandleUnauthorizedRequest(filterContext);
}
}
둘째 – 조건을 추가합시다 : 사용자가 인증되면 HTTP 403을 보냅니다. 그렇지 않으면 HTTP 401입니다.
public class ApplicationAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
var httpContext = filterContext.HttpContext;
var request = httpContext.Request;
var response = httpContext.Response;
var user = httpContext.User;
if (request.IsAjaxRequest())
{
if (user.Identity.IsAuthenticated == false)
response.StatusCode = (int)HttpStatusCode.Unauthorized;
else
response.StatusCode = (int)HttpStatusCode.Forbidden;
response.SuppressFormsAuthenticationRedirect = true;
response.End();
}
base.HandleUnauthorizedRequest(filterContext);
}
}
잘 했어. 이제 표준 AuthorizeAttribute의 모든 사용을이 새로운 필터로 바꿔야합니다. 코드를 간직한 사람에게는 적용되지 않을 수 있습니다. 그러나 나는 다른 방법을 모른다. 당신이 있다면, 코멘트로 가자.
마지막으로, 클라이언트 측에서 HTTP 401/403 처리를 추가하기 위해해야 할 일. 코드 중복을 피하기 위해 jQuery에서 ajaxError를 사용할 수 있습니다.
$(document).ajaxError(function (e, xhr) {
if (xhr.status == 401)
window.location = "/Account/Login";
else if (xhr.status == 403)
alert("You have no enough permissions to request this resource.");
});
결과 –
- 사용자가 인증되지 않은 경우 AJAX 호출 후 로그인 페이지로 리디렉션됩니다.
- 사용자가 인증되었지만 충분한 권한이없는 경우 사용자에게 친숙한 오류 메시지가 표시됩니다.
- 사용자가 인증되고 충분한 권한이있는 경우 오류가 없으며 평소와 같이 HTTP 요청이 진행됩니다.
답변
프로젝트 Web API
내에서 실행중인 경우 메소드 에 적용 할 MVC
사용자 정의 AuthorizeAttribute
를 작성 해야 API
합니다. 내부에서 IsAuthorized
override
다음 HttpContext
과 같이 리디렉션을 방지하기 위해 전류를 가져와야합니다 .
protected override bool IsAuthorized(HttpActionContext actionContext)
{
if (string.IsNullOrWhiteSpace(Thread.CurrentPrincipal.Identity.Name))
{
var response = HttpContext.Current.Response;
response.SuppressFormsAuthenticationRedirect = true;
response.StatusCode = (int)System.Net.HttpStatusCode.Forbidden;
response.End();
}
return base.IsAuthorized(actionContext);
}
답변
Azure Active Directory 통합을 직접 사용하면 CookieAuthentication
미들웨어를 사용하는 접근 방식이 효과 가 없었습니다. 나는 다음을 수행해야했다.
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
...
Notifications = new OpenIdConnectAuthenticationNotifications
{
...
RedirectToIdentityProvider = async context =>
{
if (!context.Request.Accept.Contains("html"))
{
context.HandleResponse();
}
},
...
}
});
요청이 브라우저 자체 (예 : AJAX 호출이 아닌)에서 온 경우 Accept 헤더에는 문자열이 포함됩니다. html
어딘가에 . 클라이언트가 HTML을 수락 할 때만 리디렉션이 유용한 것으로 간주합니다.
내 클라이언트 응용 프로그램은 401을 처리하여 사용자에게 앱에 더 이상 액세스 권한이 없으며 다시 로그인하기 위해 다시로드해야 함을 알려줍니다.