it-swarm.com.de

ASP.NET Core Web API-Authentifizierung

Ich habe Schwierigkeiten mit der Einrichtung der Authentifizierung in meinem Webdienst. Der Dienst wird mit der ASP.NET Core-Web-API erstellt.

Alle meine Clients (WPF-Anwendungen) sollten dieselben Anmeldeinformationen verwenden, um die Webdienstvorgänge aufzurufen. 

Nach einiger Recherche kam ich mit der Basisauthentifizierung - dem Senden eines Benutzernamens und eines Kennworts in den Header der HTTP-Anfrage. __ Nach stundenlanger Recherche scheint mir, dass die Basisauthentifizierung in ASP.NET nicht der richtige Weg ist Ader.

Die meisten Ressourcen, die ich gefunden habe, implementieren die Authentifizierung mit OAuth oder einer anderen Middleware. Dies scheint jedoch für mein Szenario überdimensioniert zu sein und den Identity-Teil von ASP.NET Core zu verwenden. 

Was ist also der richtige Weg, um mein Ziel zu erreichen - einfache Authentifizierung mit Benutzername und Kennwort in einem ASP.NET Core-Webservice?

Danke im Voraus!

53
Felix

Sie können eine Middleware implementieren, die die Standardauthentifizierung übernimmt. 

public async Task Invoke(HttpContext context)
{
    var authHeader = context.Request.Headers.Get("Authorization");
    if (authHeader != null && authHeader.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
    {
        var token = authHeader.Substring("Basic ".Length).Trim();
        System.Console.WriteLine(token);
        var credentialstring = Encoding.UTF8.GetString(Convert.FromBase64String(token));
        var credentials = credentialstring.Split(':');
        if(credentials[0] == "admin" && credentials[1] == "admin")
        {
            var claims = new[] { new Claim("name", credentials[0]), new Claim(ClaimTypes.Role, "Admin") };
            var identity = new ClaimsIdentity(claims, "Basic");
            context.User = new ClaimsPrincipal(identity);
        }
    }
    else
    {
        context.Response.StatusCode = 401;
        context.Response.Headers.Set("WWW-Authenticate", "Basic realm=\"dotnetthoughts.net\"");
    }
    await _next(context);
}

Dieser Code ist in einer Betaversion von asp.net core geschrieben. Ich hoffe es hilft.

50
Anuraj

Nun, nachdem ich in die richtige Richtung gezeigt wurde, hier meine vollständige Lösung: 

Dies ist die Middleware-Klasse, die bei jeder eingehenden Anforderung ausgeführt wird und prüft, ob die Anforderung die richtigen Anmeldeinformationen hat. Wenn keine Anmeldeinformationen vorhanden sind oder falsch sind, antwortet der Dienst sofort mit dem Fehler 401 Unauthorized.

public class AuthenticationMiddleware
{
    private readonly RequestDelegate _next;

    public AuthenticationMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        string authHeader = context.Request.Headers["Authorization"];
        if (authHeader != null && authHeader.StartsWith("Basic"))
        {
            //Extract credentials
            string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
            Encoding encoding = Encoding.GetEncoding("iso-8859-1");
            string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));

            int seperatorIndex = usernamePassword.IndexOf(':');

            var username = usernamePassword.Substring(0, seperatorIndex);
            var password = usernamePassword.Substring(seperatorIndex + 1);

            if(username == "test" && password == "test" )
            {
                await _next.Invoke(context);
            }
            else
            {
                context.Response.StatusCode = 401; //Unauthorized
                return;
            }
        }
        else
        {
            // no authorization header
            context.Response.StatusCode = 401; //Unauthorized
            return;
        }
    }
}

Die Middleware-Erweiterung muss in der Configure-Methode der Service-Startklasse aufgerufen werden

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    app.UseMiddleware<AuthenticationMiddleware>();

    app.UseMvc();
}

Und das ist alles! :)

Eine sehr gute Ressource für Middleware in .Net Core und Authentifizierung finden Sie hier: https://www.exceptionnotfound.net/writing-custom-middleware-in-asp-net-core-1-0/

