30

Ich entwickle eine REST-API in ASP.Net Web API. Auf meine API kann nur über nicht browserbasierte Clients zugegriffen werden. Ich muss Sicherheit für meine API implementieren, also entschied ich mich für die Token-basierte Authentifizierung. Ich habe ein faires Verständnis der tokenbasierten Authentifizierung und habe ein paar Tutorials gelesen, aber alle haben eine Benutzeroberfläche für die Anmeldung. Ich benötige keine Benutzeroberfläche für die Anmeldung, da die Anmeldedaten vom Client über HTTP POST übermittelt werden, der von unserer Datenbank autorisiert wird. Wie kann ich Token-basierte Authentifizierung in meiner API implementieren? Bitte beachten Sie, dass auf meine API in hoher Frequenz zugegriffen wird, so dass ich auch auf die Leistung achten muss. Bitte lassen Sie mich wissen, wenn ich es besser erklären kann.Token-basierte Authentifizierung in Web-API ohne Benutzeroberfläche

+1

jemand, irgendwo müsste den Benutzernamen und das Passwort eingeben, um die anfängliche Validierung durchzuführen; schlagen Sie vor, dass jeder, der eine Kopie Ihrer App erhält, denselben Benutzernamen und dasselbe Passwort verwendet? und wenn das der Fall ist, beabsichtigen Sie, den Benutzernamen und das Kennwort in Ihrem Code fest zu codieren? – Claies

+0

Ich kann mehrere registrierte Benutzer haben, daher werden die ursprünglichen Anmeldedaten von ihnen über HTTP POST weitergeleitet. Weiter ist was? –

+0

das macht keinen Sinn. Wie können Sie Anmeldeinformationen an Ihren Client weiterleiten? Wie soll der Server wissen, welcher Client welcher ist? – Claies

Antwort

36

Ich denke, es gibt einige Verwirrung über den Unterschied zwischen MVC und Web API. Kurz gesagt, für MVC können Sie ein Login-Formular verwenden und eine Sitzung mit Cookies erstellen. Für Web Api gibt es keine Sitzung. Deshalb möchten Sie das Token verwenden.

Sie benötigen kein Login-Formular. Der Token-Endpunkt ist alles, was Sie brauchen. Wie bei Win beschrieben, senden Sie die Anmeldeinformationen an den Token-Endpunkt, an dem sie verarbeitet wird.

Hier einige C# -Code Client-Seite ein Token zu erhalten:

//using System; 
    //using System.Collections.Generic; 
    //using System.Net; 
    //using System.Net.Http; 
    //string token = GetToken("https://localhost:<port>/", userName, password); 

    static string GetToken(string url, string userName, string password) { 
     var pairs = new List<KeyValuePair<string, string>> 
        { 
         new KeyValuePair<string, string>("grant_type", "password"), 
         new KeyValuePair<string, string>("username", userName), 
         new KeyValuePair<string, string> ("Password", password) 
        }; 
     var content = new FormUrlEncodedContent(pairs); 
     ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; 
     using (var client = new HttpClient()) { 
      var response = client.PostAsync(url + "Token", content).Result; 
      return response.Content.ReadAsStringAsync().Result; 
     } 
    } 

Um das Token fügen Sie es dem Header der Anforderung zu verwenden:

//using System; 
    //using System.Collections.Generic; 
    //using System.Net; 
    //using System.Net.Http; 
    //var result = CallApi("https://localhost:<port>/something", token); 

    static string CallApi(string url, string token) { 
     ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true; 
     using (var client = new HttpClient()) { 
      if (!string.IsNullOrWhiteSpace(token)) { 
       var t = JsonConvert.DeserializeObject<Token>(token); 

       client.DefaultRequestHeaders.Clear(); 
       client.DefaultRequestHeaders.Add("Authorization", "Bearer " + t.access_token); 
      } 
      var response = client.GetAsync(url).Result; 
      return response.Content.ReadAsStringAsync().Result; 
     } 
    } 

Wo Token ist:

//using Newtonsoft.Json; 

class Token 
{ 
    public string access_token { get; set; } 
    public string token_type { get; set; } 
    public int expires_in { get; set; } 
    public string userName { get; set; } 
    [JsonProperty(".issued")] 
    public string issued { get; set; } 
    [JsonProperty(".expires")] 
    public string expires { get; set; } 
} 

Jetzt für die Serverseite:

In Startup.Auth.cs

 var oAuthOptions = new OAuthAuthorizationServerOptions 
     { 
      TokenEndpointPath = new PathString("/Token"), 
      Provider = new ApplicationOAuthProvider("self"), 
      AccessTokenExpireTimeSpan = TimeSpan.FromDays(14), 
      // https 
      AllowInsecureHttp = false 
     }; 
     // Enable the application to use bearer tokens to authenticate users 
     app.UseOAuthBearerTokens(oAuthOptions); 

Und in ApplicationOAuthProvider.cs dem Code, der tatsächlich gewährt oder Zugriff verweigert:

//using Microsoft.AspNet.Identity.Owin; 
//using Microsoft.Owin.Security; 
//using Microsoft.Owin.Security.OAuth; 
//using System; 
//using System.Collections.Generic; 
//using System.Security.Claims; 
//using System.Threading.Tasks; 

public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider 
{ 
    private readonly string _publicClientId; 

    public ApplicationOAuthProvider(string publicClientId) 
    { 
     if (publicClientId == null) 
      throw new ArgumentNullException("publicClientId"); 

     _publicClientId = publicClientId; 
    } 

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
    { 
     var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>(); 

     var user = await userManager.FindAsync(context.UserName, context.Password); 
     if (user == null) 
     { 
      context.SetError("invalid_grant", "The user name or password is incorrect."); 
      return; 
     } 

     ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager); 
     var propertyDictionary = new Dictionary<string, string> { { "userName", user.UserName } }; 
     var properties = new AuthenticationProperties(propertyDictionary); 

     AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties); 
     // Token is validated. 
     context.Validated(ticket); 
    } 

    public override Task TokenEndpoint(OAuthTokenEndpointContext context) 
    { 
     foreach (KeyValuePair<string, string> property in context.Properties.Dictionary) 
     { 
      context.AdditionalResponseParameters.Add(property.Key, property.Value); 
     } 
     return Task.FromResult<object>(null); 
    } 

    public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) 
    { 
     // Resource owner password credentials does not provide a client ID. 
     if (context.ClientId == null) 
      context.Validated(); 

     return Task.FromResult<object>(null); 
    } 

    public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context) 
    { 
     if (context.ClientId == _publicClientId) 
     { 
      var expectedRootUri = new Uri(context.Request.Uri, "/"); 

      if (expectedRootUri.AbsoluteUri == context.RedirectUri) 
       context.Validated(); 
     } 
     return Task.FromResult<object>(null); 
    } 

} 

Wie man dort sehen kann kein Controller in das Abrufen der Token beteiligt ist. In der Tat können Sie alle MVC-Referenzen entfernen, wenn Sie nur eine Web-API möchten. Ich habe den serverseitigen Code vereinfacht, um ihn lesbarer zu machen. Sie können Code hinzufügen, um die Sicherheit zu aktualisieren.

Stellen Sie sicher, dass Sie nur SSL verwenden. Implementieren Sie das RequireHttpsAttribute, um dies zu erzwingen.

Sie können die Attribute Authorize/AllowAnonymous verwenden, um Ihre Web API zu sichern. Zusätzlich können Sie Filter (wie RequireHttpsAttribute) hinzufügen, um Ihre Web-API sicherer zu machen. Ich hoffe das hilft.

+0

sagte "für MVC können Sie ein Login-Formular verwenden und erstellen Sie eine Sitzung mit Cookies. Für Web-API gibt es keine Sitzung" aber Formularauthentifizierung kann in Web-API implementiert werden. So kann der Client die Zugangsdaten an die Web-API senden, und die Web-API gibt den Authentifizierungs-Cookie an den Client aus. für alle nachfolgenden Call-Client muss auth Cookie an Web-API übergeben ...... ich denke, das ist möglich. –

+0

Ihren Code wie folgt auswählen. 'new KeyValuePair (" Gewährungsart "," Kennwort "), neu KeyValuePair (" Benutzername ", Benutzername), neu KeyValuePair (" Kennwort ", Kennwort) ' Was bedeutet' grant_type = Passwort? ' Welche andere Option können wir mit 'grant_type statt Passwort' verwenden? teilen Sie bitte Wissen. Vielen Dank –

11

Die ASP.Net-Web-API verfügt bereits über den Authorization Server-Build. Sie können es innerhalb Startup.cs sehen, wenn Sie eine neue ASP.Net-Webanwendung mit Web-API-Vorlage erstellen.

OAuthOptions = new OAuthAuthorizationServerOptions 
{ 
    TokenEndpointPath = new PathString("/Token"), 
    Provider = new ApplicationOAuthProvider(PublicClientId), 
    AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"), 
    AccessTokenExpireTimeSpan = TimeSpan.FromDays(14), 
    // In production mode set AllowInsecureHttp = false 
    AllowInsecureHttp = true 
}; 

Alles, was Sie tun müssen, ist zu URL codiert Benutzername und Passwort innerhalb Query-String zu schreiben.

/Token/userName=johndoe%40example.com&password=1234&grant_type=password 

Wenn Sie mehr Details wissen möchten, können Sie User Registration and Login - Angular Front to Back with Web API by Deborah Kurata beobachten.

+0

Also werde ich eine POST-Anfrage an/TOKEN mit Benutzername und Passwort in der HTTP Header/Body erstellen? Ich werde einen Benutzernamen und ein Hash-Passwort für alle Benutzer in meiner App-Datenbank haben. Wie soll ich das umsetzen? –

+0

Sie benötigen ASP.Net Identity * (ich glaube, Sie haben bereits eine) *. Wenn nicht, erstellen Sie ein ASP.Net-Web-API-Projekt und sehen Sie sich den Quellcode an. – Win

+1

Was ist Grant_type = Passwort? Bitte teile Wissen. Danke, –

Verwandte Themen