Nicht autorisierter Webapi-Anruf, der die Anmeldeseite anstelle von 401 zurückgibt

179

Wie konfiguriere ich mein mvc / webapi-Projekt so, dass eine aus einer Rasiereransicht aufgerufene Webapi-Methode die Anmeldeseite nicht zurückgibt, wenn sie nicht autorisiert ist?

Es ist eine MVC5-Anwendung, die auch WebApi-Controller für Anrufe über Javascript enthält.

Die beiden folgenden Methoden

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

werden über den folgenden Winkelcode aufgerufen:

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

Ich bin also nicht angemeldet und die erste Methode gibt erfolgreich Daten zurück. Die zweite Methode gibt (in der Erfolgsfunktion) Daten zurück, die das Äquivalent einer Anmeldeseite enthalten. dh was würden Sie in mvc erhalten, wenn Sie eine Controller-Aktion anfordern würden, die mit [Authorize] versehen ist und Sie nicht angemeldet sind.

Ich möchte, dass ein 401 nicht autorisiert zurückgegeben wird, damit ich verschiedene Daten für Benutzer anzeigen kann, je nachdem, ob sie angemeldet sind oder nicht. Wenn der Benutzer angemeldet ist, möchte ich idealerweise auf die Benutzereigenschaft des Controllers zugreifen können, damit ich Daten zurückgeben kann, die für dieses Mitglied spezifisch sind.

UPDATE: Da keiner der folgenden Vorschläge mehr zu funktionieren scheint (Änderungen an Identität oder WebAPI), habe ich ein Rohbeispiel für Github erstellt, das das Problem veranschaulichen soll.

Tim
quelle

Antworten:

78

Es gibt zwei AuthorizeAttribute-Implementierungen, und Sie müssen sicherstellen, dass Sie auf die richtige für Web-APIs verweisen. Es gibt System.Web.Http.AuthorizeAttribute, das für Web-APIs verwendet wird, und System.Web.Mvc.AuthorizeAttribute, das für Controller mit Ansichten verwendet wird. Http.AuthorizeAttribute gibt einen 401-Fehler zurück, wenn die Autorisierung fehlschlägt und Mvc.AuthorizeAttribute zur Anmeldeseite umleitet.

Aktualisiert am 26.11.2013

Wie es scheint, haben sich die Dinge mit MVC 5 drastisch geändert, wie Brock Allen in seinem Artikel hervorhob . Ich denke, die OWIN-Pipeline übernimmt und führt ein neues Verhalten ein. Wenn der Benutzer nicht autorisiert ist, wird der Status 200 mit den folgenden Informationen im HTTP-Header zurückgegeben.

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

Sie können Ihre Logik auf der Clientseite ändern, um diese Informationen im Header zu überprüfen und festzustellen, wie damit umgegangen werden soll, anstatt im Fehlerzweig nach einem 401-Status zu suchen.

Ich habe versucht, dieses Verhalten in einem benutzerdefinierten AuthorizeAttribute zu überschreiben, indem ich den Status in der Antwort in den Methoden OnAuthorization und HandleUnauthorizedRequest festgelegt habe .

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

Das hat aber nicht funktioniert. Die neue Pipeline muss diese Antwort später abrufen und in dieselbe Antwort ändern, die ich zuvor erhalten habe. Das Auslösen einer HttpException funktionierte ebenfalls nicht, da sie nur in einen 500-Fehlerstatus geändert wurde.

Ich habe die Lösung von Brock Allen getestet und sie hat funktioniert, als ich einen jQuery-Ajax-Aufruf verwendet habe. Wenn es bei Ihnen nicht funktioniert, liegt es vermutlich daran, dass Sie eckig verwenden. Führen Sie Ihren Test mit Fiddler aus und prüfen Sie, ob sich in Ihrem Header Folgendes befindet.

X-Requested-With: XMLHttpRequest

Wenn dies nicht der Fall ist, ist dies das Problem. Ich bin nicht mit Angular vertraut, aber wenn Sie damit Ihre eigenen Header-Werte einfügen können, fügen Sie diese zu Ihren Ajax-Anforderungen hinzu, und es wird wahrscheinlich funktionieren.

