Cuộc gọi webapi trái phép trả lại trang đăng nhập thay vì 401


180

Làm cách nào để định cấu hình dự án mvc / webapi của tôi để phương thức webapi được gọi từ chế độ xem dao cạo không trả về trang đăng nhập khi không được phép?

Đây là một ứng dụng MVC5 cũng có bộ điều khiển WebApi cho các cuộc gọi thông qua javascript.

Hai phương pháp dưới đây

[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
}

được gọi thông qua mã góc sau:

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

Vì vậy, tôi không đăng nhập và phương thức đầu tiên trả về dữ liệu thành công. phương thức thứ hai trả về dữ liệu (trong hàm thành công) chứa dữ liệu tương đương với trang đăng nhập. tức là những gì bạn sẽ nhận được trong mvc nếu bạn yêu cầu một hành động điều khiển được đóng dấu [Ủy quyền] và bạn không đăng nhập.

Tôi muốn nó trả về một trái phép 401, để tôi có thể hiển thị các dữ liệu khác nhau cho người dùng dựa trên việc họ có đăng nhập hay không. Lý tưởng nhất là nếu người dùng đã đăng nhập tôi muốn có thể truy cập vào tài sản Người dùng của Trình điều khiển để tôi có thể trả lại dữ liệu cụ thể cho Thành viên đó.

CẬP NHẬT: Vì không có đề xuất nào dưới đây dường như hoạt động nữa (thay đổi đối với Danh tính hoặc WebAPI), tôi đã tạo một ví dụ thô trên github để minh họa vấn đề.

Câu trả lời:


78

Có hai triển khai AuthorizeAttribution và bạn cần đảm bảo rằng bạn đang tham khảo chính xác cho API Web. Có System.Web.Http.AuthorizeAttribution được sử dụng cho API của Web và System.Web.Mvc.AuthorizeAttribution được sử dụng cho các bộ điều khiển có chế độ xem. Http.AuthorizeAttribution sẽ trả về lỗi 401 nếu ủy quyền không thành công và Mvc.AuthorizeAttribution sẽ chuyển hướng đến trang đăng nhập.

Cập nhật ngày 26/11/2013

Vì vậy, có vẻ như mọi thứ đã thay đổi mạnh mẽ với MVC 5 như Brock Allen đã chỉ ra trong bài viết của mình . Tôi đoán đường ống OWIN tiếp quản và giới thiệu một số hành vi mới. Bây giờ khi người dùng không được ủy quyền, trạng thái 200 được trả về với thông tin sau trong tiêu đề HTTP.

X-Responded-JSON: {"status":401,"headers":{"location":"http:\/\/localhost:59540\/Account\/Login?ReturnUrl=%2Fapi%2FTestBasic"}}

Bạn có thể thay đổi logic của mình ở phía máy khách để kiểm tra thông tin này trong tiêu đề để xác định cách xử lý việc này, thay vì tìm trạng thái 401 trên nhánh lỗi.

Tôi cố gắng để thay đổi hành vi này trong một phong tục AuthorizeAttribute bằng cách thiết lập trạng thái trong phản ứng trong OnAuthorizationHandleUnauthorizedRequest phương pháp.

actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

Nhưng điều này đã không làm việc. Đường ống mới phải lấy phản hồi này sau và sửa đổi nó thành phản hồi giống như tôi đã nhận được trước đó. Việc ném một HTTPException cũng không hoạt động vì nó chỉ được thay đổi thành trạng thái lỗi 500.

Tôi đã thử nghiệm giải pháp của Brock Allen và nó đã hoạt động khi tôi đang sử dụng lệnh gọi ajax của jQuery. Nếu nó không hiệu quả với bạn thì tôi đoán đó là vì bạn đang sử dụng góc cạnh. Chạy thử nghiệm của bạn với Fiddler và xem nếu sau đây là trong tiêu đề của bạn.

X-Requested-With: XMLHttpRequest

Nếu không thì đó là vấn đề. Tôi không quen thuộc với góc cạnh nhưng nếu nó cho phép bạn chèn các giá trị tiêu đề của riêng bạn thì hãy thêm nó vào các yêu cầu ajax của bạn và nó có thể sẽ bắt đầu hoạt động.


Tôi nghĩ rằng tôi đang sử dụng System.web.http. Authorizeattribution, ít nhất trình điều khiển web này không sử dụng cho system.web.mvc và sẽ định nghĩa thuộc tính ủy quyền gửi tôi đến system.web.http
Tim

