it-swarm.com.de

Einfache JWT-Authentifizierung in ASP.NET Core 1.0-Web-API

Ich suche nach der einfachsten Methode zum Einrichten eines Web-API-Servers, der JWTs für die Authentifizierung in ASP.NET Core (auch als ASP.NET 5 bezeichnet) verwendet. Dieses Projekt ( blog post / github ) macht genau das, was ich suche, aber es verwendet ASP.NET 4.

Ich möchte nur in der Lage sein:

  1. richten Sie eine Login-Route ein, die ein JWT-Token erstellen und im Header zurückgeben kann. Ich integriere dies mit einem vorhandenen RESTful-Service, der mir sagt, ob der Benutzername und das Passwort gültig sind. Im ASP.NET 4-Projekt, das ich mir anschaue, könnte dies mit der folgenden Route geschehen: https://github.com/stewartm83/Jwt-WebApi/blob/master/src/JwtWebApi/Controllers/AccountController.cs# L24-L54

  2. Fangen Sie eingehende Anforderungen an Routen ab, für die eine Autorisierung erforderlich ist, entschlüsseln und validieren Sie das in den Header kommende JWT-Token und machen Sie die Benutzerinformationen in der Nutzlast des JWT-Token für die Route verfügbar. z.B. etwas wie das: https://github.com/stewartm83/Jwt-WebApi/blob/master/src/JwtWebApi/App_Start/AuthHandler.cs

Alle Beispiele, die ich in ASP.NET Core gesehen habe, sind sehr komplex und stützen sich auf einige oder alle von OAuth, IS, OpenIddict und EF, die ich vermeiden möchte.

Kann mir jemand auf ein Beispiel verweisen, wie dies in ASP.NET Core zu tun ist, oder mir helfen, damit zu beginnen?

EDIT: Beantworten Sie Ich habe diese Antwort verwendet: https://stackoverflow.com/a/33217340/373655

57
rob

Hinweis/Aktualisierung:

Der folgende Code war für .NET Core 1.1
Da .NET Core 1 sehr RTM-fähig war, änderte sich die Authentifizierung mit dem Sprung von .NET Core 1 auf 2.0 (auch bekannt als [teilweise?] Mit aktuellen Änderungen).
Deshalb funktioniert der folgende Code NICHT mehr mit .NET Core 2.0.
Aber es wird immer noch eine nützliche Lektüre sein.

Update 2018

In der Zwischenzeit finden Sie ein funktionierendes Beispiel für die JWT-Cookie-Authentifizierung von ASP.NET Core 2.0 auf meinem Github-Test-Repo . Wird mit einer Implementierung der abstrakten Klasse MS-RSA & MS-ECDSA mit BouncyCastle und einem Schlüsselgenerator für RSA & ECDSA geliefert.


Nekromanzierung.
Ich habe mich tiefer mit JWT befasst. Hier sind meine Ergebnisse:

Sie müssen Microsoft.AspNetCore.Authentication.JwtBearer hinzufügen

dann kannst du einstellen

app.UseJwtBearerAuthentication(bearerOptions);

in Startup.cs => Konfigurieren

wo bearerOptions von Ihnen definiert wird, z. wie

var bearerOptions = new JwtBearerOptions()
{
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    TokenValidationParameters = tokenValidationParameters,
    Events = new CustomBearerEvents()
};

// Optional 
// bearerOptions.SecurityTokenValidators.Clear();
// bearerOptions.SecurityTokenValidators.Add(new MyTokenHandler());

dabei ist CustomBearerEvents der Ort, an dem Sie Token-Daten zum httpContext/Route hinzufügen können

// https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/JwtBearerEvents.cs
public class CustomBearerEvents : Microsoft.AspNetCore.Authentication.JwtBearer.IJwtBearerEvents
{

    /// <summary>
    /// Invoked if exceptions are thrown during request processing. The exceptions will be re-thrown after this event unless suppressed.
    /// </summary>
    public Func<AuthenticationFailedContext, Task> OnAuthenticationFailed { get; set; } = context => Task.FromResult(0);

    /// <summary>
    /// Invoked when a protocol message is first received.
    /// </summary>
    public Func<MessageReceivedContext, Task> OnMessageReceived { get; set; } = context => Task.FromResult(0);