Kevin Junghans
quelle
Ich denke, ich benutze System.web.http.authorizeattribute, zumindest hat dieser Webapicontroller keine Verwendung für system.web.mvc, und wenn ich zur Definition des Autorisierungsattributs gehe, schicke ich zu system.web.http
Tim
Hi @ kevin-junghans hier gründlich verwirrt. Das obige Beispiel von Shiva verwendet ein MVC-Autorisierungsattribut, das ich sicherlich nicht auf eine Webapi-Aktion anwenden sollte. Das Beispiel von Brock Allen scheint nicht zu funktionieren.
Tim
1
Ich habe gerade ein Github-Beispiel hinzugefügt, um das Problem zu veranschaulichen, und jetzt Ihren Fix zu den eckigen Headern hinzugefügt. Vielen Dank. Es scheint jedoch nicht richtig zu sein, dass das Autorisierungsattribut keine Eigenschaft enthält, die ich überprüfen kann, oder dass die von Ihnen erwähnte ursprüngliche Funktionalität nicht mehr funktioniert.
Tim
3
Verwenden von POSTMAN und Header-Parameter X-Requested-With: XMLHttpRequest funktioniert für mich ... danke
Chemitaxis
Was ist, wenn Sie das haben, was Sie als reines Web-API-Projekt beabsichtigen? Ich arbeite an einem Projekt, das von einer anderen Person eingerichtet wurde, und die Autorisierung leitet wie hier beschrieben um, aber ich habe ein anderes API-Projekt, das einwandfrei funktioniert. Es muss etwas geben, das den Eindruck erweckt, dass es sich eher um eine MVC-App als um eine API-App handelt, aber ich kann nicht herausfinden, was sie möglicherweise kaputt macht.
Derek Greer
122

Brock Allen hat einen schönen Blog-Beitrag darüber, wie man 401 für Ajax-Anrufe zurückgibt, wenn man die Cookie-Authentifizierung und OWIN verwendet. http://brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/

Fügen Sie dies in die ConfigureAuth-Methode in der Datei Startup.Auth.cs ein:

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"));
}
Olav Nybø
quelle
68
Eine Variation davon: Wenn alle Ihre Web-API-Aufrufe einen bestimmten Pfad durchlaufen, z. B. /apikönnen Sie den Pfad verwenden, um zu bestimmen, ob umgeleitet werden soll. Dies ist besonders nützlich, wenn Sie Clients haben, die andere Formate wie JSON verwenden. Ersetzen Sie den Anruf durch IsAjaxRequestdurch if (!context.Request.Path.StartsWithSegments(new PathString("/api"))).
Edward Brey
Spät zur Party, aber diese Methode ist die einzige, die für mich funktioniert und scheint "genauer" zu sein.
Stephen Collins
Sogar zu spät (r) zur Party, aber das hat sich als sehr nützlich erwiesen ... es verwirrt mich, dass der standardmäßig generierte Code dies so falsch macht, auf eine so frustrierend schwierige Art und Weise zu debuggen.
Nick
Wenn Sie nach einer WebApi-Lösung suchen, ist die Antwort von Manik eine gute Alternative zu dem hoch bewerteten Kommentar hier.
Dunc
5
Unter Verwendung von C # 6 ist hier eine kleinere Version von IsAjaxRequest: private static bool IsAjaxRequest(IOwinRequest request) { return request.Query?["X-Requested-With"] == "XMLHttpRequest" || request.Headers?["X-Requested-With"] == "XMLHttpRequest"; }
Peter Örneholm
85

Wenn Sie asp.net WebApi auf der asp.net MVC-Website hinzufügen, möchten Sie wahrscheinlich auf einige Anfragen nicht autorisiert antworten. Aber dann kommt die ASP.NET-Infrastruktur ins Spiel, und wenn Sie versuchen, den Antwortstatuscode auf HttpStatusCode.Unauthorized zu setzen, erhalten Sie eine Weiterleitung zur Anmeldeseite.

Wenn Sie die asp.net-Identität und die owin-basierte Authentifizierung verwenden, finden Sie hier einen Code, der zur Lösung dieses Problems beitragen kann:

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);
}
Manik Arora
quelle
1
Ich habe die Diskriminante zu überprüfen , ob die Anforderungen text / html oder application / xhtml als Antwort akzeptieren, wenn sie es nicht tun Ich gehe davon aus, es ist ein „automatischer“ Client anfordert, wie ein Ajax - Anfrage
L.Trabacchin
4
Ich bevorzuge diesen Ansatz auch. Die einzige Ergänzung, die ich gemacht habe, war die Konvertierung von LocalPath .ToLower (), falls sie "/ API" oder etwas anderes anfordern.
FirstDivision
1
Vielen Dank. Es hat meinen Tag gerettet. :)
Amit Kumar
Hat jemand Glück damit? CookieAuthenticationOptions verfügt ab Aspnet Core 1.1 nicht mehr über eine Provider-Eigenschaft.
Jeremy
27

