Benutzerauthentifizierung in der ASP.NET-Web-API

150

Dieses Thema war für mich unglaublich verwirrend. Ich bin ein Neuling in HTTP-Apps, muss aber einen iPhone-Client entwickeln, der JSON-Daten von irgendwoher verwendet. Ich habe mich für die Web-API von MS entschieden, weil es einfach genug schien, aber wenn es darum geht, Benutzer zu authentifizieren, werden die Dinge ziemlich frustrierend.

Ich bin erstaunt, dass ich nach mehreren Stunden Googeln kein klares Beispiel für die Authentifizierung eines Benutzers vom Anmeldebildschirm bis zur Verwendung des AuthorizeAttributs über meine ApiControllerMethoden gefunden habe.

Dies ist keine Frage, sondern eine Anfrage nach einem Beispiel, wie dies genau zu tun ist. Ich habe mir folgende Seiten angesehen:

Obwohl diese erklären, wie mit nicht autorisierten Anfragen umgegangen wird, zeigen diese nicht deutlich etwas Ähnliches LoginController, um nach Benutzeranmeldeinformationen zu fragen und diese zu validieren.

Wer bereit ist, ein schönes einfaches Beispiel zu schreiben oder mich in die richtige Richtung zu weisen, bitte?

Vielen Dank.

Luis Aguilar
quelle
1
Ich habe die gleiche Frage zu diesem Thema
cuongle
Für Web-API mit asp.net können Sie das Cookie- und Formularauthentifizierungsmodul wie bei einer MVC-App verwenden (wenn Sie möchten). In Ihrem Web-API-Code können Sie dann den Principal überprüfen, um festzustellen, ob der Benutzer beispielsweise angemeldet ist (wie zuvor).
Elliot
Schauen Sie sich auch meine Antwort für stackoverflow.com/questions/11775594/…
Varun Chatterji
Ich empfehle vielen Leuten dringend, den Artikel asp.net/web-api/overview/security/… zu lesen .
Youngjae

Antworten:

176

Ich bin erstaunt, dass ich nach mehreren Stunden Googeln kein klares Beispiel für die Authentifizierung eines Benutzers vom Anmeldebildschirm bis zur Verwendung des Authorize-Attributs über meine ApiController-Methoden gefunden habe.

Das liegt daran, dass Sie über diese beiden Konzepte verwirrt sind:

  • Die Authentifizierung ist der Mechanismus, mit dem Systeme ihre Benutzer sicher identifizieren können. Authentifizierungssysteme geben Antworten auf die folgenden Fragen:

    • Wer ist der Benutzer?
    • Ist der Benutzer wirklich der, für den er sich darstellt?
  • Die Autorisierung ist der Mechanismus, mit dem ein System bestimmt, welche Zugriffsebene ein bestimmter authentifizierter Benutzer auf vom System kontrollierte Ressourcen haben soll. Beispielsweise könnte ein Datenbankverwaltungssystem so konzipiert sein, dass bestimmte spezifizierte Personen die Möglichkeit erhalten, Informationen aus einer Datenbank abzurufen, jedoch nicht die in der Datenbank gespeicherten Daten zu ändern, während anderen Personen die Möglichkeit gegeben wird, Daten zu ändern. Autorisierungssysteme geben Antworten auf folgende Fragen:

    • Ist Benutzer X berechtigt, auf Ressource R zuzugreifen?
    • Ist Benutzer X berechtigt, Operation P auszuführen?
    • Ist Benutzer X berechtigt, Operation P für Ressource R auszuführen?

Das AuthorizeAttribut in MVC wird verwendet, um Zugriffsregeln anzuwenden, zum Beispiel:

 [System.Web.Http.Authorize(Roles = "Admin, Super User")]
 public ActionResult AdministratorsOnly()
 {
     return View();
 }

Die obige Regel erlaubt nur Benutzern im Admin und Super User Rollen " auf die Methode zugreifen

Diese Regeln können auch in der Datei web.config mithilfe des locationElements festgelegt werden. Beispiel:

  <location path="Home/AdministratorsOnly">
    <system.web>
      <authorization>
        <allow roles="Administrators"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>