    /// <summary>
    /// Invoked after the security token has passed validation and a ClaimsIdentity has been generated.
    /// </summary>
    public Func<TokenValidatedContext, Task> OnTokenValidated { get; set; } = context => Task.FromResult(0);


    /// <summary>
    /// Invoked before a challenge is sent back to the caller.
    /// </summary>
    public Func<JwtBearerChallengeContext, Task> OnChallenge { get; set; } = context => Task.FromResult(0);


    Task IJwtBearerEvents.AuthenticationFailed(AuthenticationFailedContext context)
    {
        return OnAuthenticationFailed(context);
    }

    Task IJwtBearerEvents.Challenge(JwtBearerChallengeContext context)
    {
        return OnChallenge(context);
    }

    Task IJwtBearerEvents.MessageReceived(MessageReceivedContext context)
    {
        return OnMessageReceived(context);
    }

    Task IJwtBearerEvents.TokenValidated(TokenValidatedContext context)
    {
        return OnTokenValidated(context);
    }
}

Und tokenValidationParameters wird von Ihnen definiert, z.

var tokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
    // The signing key must match!
    ValidateIssuerSigningKey = true,
    IssuerSigningKey = signingKey,

    // Validate the JWT Issuer (iss) claim
    ValidateIssuer = true,
    ValidIssuer = "ExampleIssuer",

    // Validate the JWT Audience (aud) claim
    ValidateAudience = true,
    ValidAudience = "ExampleAudience",

    // Validate the token expiry
    ValidateLifetime = true,

    // If you want to allow a certain amount of clock drift, set that here:
    ClockSkew = TimeSpan.Zero, 
};

Und MyTokenHandler wird optional von Ihnen definiert, wenn Sie die Token-Validierung anpassen möchten, z.

// https://Gist.github.com/pmhsfelix/4151369
public class MyTokenHandler : Microsoft.IdentityModel.Tokens.ISecurityTokenValidator
{
    private int m_MaximumTokenByteSize;

    public MyTokenHandler()
    { }

    bool ISecurityTokenValidator.CanValidateToken
    {
        get
        {
            // throw new NotImplementedException();
            return true;
        }
    }



    int ISecurityTokenValidator.MaximumTokenSizeInBytes
    {
        get
        {
            return this.m_MaximumTokenByteSize;
        }

        set
        {
            this.m_MaximumTokenByteSize = value;
        }
    }

    bool ISecurityTokenValidator.CanReadToken(string securityToken)
    {
        System.Console.WriteLine(securityToken);
        return true;
    }

    ClaimsPrincipal ISecurityTokenValidator.ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
    {
        JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
        // validatedToken = new JwtSecurityToken(securityToken);
        try
        {

            tokenHandler.ValidateToken(securityToken, validationParameters, out validatedToken);
            validatedToken = new JwtSecurityToken("jwtEncodedString");
        }
        catch (Exception ex)
        {
            System.Console.WriteLine(ex.Message);
            throw;
        }



        ClaimsPrincipal principal = null;
        // SecurityToken validToken = null;

        validatedToken = null;


        System.Collections.Generic.List<System.Security.Claims.Claim> ls =
            new System.Collections.Generic.List<System.Security.Claims.Claim>();

        ls.Add(
            new System.Security.Claims.Claim(
                System.Security.Claims.ClaimTypes.Name, "IcanHazUsr_éèêëïàáâäåãæóòôöõõúùûüñçø_ÉÈÊËÏÀÁÂÄÅÃÆÓÒÔÖÕÕÚÙÛÜÑÇØ 你好,世界 Привет\tмир"
            , System.Security.Claims.ClaimValueTypes.String
            )
        );

        // 

        System.Security.Claims.ClaimsIdentity id = new System.Security.Claims.ClaimsIdentity("authenticationType");
        id.AddClaims(ls);

        principal = new System.Security.Claims.ClaimsPrincipal(id);

        return principal;
        throw new NotImplementedException();
    }


}

Der schwierige Teil ist, wie Sie den AsymmetricSecurityKey erhalten, da Sie keinen rsaCryptoServiceProvider übergeben möchten, da Sie Interoperabilität im Kryptoformat benötigen.

Die Schöpfung folgt der Linie von

// System.Security.Cryptography.X509Certificates.X509Certificate2 cert2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(byte[] rawData);
System.Security.Cryptography.X509Certificates.X509Certificate2 cert2 = 
    DotNetUtilities.CreateX509Cert2("mycert");