Ich habe die gleiche Situation, wenn OWIN die 401-Antwort von WebApi immer auf die Anmeldeseite umleitet. Unsere Web-API unterstützt nicht nur Ajax-Aufrufe von Angular, sondern auch Mobile Win Win-Aufrufe. Daher ist die Lösung zur Überprüfung, ob die Anfrage eine Ajax-Anfrage ist, für unseren Fall nicht wirklich sortiert.

Ich habe mich für einen anderen Ansatz entschieden, bei dem eine neue Header-Antwort Suppress-Redirecteingefügt wird : Wenn die Antworten von webApi stammen. Die Implementierung erfolgt im 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);
    }
}

Und registrieren Sie diesen Handler auf globaler Ebene von WebApi:

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

Beim Start von OWIN können Sie also überprüfen, ob der Antwortheader Folgendes enthält 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;
}
cuongle
quelle
Danke ! Unsere APIs funktionierten auf allen Plattenformen außer Xamarin / Android. Wird diese Lösung verwenden
Jurion
17

In früheren Versionen von ASP.NET mussten Sie eine ganze Reihe von Aufgaben ausführen , damit dies funktioniert.

Die gute Nachricht ist, dass Sie ASP.NET 4.5 verwenden. Sie können die Umleitung der Formularauthentifizierung mithilfe der neuen Eigenschaft HttpResponse.SuppressFormsAuthenticationRedirect deaktivieren .

In Global.asax:

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

BEARBEITEN : Vielleicht möchten Sie auch einen Blick auf diesen Artikel von Sergey Zwezdin werfen, der eine verfeinerte Methode bietet, um das zu erreichen, was Sie versuchen.

Relevante Codefragmente und Autorenerzählungen werden unten eingefügt. Ursprünglicher Autor von Code und Erzählung - Sergey Zwezdin .

Lassen Sie uns zunächst feststellen, ob die aktuelle HTTP-Anforderung eine AJAX-Anforderung ist. Wenn ja, sollten wir das Ersetzen von HTTP 401 durch HTTP 302 deaktivieren:

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

Zweitens: Fügen wir eine Bedingung hinzu: Wenn der Benutzer authentifiziert ist, senden wir HTTP 403. und sonst 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);
    }
}

Gut gemacht. Jetzt sollten wir alle Verwendungen von Standard AuthorizeAttribute durch diesen neuen Filter ersetzen. Es ist möglicherweise nicht anwendbar für Sime-Leute, die sich mit Code auskennen. Aber ich kenne keinen anderen Weg. Wenn ja, gehen wir bitte zu den Kommentaren.

Das Letzte, was wir tun sollten - um die HTTP 401/403-Behandlung auf einer Clientseite hinzuzufügen. Wir können ajaxError bei jQuery verwenden, um Codeduplizierungen zu vermeiden:

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

Das Ergebnis -

  • Wenn der Benutzer nicht authentifiziert ist, wird er nach jedem AJAX-Aufruf auf eine Anmeldeseite umgeleitet.
  • Wenn der Benutzer authentifiziert ist, aber nicht über genügend Berechtigungen verfügt, wird eine benutzerfreundliche Fehlermeldung angezeigt.
  • Wenn der Benutzer authentifiziert ist und über ausreichende Berechtigungen verfügt, treten keine Fehler auf, und die HTTP-Anforderung wird wie gewohnt fortgesetzt.
Shiva
quelle
Ich verwende das neue Identitätsframework für die Authentifizierung über MVC. Würde diese Einstellung nicht verhindern, dass die MVC-Anmeldung genauso funktioniert wie die Webapi-Aufrufe?
Tim
5
Als ich dieses Beispiel überprüft habe, scheint es, dass das verwendete Autorisierungsattribut die MVC-Version und nicht die WebApi-Version ist. Die Webapi-Version bietet jedoch keine Optionen zum Unterdrücken der Formularauthentifizierung.
Tim
Meine Anfrage hat keine IsAjaxRequest-Methode.
Tim
1
Tim schaut sich das für die IsAjaxRequest an: brockallen.com/2013/10/27/… Wenn Sie AngularJs verwenden, ohne die Header zu bearbeiten, haben Sie nicht "XMLHttpRequest" und fügen es entweder hinzu oder suchen nach etwas anderem.
Tim
10

Wenn Sie Ihre Web APIinnerhalb Ihres MVCProjekts ausführen, müssen Sie eine benutzerdefinierte AuthorizeAttributeDatei erstellen , die auf Ihre APIMethoden angewendet werden soll. Innerhalb der müssen IsAuthorized overrideSie den Strom HttpContextabrufen, um die Umleitung wie folgt zu verhindern:

    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);
    }