Bevor diese Autorisierungsregeln ausgeführt werden, müssen Sie jedoch bei der aktuellen Website authentifiziert sein .

Obwohl diese erklären, wie nicht autorisierte Anfragen behandelt werden, zeigen sie nicht deutlich etwas wie einen LoginController oder ähnliches, um nach Benutzeranmeldeinformationen zu fragen und diese zu validieren.

Von hier aus könnten wir das Problem in zwei Teile teilen:

  • Authentifizieren Sie Benutzer, wenn Sie die Web-API-Dienste in derselben Webanwendung nutzen

    Dies wäre der einfachste Ansatz, da Sie sich auf die verlassen würden Authentifizierung in ASP.Net verlassen würden

    Dies ist ein einfaches Beispiel:

    Web.config

    <authentication mode="Forms">
      <forms
        protection="All"
        slidingExpiration="true"
        loginUrl="account/login"
        cookieless="UseCookies"
        enableCrossAppRedirects="false"
        name="cookieName"
      />
    </authentication>

    Benutzer werden zur Konto- / Anmelderoute umgeleitet. Dort würden Sie benutzerdefinierte Steuerelemente rendern, um nach Benutzeranmeldeinformationen zu fragen, und dann würden Sie das Authentifizierungscookie wie folgt setzen:

        if (ModelState.IsValid)
        {
            if (Membership.ValidateUser(model.UserName, model.Password))
            {
                FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                return RedirectToAction("Index", "Home");
            }
            else
            {
                ModelState.AddModelError("", "The user name or password provided is incorrect.");
            }
        }
    
        // If we got this far, something failed, redisplay form
        return View(model);
  • Plattformübergreifende Authentifizierung

    In diesem Fall würden Sie nur Web-API-Dienste in der Webanwendung verfügbar machen. Daher würde ein anderer Client die Dienste nutzen. Der Client könnte eine andere Webanwendung oder eine beliebige .NET-Anwendung sein (Win Forms, WPF, Konsole, Windows-Dienst, etc)

    Angenommen, Sie verwenden den Web-API-Dienst von einer anderen Webanwendung in derselben Netzwerkdomäne (innerhalb eines Intranets). In diesem Fall können Sie sich auf die von ASP.Net bereitgestellte Windows-Authentifizierung verlassen.

    <authentication mode="Windows" />

    Wenn Ihre Dienste im Internet verfügbar gemacht werden, müssen Sie die authentifizierten Token an jeden Web-API-Dienst übergeben.

    Weitere Informationen erhalten Sie in den folgenden Artikeln:

Jupaol
quelle
3
Beeindruckend! Das nenne ich eine Antwort. Also zum Schluss. Ich plane Folgendes: 1. Erstellen Sie einen Account Controller mit einer Anmeldemethode, die den Benutzernamen und das Kennwort über HTTPS empfängt und das Anmeldeergebnis und das Token zurückgibt. 2. Der Client speichert das Token und sendet es als Header (kein HTTPS mehr) in der Anforderung, die vom Webserver validiert wird. Ist das ein guter Ansatz? Dann ist mein letzter Zweifel, wie man die Manipulation und das Ablaufen von Token kontrolliert. Ist das möglich?
Luis Aguilar
6
@Jupaol Ich glaube, ich spreche für viele Web-API-Entwickler. Ich kann die Formularauthentifizierung nicht verwenden, da ich keine Website habe und Clients keinen Browser verwenden. Ich kann auch keine integrierte Authentifizierung verwenden, da Benutzer auf jedem Gerät überall auf der Welt sein können. daher die Web-API), also was verwende ich?
Markmnl
21
Ich verstehe nicht, warum diese Antwort so viele positive Stimmen bekommt. Es geht nicht um die ASP.NET-Web-API, sondern um ASP.NET MVC.
Bastien Vandamme
3
Ich möchte den Kommentar von B413 wiederholen und darauf hinweisen, dass diese Frage speziell nach der Web-API fragt
Julien
6
Ist dies die am häufigsten gewählte "falsche" Antwort auf SO? Die Antwort spricht eigentlich nicht über Web-API, die sich sehr von einer MVC-Webanwendung unterscheidet! Wie @ B413 bin ich total geschockt!
stt106
15