Microsoft.IdentityModel.Tokens.SecurityKey secKey = new X509SecurityKey(cert2);

z.B. mit BouncyCastle von einem DER Zertifikat:

    // http://stackoverflow.com/questions/36942094/how-can-i-generate-a-self-signed-cert-without-using-obsolete-bouncycastle-1-7-0
    public static System.Security.Cryptography.X509Certificates.X509Certificate2 CreateX509Cert2(string certName)
    {

        var keypairgen = new Org.BouncyCastle.Crypto.Generators.RsaKeyPairGenerator();
        keypairgen.Init(new Org.BouncyCastle.Crypto.KeyGenerationParameters(
            new Org.BouncyCastle.Security.SecureRandom(
                new Org.BouncyCastle.Crypto.Prng.CryptoApiRandomGenerator()
                )
                , 1024
                )
        );

        Org.BouncyCastle.Crypto.AsymmetricCipherKeyPair keypair = keypairgen.GenerateKeyPair();

        // --- Until here we generate a keypair



        var random = new Org.BouncyCastle.Security.SecureRandom(
                new Org.BouncyCastle.Crypto.Prng.CryptoApiRandomGenerator()
        );


        // SHA1WITHRSA
        // SHA256WITHRSA
        // SHA384WITHRSA
        // SHA512WITHRSA

        // SHA1WITHECDSA
        // SHA224WITHECDSA
        // SHA256WITHECDSA
        // SHA384WITHECDSA
        // SHA512WITHECDSA

        Org.BouncyCastle.Crypto.ISignatureFactory signatureFactory = 
            new Org.BouncyCastle.Crypto.Operators.Asn1SignatureFactory("SHA512WITHRSA", keypair.Private, random)
        ;



        var gen = new Org.BouncyCastle.X509.X509V3CertificateGenerator();


        var CN = new Org.BouncyCastle.Asn1.X509.X509Name("CN=" + certName);
        var SN = Org.BouncyCastle.Math.BigInteger.ProbablePrime(120, new Random());

        gen.SetSerialNumber(SN);
        gen.SetSubjectDN(CN);
        gen.SetIssuerDN(CN);
        gen.SetNotAfter(DateTime.Now.AddYears(1));
        gen.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0)));
        gen.SetPublicKey(keypair.Public);


        // -- Are these necessary ? 

        // public static readonly DerObjectIdentifier AuthorityKeyIdentifier = new DerObjectIdentifier("2.5.29.35");
        // OID value: 2.5.29.35
        // OID description: id-ce-authorityKeyIdentifier
        // This extension may be used either as a certificate or CRL extension. 
        // It identifies the public key to be used to verify the signature on this certificate or CRL.
        // It enables distinct keys used by the same CA to be distinguished (e.g., as key updating occurs).


        // http://stackoverflow.com/questions/14930381/generating-x509-certificate-using-bouncy-castle-Java
        gen.AddExtension(
        Org.BouncyCastle.Asn1.X509.X509Extensions.AuthorityKeyIdentifier.Id,
        false,
        new Org.BouncyCastle.Asn1.X509.AuthorityKeyIdentifier(
            Org.BouncyCastle.X509.SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(keypair.Public),
            new Org.BouncyCastle.Asn1.X509.GeneralNames(new Org.BouncyCastle.Asn1.X509.GeneralName(CN)),
            SN
        ));

        // OID value: 1.3.6.1.5.5.7.3.1
        // OID description: Indicates that a certificate can be used as an SSL server certificate.
        gen.AddExtension(
            Org.BouncyCastle.Asn1.X509.X509Extensions.ExtendedKeyUsage.Id,
            false,
            new Org.BouncyCastle.Asn1.X509.ExtendedKeyUsage(new ArrayList()
            {
            new Org.BouncyCastle.Asn1.DerObjectIdentifier("1.3.6.1.5.5.7.3.1")
        }));

        // -- End are these necessary ? 

        Org.BouncyCastle.X509.X509Certificate bouncyCert = gen.Generate(signatureFactory);

        byte[] ba = bouncyCert.GetEncoded();
        System.Security.Cryptography.X509Certificates.X509Certificate2 msCert = new System.Security.Cryptography.X509Certificates.X509Certificate2(ba);
        return msCert;
    }

Anschließend können Sie ein benutzerdefiniertes Cookie-Format hinzufügen, das den JWT-Bearer enthält:

app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
    AuthenticationScheme = "MyCookieMiddlewareInstance",
    CookieName = "SecurityByObscurityDoesntWork",
    ExpireTimeSpan = new System.TimeSpan(15, 0, 0),
    LoginPath = new Microsoft.AspNetCore.Http.PathString("/Account/Unauthorized/"),
    AccessDeniedPath = new Microsoft.AspNetCore.Http.PathString("/Account/Forbidden/"),
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    CookieSecure = Microsoft.AspNetCore.Http.CookieSecurePolicy.SameAsRequest,
    CookieHttpOnly = false,
    TicketDataFormat = new CustomJwtDataFormat("foo", tokenValidationParameters)

    // DataProtectionProvider = null,

    // DataProtectionProvider = new DataProtectionProvider(new System.IO.DirectoryInfo(@"c:\shared-auth-ticket-keys\"),
    //delegate (DataProtectionConfiguration options)
    //{
    //    var op = new Microsoft.AspNet.DataProtection.AuthenticatedEncryption.AuthenticatedEncryptionOptions();
    //    op.EncryptionAlgorithm = Microsoft.AspNet.DataProtection.AuthenticatedEncryption.EncryptionAlgorithm.AES_256_GCM:
    //    options.UseCryptographicAlgorithms(op);
    //}
    //),
});

Wo CustomJwtDataFormat ist etwas in der Art von

public class CustomJwtDataFormat : ISecureDataFormat<AuthenticationTicket>
{

    private readonly string algorithm;
    private readonly TokenValidationParameters validationParameters;

    public CustomJwtDataFormat(string algorithm, TokenValidationParameters validationParameters)
    {
        this.algorithm = algorithm;
        this.validationParameters = validationParameters;
    }



    // This ISecureDataFormat implementation is decode-only
    string ISecureDataFormat<AuthenticationTicket>.Protect(AuthenticationTicket data)
    {
        return MyProtect(data, null);
    }

    string ISecureDataFormat<AuthenticationTicket>.Protect(AuthenticationTicket data, string purpose)
    {
        return MyProtect(data, purpose);
    }

    AuthenticationTicket ISecureDataFormat<AuthenticationTicket>.Unprotect(string protectedText)
    {
        return MyUnprotect(protectedText, null);
    }

    AuthenticationTicket ISecureDataFormat<AuthenticationTicket>.Unprotect(string protectedText, string purpose)
    {
        return MyUnprotect(protectedText, purpose);
    }


    private string MyProtect(AuthenticationTicket data, string purpose)
    {
        return "wadehadedudada";
        throw new System.NotImplementedException();
    }


    // http://blogs.Microsoft.co.il/sasha/2012/01/20/aggressive-inlining-in-the-clr-45-jit/
    [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    private AuthenticationTicket MyUnprotect(string protectedText, string purpose)
    {
        JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
        ClaimsPrincipal principal = null;
        SecurityToken validToken = null;


        System.Collections.Generic.List<System.Security.Claims.Claim> ls = 
            new System.Collections.Generic.List<System.Security.Claims.Claim>();

        ls.Add(
            new System.Security.Claims.Claim(
                System.Security.Claims.ClaimTypes.Name, "IcanHazUsr_éèêëïàáâäåãæóòôöõõúùûüñçø_ÉÈÊËÏÀÁÂÄÅÃÆÓÒÔÖÕÕÚÙÛÜÑÇØ 你好,世界 Привет\tмир"
            , System.Security.Claims.ClaimValueTypes.String
            )
        );

        // 

        System.Security.Claims.ClaimsIdentity id = new System.Security.Claims.ClaimsIdentity("authenticationType");
        id.AddClaims(ls);

        principal = new System.Security.Claims.ClaimsPrincipal(id);
        return new AuthenticationTicket(principal, new AuthenticationProperties(), "MyCookieMiddlewareInstance");


        try
        {
            principal = handler.ValidateToken(protectedText, this.validationParameters, out validToken);

            JwtSecurityToken validJwt = validToken as JwtSecurityToken;

            if (validJwt == null)
            {
                throw new System.ArgumentException("Invalid JWT");
            }

            if (!validJwt.Header.Alg.Equals(algorithm, System.StringComparison.Ordinal))
            {
                throw new System.ArgumentException($"Algorithm must be '{algorithm}'");
            }

            // Additional custom validation of JWT claims here (if any)
        }
        catch (SecurityTokenValidationException)
        {
            return null;
        }
        catch (System.ArgumentException)
        {
            return null;
        }

        // Validation passed. Return a valid AuthenticationTicket:
        return new AuthenticationTicket(principal, new AuthenticationProperties(), "MyCookieMiddlewareInstance");
    }


}

Sie können das JWT-Token auch mit Microsoft.IdentityModel.Token erstellen:

// https://github.com/aspnet/Security/blob/master/src/Microsoft.AspNetCore.Authentication.JwtBearer/Events/IJwtBearerEvents.cs
// http://codereview.stackexchange.com/questions/45974/web-api-2-authentication-with-jwt
public class TokenMaker
{