Serj Sagan
quelle
8

Bei Verwendung der Azure Active Directory-Integration selbst hat der Ansatz mit der CookieAuthenticationMiddleware bei mir nicht funktioniert. Ich musste folgendes tun:

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

Wenn die Anforderung vom Browser selbst stammt (und beispielsweise nicht von einem AJAX-Aufruf), enthält der Accept-Header htmlirgendwo die Zeichenfolge . Nur wenn der Client HTML akzeptiert, halte ich eine Weiterleitung für nützlich.

Meine Client-Anwendung kann mit dem 401 umgehen und den Benutzer darüber informieren, dass die App keinen Zugriff mehr hat und neu geladen werden muss, um sich erneut anzumelden.

Dave Van den Eynde
quelle
Dies ist der vorgeschlagenen Lösung für eine verwandte Frage sehr ähnlich: stackoverflow.com/questions/34997674/…
Guillaume LaHaye
6

Ich hatte auch eine MVC5-Anwendung (System.Web) mit WebApi (unter Verwendung von OWIN) und wollte nur verhindern, dass 401 Antworten von WebApi in 302 Antworten geändert werden.

Für mich hat es funktioniert, eine angepasste Version des WebApi AuthorizeAttribute wie folgt zu erstellen:

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

Und um es anstelle des Standard-WebApi AuthorizeAttribute zu verwenden. Ich habe das Standard-MVC AuthorizeAttribute verwendet, um das MVC-Verhalten unverändert zu lassen.

Jono Job
quelle
Funktioniert, aber jetzt habe ich das Problem, dass der Client den Status -1 anstelle von 401 erhält
Sebastián Rojas
@ SebastiánRojas Ich bin mir nicht sicher, was das verursachen würde - das Setzen des SuppressFormsAuthenticationRedirect Flags hat dazu geführt, dass nur das vorhandene 401 für mich zurückgegeben wurde.
Jono Job
3

Installieren Sie einfach das folgende NeGet-Paket

Installationspaket Microsoft.AspNet.WebApi.Owin

Schreiben Sie den folgenden Code in die WebApiConfig-Datei.

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

quelle
Alles was ich tun musste, war diesen Filter hinzuzufügen und es funktioniert immer config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));andersUser.Identity.IsAuthenticatedfalse
Ricardo Saracino
1

Wenn Sie Content-Type == application / json abfangen möchten, können Sie diesen Code verwenden:

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;

    }

Grüße!!

Chemitaxis
quelle
1

Es fiel mir schwer, sowohl den Statuscode als auch eine Textantwort in den OnAuthorization / HandleUnauthorizedRequest-Methoden zum Laufen zu bringen. Dies stellte sich als die beste Lösung für mich heraus:

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

Nachdem ich viel Aufhebens gemacht hatte, um die Weiterleitungen zur Anmeldeseite zu vermeiden, wurde mir klar, dass dies für das Attribut "Autorisieren" durchaus angemessen ist. Es heißt, geh und hol die Genehmigung. Stattdessen wollte ich für Api-Anrufe, die nicht autorisiert sind, keine Informationen an Hacker weitergeben. Dieses Ziel war einfacher direkt zu erreichen, indem ein neues Attribut hinzugefügt wurde, das von Authorize abgeleitet wurde und stattdessen den Inhalt als 404-Fehler verbirgt:

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

Danke Leute!

In meinem Fall habe ich die Antworten von cuongle & Shiva kombiniert und so etwas erhalten:

Im OnException () - Handler des Controllers für API-Ausnahmen:

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

Im App-Startkonfigurationscode:

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);
                }
            }
        }
    });
Chakrit W.
quelle
0

Wenn Sie MVC und WebAPI mischen und die Anforderung nicht autorisiert ist, wird sie auch in WebAPI-Anforderungen zur Anmeldeseite umgeleitet. Dazu können wir den folgenden Code hinzufügen, um eine Antwort an die mobile Anwendung zu senden

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();
}
Avid Programmer
quelle
-1

In MVC 5 mit Dot Net Framework 4.5.2 erhalten wir "application / json, klagetext .." unter "Accept" -Header. Es wird schön sein, wie folgt zu verwenden:

isJson = headers["Content-Type"] == "application/json" || headers["Accept"].IndexOf("application/json", System.StringComparison.CurrentCultureIgnoreCase) >= 0;
Imran Javed
quelle