68
Felix

Um dies nur für bestimmte Controller zu verwenden, verwenden Sie Folgendes:

app.UseWhen(x => (x.Request.Path.StartsWithSegments("/api", StringComparison.OrdinalIgnoreCase)), 
            builder =>
            {
                builder.UseMiddleware<AuthenticationMiddleware>();
            });
14
mr_squall

Ich denke, Sie können mit JWT (Json Web Tokens) gehen.

Zuerst müssen Sie das Paket System.IdentityModel.Tokens.Jwt installieren:

$ dotnet add package System.IdentityModel.Tokens.Jwt

Sie müssen einen Controller für die Token-Generierung und -Authentifizierung wie diesen hinzufügen:

public class TokenController : Controller
{
    [Route("/token")]

    [HttpPost]
    public IActionResult Create(string username, string password)
    {
        if (IsValidUserAndPasswordCombination(username, password))
            return new ObjectResult(GenerateToken(username));
        return BadRequest();
    }

    private bool IsValidUserAndPasswordCombination(string username, string password)
    {
        return !string.IsNullOrEmpty(username) && username == password;
    }

    private string GenerateToken(string username)
    {
        var claims = new Claim[]
        {
            new Claim(ClaimTypes.Name, username),
            new Claim(JwtRegisteredClaimNames.Nbf, new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString()),
            new Claim(JwtRegisteredClaimNames.Exp, new DateTimeOffset(DateTime.Now.AddDays(1)).ToUnixTimeSeconds().ToString()),
        };

        var token = new JwtSecurityToken(
            new JwtHeader(new SigningCredentials(
                new SymmetricSecurityKey(Encoding.UTF8.GetBytes("H38DLSIEKD8EKDOS")),
                                         SecurityAlgorithms.HmacSha256)),
            new JwtPayload(claims));

        return new JwtSecurityTokenHandler().WriteToken(token);
    }
}

Nach diesem Update sieht die Klasse Startup.cs wie folgt aus:

namespace WebAPISecurity
{   
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        services.AddAuthentication(options => {
            options.DefaultAuthenticateScheme = "JwtBearer";
            options.DefaultChallengeScheme = "JwtBearer";
        })
        .AddJwtBearer("JwtBearer", jwtBearerOptions =>
        {
            jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("H38DLSIEKD8EKDOS")),
                ValidateIssuer = false,
                //ValidIssuer = "The name of the issuer",
                ValidateAudience = false,
                //ValidAudience = "The name of the audience",
                ValidateLifetime = true, //validate the expiration and not before values in the token
                ClockSkew = TimeSpan.FromMinutes(5) //5 minute tolerance for the expiration date
            };
        });

    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseAuthentication();

        app.UseMvc();
    }
}

Und das ist es, was jetzt übrig bleibt, ist das [Authorize]-Attribut auf die gewünschten Controller oder Aktionen zu setzen.

Hier ist ein Link zu einem kompletten Tutorial.

http://www.blinkingcaret.com/2017/09/06/secure-web-api-in-asp-net-core/

8
Jaffal

Ich habe BasicAuthenticationHandler für die Basisauthentifizierung implementiert, sodass Sie es mit den Standardattributen Authorize und AllowAnonymous verwenden können.

public class BasicAuthenticationHandler : AuthenticationHandler<BasicAuthenticationOptions>
{
    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var authHeader = (string)this.Request.Headers["Authorization"];

        if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
        {
            //Extract credentials
            string encodedUsernamePassword = authHeader.Substring("Basic ".Length).Trim();
            Encoding encoding = Encoding.GetEncoding("iso-8859-1");
            string usernamePassword = encoding.GetString(Convert.FromBase64String(encodedUsernamePassword));

            int seperatorIndex = usernamePassword.IndexOf(':');

            var username = usernamePassword.Substring(0, seperatorIndex);
            var password = usernamePassword.Substring(seperatorIndex + 1);

            //you also can use this.Context.Authentication here
            if (username == "test" && password == "test")
            {
                var user = new GenericPrincipal(new GenericIdentity("User"), null);
                var ticket = new AuthenticationTicket(user, new AuthenticationProperties(), Options.AuthenticationScheme);
                return Task.FromResult(AuthenticateResult.Success(ticket));
            }
            else
            {
                return Task.FromResult(AuthenticateResult.Fail("No valid user."));
            }
        }