Hi @ kevin-junghans hoàn toàn bối rối ở đây. ví dụ trên từ shiva sử dụng thuộc tính ủy quyền mvc mà chắc chắn tôi không nên áp dụng cho hành động webapi, Ví dụ từ Brock allen dường như không hoạt động hoặc nó không nghĩ rằng đó là yêu cầu ajax khi tôi bước qua.
Tim

1
chỉ phát hiện ra câu trả lời này (nghĩ rằng stackoverflow không gửi thông báo) Tôi đã thêm một ví dụ github để minh họa vấn đề và bây giờ đã thêm bản sửa lỗi của bạn vào các tiêu đề góc. Cảm ơn. Tuy nhiên có vẻ không đúng khi không có thuộc tính trong thuộc tính ủy quyền mà tôi có thể kiểm tra hoặc chức năng ban đầu bạn đã đề cập không hoạt động nữa.
Tim

3
Sử dụng POSTMAN và tiêu đề param X-Requested-With: XMLHttpRequest hoạt động với tôi ... cảm ơn
chemitaxis

Vậy, điều gì sẽ xảy ra nếu bạn có những gì bạn dự định là một dự án API Web thuần túy thực hiện điều này? Tôi đang làm việc trên một dự án do người khác thiết lập và Authorize đang chuyển hướng như được mô tả ở đây, nhưng tôi có một dự án API khác hoạt động tốt. Phải có một cái gì đó làm cho điều này nghĩ rằng đó là một ứng dụng MVC chứ không phải là một ứng dụng API, nhưng tôi không thể tìm thấy những gì có thể làm hỏng nó.
Derek Greer

123

Brock Allen có một bài đăng trên blog rất hay về cách trả lại 401 cho các cuộc gọi ajax khi sử dụng xác thực Cookie và OWIN. http://brockallen.com/2013/10/27/USE-cookie-authentication-middleware-with-web-api-and-401-response-codes/

Đặt cái này trong phương thức ConfigureAuth trong tệp Startup.Auth.cs:

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

68
Một biến thể về điều này: Nếu tất cả các lệnh gọi API Web của bạn đi qua một đường dẫn nhất định, ví dụ: /apibạn có thể sử dụng đường dẫn để xác định có chuyển hướng hay không. Nó đặc biệt hữu ích nếu bạn có các máy khách sử dụng các định dạng khác như JSON. Thay thế cuộc gọi IsAjaxRequestbằng if (!context.Request.Path.StartsWithSegments(new PathString("/api"))).
Edward Brey

Đến bữa tiệc muộn, nhưng phương pháp này là cách duy nhất làm tôi lo lắng và dường như "chính xác" hơn.
Stephen Collins

Ngay cả khi đến bữa tiệc muộn, nhưng điều này đã được chứng minh là rất hữu ích ... tôi nghĩ rằng mã được tạo mặc định làm điều này rất sai, theo cách khó gỡ rối đến mức khó chịu.
Nick

Nếu bạn theo đuổi giải pháp WebApi, câu trả lời của Manik là một lựa chọn tốt cho nhận xét được bình chọn cao ở đây.
Dunc

5
Sử dụng C # 6, đây là phiên bản nhỏ hơn của IsAjaxRequest: private static bool IsAjaxRequest(IOwinRequest request) { return request.Query?["X-Requested-With"] == "XMLHttpRequest" || request.Headers?["X-Requested-With"] == "XMLHttpRequest"; }
Peter Örneholm

85

Nếu bạn đang thêm asp.net WebApi bên trong trang web asp.net MVC, bạn có thể muốn phản hồi trái phép với một số yêu cầu. Nhưng sau đó, cơ sở hạ tầng ASP.NET đi vào hoạt động và khi bạn cố gắng đặt mã trạng thái phản hồi thành HttpStatusCode.Unauthorized, bạn sẽ nhận được 302 chuyển hướng đến trang đăng nhập.

Nếu bạn đang sử dụng danh tính asp.net và xác thực dựa trên owin ở đây, một mã có thể giúp giải quyết vấn đề đó:

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

1
tôi đã thay đổi phân biệt đối xử để kiểm tra xem các yêu cầu có chấp nhận văn bản / html hoặc ứng dụng / xhtml dưới dạng phản hồi hay không, nếu họ không cho rằng đó là yêu cầu của khách hàng "tự động", như một yêu cầu ajax
L.Trabacchin