    class SecurityConstants
    {
        public static string TokenIssuer;
        public static string TokenAudience;
        public static int TokenLifetimeMinutes;
    }


    public static string IssueToken()
    {
        SecurityKey sSKey = null;

        var claimList = new List<Claim>()
        {
            new Claim(ClaimTypes.Name, "userName"),
            new Claim(ClaimTypes.Role, "role")     //Not sure what this is for
        };

        JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
        SecurityTokenDescriptor desc = makeSecurityTokenDescriptor(sSKey, claimList);

        // JwtSecurityToken tok = tokenHandler.CreateJwtSecurityToken(desc);
        return tokenHandler.CreateEncodedJwt(desc);
    }


    public static ClaimsPrincipal ValidateJwtToken(string jwtToken)
    {
        SecurityKey sSKey = null;
        var tokenHandler = new JwtSecurityTokenHandler();

        // Parse JWT from the Base64UrlEncoded wire form 
        //(<Base64UrlEncoded header>.<Base64UrlEncoded body>.<signature>)
        JwtSecurityToken parsedJwt = tokenHandler.ReadToken(jwtToken) as JwtSecurityToken;

        TokenValidationParameters validationParams =
            new TokenValidationParameters()
            {
                RequireExpirationTime = true,
                ValidAudience = SecurityConstants.TokenAudience,
                ValidIssuers = new List<string>() { SecurityConstants.TokenIssuer },
                ValidateIssuerSigningKey = true,
                ValidateLifetime = true,
                IssuerSigningKey = sSKey,

            };

        SecurityToken secT;
        return tokenHandler.ValidateToken("token", validationParams, out secT);
    }


    private static SecurityTokenDescriptor makeSecurityTokenDescriptor(SecurityKey sSKey, List<Claim> claimList)
    {
        var now = DateTime.UtcNow;
        Claim[] claims = claimList.ToArray();
        return new Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(claims),
            Issuer = SecurityConstants.TokenIssuer,
            Audience = SecurityConstants.TokenAudience,
            IssuedAt = System.DateTime.UtcNow,
            Expires = System.DateTime.UtcNow.AddMinutes(SecurityConstants.TokenLifetimeMinutes),
            NotBefore = System.DateTime.UtcNow.AddTicks(-1),

            SigningCredentials = new SigningCredentials(sSKey, Microsoft.IdentityModel.Tokens.SecurityAlgorithms.EcdsaSha512Signature)
        };



    }

}

Beachten Sie, dass Sie tatsächlich MEHR als 1 Benutzer haben können, da Sie im Cookie einen anderen Benutzer als http-Header (Bearer) oder eine andere von Ihnen angegebene Authentifizierungsmethode angeben können!


Schau dir das an:
https://stormpath.com/blog/token-authentication-asp-net-core

es sollte genau das sein, wonach du suchst.

Es gibt auch diese beiden:

https://goblincoding.com/2016/07/03/issuing-and-authentication-jwt-tokens-in-asp-net-core-webapi-part-i/

https://goblincoding.com/2016/07/issuing-and-authentication-jwt-tokens-in-asp-net-core-webapi-part-ii/

und das hier
http://blog.novanet.no/hooking-up-asp-net-core-1-rc1-web-api-with-auth0-bearer-tokens/

Und die JWT-Bearer-Quellen https://github.com/aspnet/Security/tree/master/src/Microsoft.AspNetCore.Authentication.JwtBearer


Wenn Sie ultrahohe Sicherheit benötigen, sollten Sie sich vor Wiederholungsangriffen schützen, indem Sie das Ticket bei jeder Anforderung erneuern und alte Tickets nach einem bestimmten Timeout und nach dem Abmelden des Benutzers ungültig machen (nicht erst nach Ablauf der Gültigkeit).