        this.Response.Headers["WWW-Authenticate"]= "Basic realm=\"yourawesomesite.net\"";
        return Task.FromResult(AuthenticateResult.Fail("No credentials."));
    }
}

public class BasicAuthenticationMiddleware : AuthenticationMiddleware<BasicAuthenticationOptions>
{
    public BasicAuthenticationMiddleware(
       RequestDelegate next,
       IOptions<BasicAuthenticationOptions> options,
       ILoggerFactory loggerFactory,
       UrlEncoder encoder)
       : base(next, options, loggerFactory, encoder)
    {
    }

    protected override AuthenticationHandler<BasicAuthenticationOptions> CreateHandler()
    {
        return new BasicAuthenticationHandler();
    }
}

public class BasicAuthenticationOptions : AuthenticationOptions
{
    public BasicAuthenticationOptions()
    {
        AuthenticationScheme = "Basic";
        AutomaticAuthenticate = true;
    }
}

Registrierung unter Startup.cs - app.UseMiddleware<BasicAuthenticationMiddleware>();. Mit diesem Code können Sie jeden Controller mit dem Standart-Attribut Autorize einschränken:

[Authorize(ActiveAuthenticationSchemes = "Basic")]
[Route("api/[controller]")]
public class ValuesController : Controller

und verwenden Sie das Attribut AllowAnonymous, wenn Sie einen Berechtigungsfilter auf Anwendungsebene anwenden.

4
Ivan R.

ASP.NET Core 2.0 mit Angular 

https://fullstackmark.com/post/13/jwt-authentication-with-aspnet-core-2-web-api-angular-5-net-core-identity-and-facebook-login

Stellen Sie sicher, dass Sie den Typ des Authentifizierungsfilters verwenden

[Authorize (AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

0

In diesem öffentlichen Repository von Github https://github.com/boskjoett/BasicAuthWebApi Können Sie ein einfaches Beispiel für eine ASP.NET Core 2.2-Web-API mit durch die Standardauthentifizierung geschützten Endpunkten sehen.

Wie in früheren Beiträgen zu Recht erwähnt, besteht eine Möglichkeit darin, eine benutzerdefinierte Middleware für die Basisauthentifizierung zu implementieren. In diesem Blog habe ich den besten funktionierenden Code mit Erläuterungen gefunden: Basic Auth with custom middleware

Ich bezog mich auf den gleichen Blog, musste aber zwei Anpassungen vornehmen:

  1. Fügen Sie beim Hinzufügen der Middleware in der Startdatei -> Funktion konfigurieren immer benutzerdefinierte Middleware hinzu, bevor Sie app.UseMvc () hinzufügen.
  2. Fügen Sie beim Lesen des Benutzernamens und des Kennworts aus der Datei appsettings.json eine statische schreibgeschützte Eigenschaft in die Startdatei ein. Dann lies aus appsettings.json. Lesen Sie abschließend die Werte an einer beliebigen Stelle im Projekt. Beispiel:

    public class Startup
    {
      public Startup(IConfiguration configuration)
      {
        Configuration = configuration;
      }
    
      public IConfiguration Configuration { get; }
      public static string UserNameFromAppSettings { get; private set; }
      public static string PasswordFromAppSettings { get; private set; }
    
      //set username and password from appsettings.json
      UserNameFromAppSettings = Configuration.GetSection("BasicAuth").GetSection("UserName").Value;
      PasswordFromAppSettings = Configuration.GetSection("BasicAuth").GetSection("Password").Value;
    }
    
0
Palash Roy