4
Tôi thích cách tiếp cận này quá. Sự bổ sung duy nhất tôi đã thực hiện là chuyển đổi LocalPath .ToLower () trong trường hợp họ yêu cầu "/ API" hoặc một cái gì đó.
FirstDivision

1
Cảm ơn rất nhiều. Nó đã cứu ngày của tôi. :)
Amit Kumar

Có ai gặp may mắn với điều này? CookieAuthenticationOptions không còn có thuộc tính Nhà cung cấp kể từ lõi aspnet 1.1.
Jeremy

27

Tôi cũng gặp tình huống tương tự khi OWIN luôn chuyển hướng phản hồi 401 đến trang Đăng nhập từ WebApi.O API Web của chúng tôi không chỉ hỗ trợ các cuộc gọi ajax từ Angular mà cả Mobile, Win Form. Do đó, giải pháp để kiểm tra xem yêu cầu có phải là yêu cầu ajax không thực sự được sắp xếp cho trường hợp của chúng tôi.

Tôi đã chọn một cách tiếp cận khác là tiêm phản hồi tiêu đề mới: Suppress-Redirectnếu phản hồi đến từ webApi. Việc thực hiện là trên handler:

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

Và đăng ký trình xử lý này ở cấp độ toàn cầu của WebApi:

config.MessageHandlers.Add(new SuppressRedirectHandler());

Vì vậy, khi khởi động OWIN, bạn có thể kiểm tra xem tiêu đề phản hồi có 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;
}

Cảm ơn bạn ! API của chúng tôi hoạt động trên mọi dạng tấm, ngoại trừ Xamarin / Android. Sẽ sử dụng giải pháp này
Jurion

17

Trong các phiên bản trước của ASP.NET, bạn phải thực hiện một loạt các công cụ để làm việc này.

Tin tốt là, vì bạn đang sử dụng ASP.NET 4.5. bạn có thể vô hiệu hóa chuyển hướng xác thực mẫu bằng cách sử dụng thuộc tính httpResponse.SuppressFormsAuthenticationRedirect mới .

Trong Global.asax:

protected void Application_EndRequest(Object sender, EventArgs e)
{
        HttpApplication context = (HttpApplication)sender;
        context.Response.SuppressFormsAuthenticationRedirect = true;
}

EDIT : Bạn cũng có thể muốn xem bài viết này của Serge Zwezdin, người có cách tinh tế hơn để hoàn thành những gì bạn đang cố gắng làm.

Đoạn mã có liên quan và tường thuật của tác giả dán bên dưới. Tác giả gốc của mã và tường thuật - Sergey Zwezdin .

Trước tiên - hãy xác định xem yêu cầu HTTP hiện tại có phải là yêu cầu AJAX không. Nếu có, chúng ta nên vô hiệu hóa thay thế HTTP 401 bằng 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);
    }
}

Thứ hai - hãy thêm một điều kiện :: nếu người dùng được xác thực, thì chúng tôi sẽ gửi HTTP 403; và HTTP 401 nếu không.

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

Làm tốt. Bây giờ chúng ta nên thay thế tất cả các cách sử dụng AuthorizeAttribution tiêu chuẩn bằng bộ lọc mới này. Nó có thể không áp dụng cho những người sime, người bị ghẻ lạnh. Nhưng tôi không biết cách nào khác. Nếu bạn có, hãy đi đến bình luận, xin vui lòng.

Cuối cùng, những gì chúng ta nên làm - để thêm xử lý HTTP 401/403 ở phía máy khách. Chúng tôi có thể sử dụng ajaxError tại jQuery để tránh trùng lặp mã:

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

Kết quả -

  • Nếu người dùng không được xác thực, thì anh ta sẽ được chuyển hướng đến trang đăng nhập sau bất kỳ cuộc gọi AJAX nào.
  • Nếu người dùng được xác thực, nhưng không có đủ quyền, thì anh ta sẽ thấy thông báo erorr thân thiện với người dùng.
  • Nếu người dùng được xác thực và có đủ quyền, thì không có bất kỳ lỗi nào và yêu cầu HTTP sẽ được tiến hành như bình thường.

Tôi đang sử dụng khung nhận dạng mới cho auth qua mvc. Cài đặt này sẽ không ngăn đăng nhập mvc hoạt động tốt như các cuộc gọi webapi?
Tim

5
Khi tôi kiểm tra ví dụ này, có vẻ như Thuộc tính ủy quyền đang được sử dụng là phiên bản MVC chứ không phải là phiên bản WebApi. tuy nhiên phiên bản webapi không có tùy chọn để ngăn chặn xác thực mẫu.
Tim