Für diejenigen von Ihnen, die von hier aus über Google kommen, können Sie ein TicketDataFormat in die Cookie-Authentifizierung implementieren, wenn Sie Ihre eigene Version von JWT verwenden möchten.

Ich musste mich bei JWT umsehen, weil wir unsere Bewerbung sichern mussten.
Da ich noch .NET 2.0 verwenden musste, musste ich meine eigene Bibliothek schreiben.

Ich habe das Ergebnis dieses Wochenendes auf .NET Core portiert. Sie finden es hier: https://github.com/ststeiger/Jwt_Net20/tree/master/CoreJWT

Es verwendet keine Datenbank, das ist nicht die Aufgabe einer JWT-Bibliothek.
Das Abrufen und Einstellen von DB-Daten ist Ihre Aufgabe.
Die Bibliothek ermöglicht die JWT-Autorisierung und -Verifizierung in .NET Core mit allen Algorithmen angegeben in der JWT-RFC, die in der IANA JOSE-Zuweisung aufgeführt ist .
Was das Hinzufügen von Berechtigungen zur Pipeline und das Hinzufügen von Werten zur Route betrifft - dies sind zwei Dinge, die separat durchgeführt werden sollten, und ich denke, Sie tun dies am besten selbst.

Sie können die benutzerdefinierte Authentifizierung in ASP.NET Core verwenden.
Sehen Sie sich die Kategorie "Sicherheit" in docs.asp.net an.

Oder Sie schauen in die Cookie-Middleware ohne ASP.NET-Identität oder in Benutzerdefinierte richtlinienbasierte Autorisierung .

Weitere Informationen erhalten Sie auch im auth workshop on github oder im social login Abschnitt oder in dieses Video-Tutorial für Kanal 9 .
Wenn alles andere fehlschlägt, lautet der Quellcode der asp.net-Sicherheit auf github .


Das ursprüngliche Projekt für .NET 3.5, von dem meine Bibliothek abgeleitet ist, ist hier:
https://github.com/jwt-dotnet/jwt
Ich habe alle Verweise auf LINQ + -Erweiterungsmethoden entfernt, da sie in .NET 2.0 nicht unterstützt werden. Wenn Sie entweder LINQ oder ExtensionAttribute in den Quellcode aufnehmen, können Sie die .NET-Laufzeit nicht einfach ändern, ohne Warnungen zu erhalten. deshalb habe ich sie komplett entfernt.
Außerdem habe ich RSA + ECSD JWS-Methoden hinzugefügt, aus diesem Grund hängt das CoreJWT-Projekt von BouncyCastle ab.
Wenn Sie sich auf HMAC-SHA256 + HMAC-SHA384 + HMAC-SHA512 beschränken, können Sie BouncyCastle entfernen.

JWE wird (noch) nicht unterstützt.

Die Verwendung ist wie bei jwt-dotnet/jwt , außer dass ich den Namespace JWT in CoreJWT geändert habe.
Ich habe auch eine interne Kopie von PetaJSON als Serializer hinzugefügt, damit die Projektabhängigkeiten anderer nicht beeinträchtigt werden.

Erstellen Sie ein JWT-Token:

var payload = new Dictionary<string, object>()
{
    { "claim1", 0 },
    { "claim2", "claim2-value" }
};
var secretKey = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
string token = JWT.JsonWebToken.Encode(payload, secretKey, JWT.JwtHashAlgorithm.HS256);
Console.WriteLine(token);

Überprüfen Sie ein JWT-Token:

var token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJjbGFpbTEiOjAsImNsYWltMiI6ImNsYWltMi12YWx1ZSJ9.8pwBI_HtXqI3UgQHQ_rDRnSQRxFL1SR8fbQoS-5kM5s";
var secretKey = "GQDstcKsx0NHjPOuXOYg5MbeJ1XT0uFiwDVvVBrk";
try
{
    string jsonPayload = JWT.JsonWebToken.Decode(token, secretKey);
    Console.WriteLine(jsonPayload);
}
catch (JWT.SignatureVerificationException)
{
    Console.WriteLine("Invalid token!");
}

Für RSA & ECSA müssen Sie anstelle von secretKey den privaten RSA/ECSD-Schlüssel (BouncyCastle) übergeben.

namespace BouncyJWT
{