Wenn Sie sich anhand eines Benutzernamens und eines Kennworts und ohne Autorisierungscookie authentifizieren möchten , funktioniert das MVC4- Autorisierungsattribut nicht sofort . Sie können Ihrem Controller jedoch die folgende Hilfsmethode hinzufügen, um grundlegende Authentifizierungsheader zu akzeptieren. Rufen Sie es vom Anfang der Methoden Ihres Controllers auf.

void EnsureAuthenticated(string role)
{
    string[] parts = UTF8Encoding.UTF8.GetString(Convert.FromBase64String(Request.Headers.Authorization.Parameter)).Split(':');
    if (parts.Length != 2 || !Membership.ValidateUser(parts[0], parts[1]))
        throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "No account with that username and password"));
    if (role != null && !Roles.IsUserInRole(parts[0], role))
        throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "An administrator account is required"));
}

Auf der Clientseite erstellt dieser Helfer einen HttpClientmit dem vorhandenen Authentifizierungsheader:

static HttpClient CreateBasicAuthenticationHttpClient(string userName, string password)
{
    var client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(userName + ':' + password)));
    return client;
}
Edward Brey
quelle
Ich wollte nur kommentieren, dass ich nach einer einfachen Möglichkeit suchte, den Industriestandard zu verwenden, um Anmeldeinformationen in der Kopfzeile zu übergeben. Dieses Beispiel zeigte die Grundlagen sowohl vom Server als auch vom Client und war alles, was ich brauchte.
da_jokker
9

Ich arbeite an einem MVC5 / Web-API-Projekt und musste in der Lage sein, eine Autorisierung für die Web-API-Methoden zu erhalten. Wenn meine Indexansicht zum ersten Mal geladen wird, rufe ich die 'API'-Web-API-Methode auf, von der ich glaube, dass sie automatisch erstellt wird.

Der clientseitige Code (CoffeeScript) zum Abrufen des Tokens lautet:

getAuthenticationToken = (username, password) ->
    dataToSend = "username=" + username + "&password=" + password
    dataToSend += "&grant_type=password"
    $.post("/token", dataToSend).success saveAccessToken

Bei Erfolg wird Folgendes aufgerufen, wodurch das Authentifizierungstoken lokal gespeichert wird:

saveAccessToken = (response) ->
    window.authenticationToken = response.access_token

Wenn ich dann einen Ajax-Aufruf an eine Web-API-Methode mit dem Tag [Authorize] senden muss, füge ich meinem Ajax-Aufruf einfach den folgenden Header hinzu:

{ "Authorization": "Bearer " + window.authenticationToken }
ProfNimrod
quelle
Woher kommt das response.access_token? Stellen Sie es aus dem C # -Code ein?
Shashwat
Das 'Antwort'-Objekt wird von der' Token'-Methode zurückgegeben.
ProfNimrod
Ich habe mich nicht mit Rollen befasst. Bei diesem Ansatz erhalten Sie lediglich ein Zugriffstoken, mit dem Sie WebApi-Methoden aufrufen können, die mit dem Tag [Authorize] versehen sind. Wenn Sie eine dieser Methoden aufrufen, können Sie vermutlich nach Rollen suchen. stackoverflow.com/questions/19689570/mvc-5-check-user-role könnte helfen.
ProfNimrod
Und wo in dieser Lösung authentifizieren Sie Ihren Benutzer tatsächlich?
Craig Brett
Der / token-Endpunkt wird automatisch für jedes neue Web-API-Projekt erstellt. Im Code dahinter wird der Benutzer authentifiziert. Es ist etwas komplizierter, wenn Sie einem vorhandenen MVC-Projekt einen Web-API-Controller hinzugefügt haben.
ProfNimrod