yêu cầu của tôi không có phương pháp IsAjaxRequest.
Tim

1
Tim nhìn vào điều này cho IsAjaxRequest: brockallen.com/2013/10/27/NH Nếu bạn đang sử dụng AngularJs mà không chỉnh sửa các tiêu đề bạn sẽ không có "XMLHttpRequest" và thêm nó hoặc kiểm tra cái gì khác.
Tim

10

Nếu bạn đang chạy Web APItừ trong MVCdự án của mình , bạn sẽ cần tạo một tùy chỉnh AuthorizeAttributeđể áp dụng cho các APIphương thức của mình . Trong phạm vi IsAuthorized overridebạn cần lấy dòng điện HttpContextđể ngăn chuyển hướng, như thế này:

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

8

Tự mình sử dụng tích hợp Azure Active Directory, cách tiếp cận bằng cách sử dụng CookieAuthentication phần mềm trung gian không hiệu quả với tôi. Tôi đã phải làm như sau:

app.UseOpenIdConnectAuthentication(
    new OpenIdConnectAuthenticationOptions
    {
        ...
        Notifications = new OpenIdConnectAuthenticationNotifications
        {   
            ...         
            RedirectToIdentityProvider = async context =>
            {
                if (!context.Request.Accept.Contains("html"))
                {
                    context.HandleResponse();
                }
            },
            ...
        }
    });

Nếu yêu cầu đến từ chính trình duyệt (chẳng hạn như cuộc gọi AJAX) thì tiêu đề Chấp nhận sẽ chứa chuỗi htmltrong đó ở đâu đó. Chỉ khi khách hàng chấp nhận HTML tôi mới xem xét chuyển hướng một cái gì đó hữu ích.

Ứng dụng khách của tôi có thể xử lý 401 thông báo cho người dùng rằng ứng dụng không còn quyền truy cập nữa và cần tải lại để đăng nhập lại.


Điều này rất giống với giải pháp được đề xuất cho một câu hỏi liên quan: stackoverflow.com/questions 432997674/21
Guillaume LaHaye

6

Tôi cũng đã có một ứng dụng MVC5 (System.Web) với WebApi (sử dụng OWIN) và chỉ muốn ngăn chặn 401 phản hồi từ WebApi bị thay đổi thành 302 phản hồi.

Điều làm việc cho tôi là tạo ra một phiên bản tùy chỉnh của WebApi AuthorizeAttribution như thế này:

public class MyAuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
    {
        base.HandleUnauthorizedRequest(actionContext);
        HttpContext.Current.Response.SuppressFormsAuthenticationRedirect = true;
    }
}

Và để sử dụng nó thay cho WebApi AuthorizeAttribution tiêu chuẩn. Tôi đã sử dụng MVC AuthorizeAttribution tiêu chuẩn để giữ cho hành vi MVC không thay đổi.


Hoạt động, nhưng bây giờ tôi có vấn đề là khách hàng nhận được trạng thái -1 thay vì 401
Sebastián Rojas

@ SebastiánRojas Tôi không chắc điều gì sẽ gây ra điều đó - việc đặt SuppressFormsAuthenticationRedirect cờ khiến nó chỉ trả lại số tiền hiện tại cho tôi.
Công việc Jono

3

Chỉ cần cài đặt gói NeGet sau

Gói cài đặt Microsoft.AspNet.WebApi.Owin

Viết mã sau vào tệp WebApiConfig.

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        //Web API configuration and services
        //Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
        config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
        config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("multipart/form-data"));
    }
}

Tất cả tôi cần làm là thêm bộ lọc này và làm việc của mình config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));bằng cách khác User.Identity.IsAuthenticatedluôn luôn làfalse
Ricardo Saracino

1

nếu bạn muốn bắt Content-Type == application / json, bạn có thể sử dụng mã đó:

private static bool IsAjaxRequest(IOwinRequest request)
    {
        IReadableStringCollection queryXML = request.Query;
        if ((queryXML != null) && (queryXML["X-Requested-With"] == "XMLHttpRequest"))
        {
            return true;
        }

        IReadableStringCollection queryJSON = request.Query;
        if ((queryJSON != null) && (queryJSON["Content-Type"] == "application/json"))
        {
            return true;
        }

        IHeaderDictionary headersXML = request.Headers;
        var isAjax = ((headersXML != null) && (headersXML["X-Requested-With"] == "XMLHttpRequest"));

        IHeaderDictionary headers = request.Headers;
        var isJson = ((headers != null) && (headers["Content-Type"] == "application/json"));

        return isAjax || isJson;

    }