    public class JwtKey
    {
        public byte[] MacKeyBytes;
        public Org.BouncyCastle.Crypto.AsymmetricKeyParameter RsaPrivateKey;
        public Org.BouncyCastle.Crypto.Parameters.ECPrivateKeyParameters EcPrivateKey;


        public string MacKey
        {
            get { return System.Text.Encoding.UTF8.GetString(this.MacKeyBytes); }
            set { this.MacKeyBytes = System.Text.Encoding.UTF8.GetBytes(value); }
        }


        public JwtKey()
        { }

        public JwtKey(string macKey)
        {
            this.MacKey = macKey;
        }

        public JwtKey(byte[] macKey)
        {
            this.MacKeyBytes = macKey;
        }

        public JwtKey(Org.BouncyCastle.Crypto.AsymmetricKeyParameter rsaPrivateKey)
        {
            this.RsaPrivateKey = rsaPrivateKey;
        }

        public JwtKey(Org.BouncyCastle.Crypto.Parameters.ECPrivateKeyParameters ecPrivateKey)
        {
            this.EcPrivateKey = ecPrivateKey;
        }
    }


}

Informationen zum Generieren/Exportieren/Importieren von RSA/ECSD-Schlüsseln mit BouncyCastle finden Sie im Projekt "BouncyCastleTests" im selben Repository. Ich überlasse es Ihnen, Ihre eigenen privaten RSA/ECSD-Schlüssel sicher zu speichern und abzurufen.

Ich habe die Ergebnisse meiner Bibliothek für HMAC-ShaXXX und RSA-XXX mit JWT.io überprüft - anscheinend sind sie in Ordnung.
ECSD sollte auch in Ordnung sein, aber ich habe es gegen nichts getestet.
Ich habe sowieso keine umfangreichen Tests durchgeführt, FYI.

50
Stefan Steiger

Die einfachste Option, die ich bisher gefunden habe, ist OpenIddict . Sie sagen, Sie wollen Entity Framework und OpenIddict vermeiden - dann müssen Sie selbst viel programmieren und Teile von OpenIddict und ASOS (die OpenIddict verwendet) effektiv umschreiben, um das zu tun, was sie sowieso tun.

Wenn Sie mit OpenIddict zufrieden sind, ist dies praktisch die gesamte Konfiguration, die Sie benötigen. Es ist sehr einfach. 

Wenn Sie EF nicht verwenden möchten, ist dies mit OpenIddict möglich. Ich bin nicht sicher, wie, aber das ist der Punkt, den Sie herausfinden müssen.

ConfigureServices:

services.AddIdentity<ApplicationUser, ApplicationRole>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders()
            .AddOpenIddictCore<Application>(config => config.UseEntityFramework()); // this line is for OpenIddict

Konfigurieren

app.UseOpenIddictCore(builder =>
{
    // tell openiddict you're wanting to use jwt tokens
    builder.Options.UseJwtTokens();
    // NOTE: for dev consumption only! for live, this is not encouraged!
    builder.Options.AllowInsecureHttp = true;
    builder.Options.ApplicationCanDisplayErrors = true;
});

// use jwt bearer authentication
app.UseJwtBearerAuthentication(options =>
{
    options.AutomaticAuthenticate = true;
    options.AutomaticChallenge = true;
    options.RequireHttpsMetadata = false;
    // these urls must match the value sent in the payload posted from the client side during login
    options.Audience = "http://localhost:58292/";
    options.Authority = "http://localhost:58292/";
});

Es gibt ein oder zwei weitere Kleinigkeiten, die DbContext von OpenIddictContext<ApplicationUser, Application, ApplicationRole, string> ableiten muss.

In diesem Blogbeitrag finden Sie eine ausführliche Erklärung (einschließlich Links zum Github-Repo): http://capesean.co.za/blog/asp-net-5-jwt-tokens/

13
Sean

Wenn Sie nur eine Authentifizierung gegen einen externen OAuth/OpenID-Anbieter (wie Google, GitHub, Facebook, Microsoft-Konto usw.) benötigen, benötigen Sie keine Tools von Drittanbietern. 

Authentifizierungsanbieter für die am häufigsten verwendeten OAuth- und OpenID-Anbieter werden mit ASP.NET Core bereits in den Microsoft.AspNetCore.Authorization.*-Paketen bereitgestellt. Schauen Sie sich die Beispiele an, die im GitHub-Repository des " Security " - Repositorys bereitgestellt werden 

Wenn Sie eigene JWT-Token erstellen müssen, benötigen Sie einen OAuth/OpenID-Server. OpenIddict ist ein einfach einzurichtender Autorisierungsserver. Hierfür benötigen Sie eine Art Datenbank, da externe Anbieter zur Authentifizierung der Person verwendet werden. Sie benötigen jedoch auch ein Konto auf Ihrem Autorisierungsserver.

Wenn Sie mehr Anpassungen und mehr Kontrolle über den Fluss benötigen, müssen Sie ASOS oder IdentityServer4 verwenden (wird derzeit nur von ASP.NET Core unterstützt, wenn Sie mit vollständigem .NET Framework oder Mono arbeiten. Die Core-Laufzeit wird meines Wissens noch nicht unterstützt.) . 

Es gibt auch einen Gitter-Chatroom für OpenIddict unter https://gitter.im/openiddict/core und https://gitter.im/aspnet-contrib/AspNet.Security.OpenIdConnect.Server für ASOS .

9
Tseng

Es gibt ein vollständiges Beispiel für ASP.NET Core + JWT Auth + SQL Server + Swagger: https://github.com/wilsonwu/netcoreauth

Hoffe das kann dir helfen.

2
Wilson Wu

Hier ist ein Paket welches 

  • Die Integration von JWT Bearer Token Security in Ihre App Asp Net Core 2.0+ wird zum Kinderspiel!
  • Azure Active Directory-Authentifizierungsintegration.
  • Facebook Auth Integration. 
  • Auch Swagger UI-Integration!

Es heißt AspNetCore.Security.Jwt.

GitHub:

https://github.com/VeritasSoftware/AspNetCore.Security.Jwt

Das Paket integriert das JWT-Trägertoken wie folgt in Ihre App:

1. Implementieren Sie die IAuthentication-Schnittstelle in Ihrer App

using AspNetCore.Security.Jwt;
using System.Threading.Tasks;

namespace XXX.API
{
    public class Authenticator : IAuthentication
    {        
        public async Task<bool> IsValidUser(string id, string password)
        {
            //Put your id authenication here.
            return true;
        }
    }
}

2. In Ihrer Startup.cs

using AspNetCore.Security.Jwt;
using Swashbuckle.AspNetCore.Swagger;
.
.
public void ConfigureServices(IServiceCollection services)
{
    .
    .
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new Info { Title = "XXX API", Version = "v1" });
    });

    services.AddSecurity<Authenticator>(this.Configuration, true);
    services.AddMvc().AddSecurity();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    .
    .
    .
    // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), 
    // specifying the Swagger JSON endpoint.
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "XXX API V1");
    });

    app.UseSecurity(true);

    app.UseMvc();
}

3. In Ihrem appsettings.json

Hinweis: - Sie können diese Einstellungen in Secret Manager vornehmen, indem Sie das Menü User Secrets verwalten verwenden (klicken Sie mit der rechten Maustaste auf Ihr Projekt).

 {
     "SecuritySettings": {
        "Secret": "a secret that needs to be at least 16 characters long",
        "Issuer": "your app",
        "Audience": "the client of your app",
        "IdType":  "Name",
        "TokenExpiryInHours" :  2
    },
    .
    .
    .
}

Dann erhalten Sie automatisch Endpunkte:

/Zeichen

/Facebook

Wenn Sie diese Endpunkte aufrufen und erfolgreich authentifiziert werden, erhalten Sie ein JWT-Bearer-Token zurück.

In Ihrem Controller, den Sie sichern möchten

Sie müssen den Controller oder die Aktion, die Sie mit dem Attribut Authorize sichern möchten, wie folgt markieren:

    using Microsoft.AspNetCore.Mvc;
    .
    .
    .

    namespace XXX.API.Controllers
    {
        using Microsoft.AspNetCore.Authorization;

        [Authorize]
        [Route("api/[controller]")]
        public class XXXController : Controller
        {
            .
            .
            .
        }
    }

In der Swagger-Benutzeroberfläche werden diese Endpunkte automatisch angezeigt.

 Auth

0
Shane

Sicherung der ASP.NET Core 2.0-Web-API mit der auf Standard JWT Bearer Token basierenden Authentifizierung 

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

& Wenden Sie den Autorisierungsfilter wie folgt an 

 [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
0