Trân trọng!!


1

Tôi đã có một thời gian khó khăn để có được cả mã trạng thái và phản hồi văn bản làm việc trong các phương thức OnAuthorization / HandleUnauthorizedRequest. Đây hóa ra là giải pháp tốt nhất cho tôi:

    actionContext.Response = new HttpResponseMessage()
    {
        StatusCode = HttpStatusCode.Forbidden,
        Content = new StringContent(unauthorizedMessage)
    };

1

Sau nhiều lần cố gắng tránh các chuyển hướng đến trang đăng nhập, tôi nhận ra rằng điều này thực sự khá phù hợp với thuộc tính Authorize. Đó là nói đi và nhận ủy quyền. Thay vào đó đối với các cuộc gọi Api không được ủy quyền, tôi chỉ muốn không tiết lộ bất kỳ thông tin nào sẽ là tin tặc. Mục tiêu này dễ dàng đạt được trực tiếp hơn bằng cách thêm một thuộc tính mới xuất phát từ Authorize, thay vào đó ẩn nội dung là lỗi 404:

public class HideFromAnonymousUsersAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
    {
         actionContext.Response = ActionContext.Request.CreateErrorResponse(HttpStatusCode.NotFound, "Access Restricted");
    }
}

1

Trộn MVC và WebAPI, nếu yêu cầu không được ủy quyền thì nó sẽ chuyển hướng đến trang đăng nhập ngay cả trong yêu cầu WebAPI. Vì vậy, chúng tôi có thể thêm mã dưới đây để gửi phản hồi cho ứng dụng di động

protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
{
    var httpContext = HttpContext.Current;
    if (httpContext == null)
    {
        base.HandleUnauthorizedRequest(actionContext);
        return;
    }

    actionContext.Response = httpContext.User.Identity.IsAuthenticated == false ?
        actionContext.Request.CreateErrorResponse(
      System.Net.HttpStatusCode.Unauthorized, "Unauthorized") :
       actionContext.Request.CreateErrorResponse(
      System.Net.HttpStatusCode.Forbidden, "Forbidden");

    httpContext.Response.SuppressFormsAuthenticationRedirect = true;
    httpContext.Response.End();
}

0

Cảm ơn các bạn!

Trong trường hợp của tôi, tôi đã kết hợp câu trả lời của cuongle & Shiva và nhận được một cái gì đó như thế này:

Trong trình xử lý OnException () của Trình điều khiển cho các ngoại lệ API:

filterContext.ExceptionHandled = true;
//...
var response = filterContext.HttpContext.Response;
response.Headers.Add("Suppress-Redirect", "true");
response.SuppressFormsAuthenticationRedirect = true;

Trong mã cấu hình khởi động ứng dụng:

app.UseCookieAuthentication(new CookieAuthenticationOptions {
        AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
        LoginPath = new PathString("/Account/Login"),
        Provider = new CookieAuthenticationProvider {
            OnValidateIdentity = ctx => {
                return validateFn.Invoke(ctx);
            },
            OnApplyRedirect = ctx =>
            {
                bool enableRedir = true;
                if (ctx.Response != null)
                {
                    string respType = ctx.Response.ContentType;
                    string suppress = ctx.Response.Headers["Suppress-Redirect"];
                    if (respType != null)
                    {
                        Regex rx = new Regex("^application\\/json(;(.*))?$",
                            RegexOptions.IgnoreCase);
                        if (rx.IsMatch(respType))
                        {
                            enableRedir = false;
                        }  
                    }
                    if ((!String.IsNullOrEmpty(suppress)) && (Boolean.Parse(suppress)))
                    {
                        enableRedir = false;
                    }
                }
                if (enableRedir)
                {
                    ctx.Response.Redirect(ctx.RedirectUri);
                }
            }
        }
    });

-1

Trong MVC 5 với Dot Net Framework 4.5.2, chúng tôi đang nhận được "application / json, văn bản đơn giản .." trong tiêu đề "Chấp nhận" Sẽ rất tuyệt khi sử dụng như sau:

isJson = headers["Content-Type"] == "application/json" || headers["Accept"].IndexOf("application/json", System.StringComparison.CurrentCultureIgnoreCase) >= 0;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.