ASP.NET Core 1.0 Web API中的简单JWT身份验证

rob*_*rob 58 c# asp.net authentication asp.net-web-api asp.net-core

我正在寻找最简单的方法来设置一个Web API服务器,该服务器使用JWT进行ASP.NET Core(即ASP.NET 5)中的身份验证.这个项目(博客文章/github)正是我正在寻找的,但它使用的是ASP.NET 4.

我只希望能够:

  1. 设置一个登录路由,可以创建一个JWT令牌并将其返回到标题中.我正在将它与现有的RESTful服务集成,它将告诉我用户名和密码是否有效.在ASP.NET 4项目中,我看到这可以通过以下路由完成https://github.com/stewartm83/Jwt-WebApi/blob/master/src/JwtWebApi/Controllers/AccountController.cs#L24- L54

  2. 拦截对需要授权的路由的传入请求,解密并验证标头中的JWT令牌,并使JWT令牌的有效负载中的用户信息可供路由访问.例如:https://github.com/stewartm83/Jwt-WebApi/blob/master/src/JwtWebApi/App_Start/AuthHandler.cs

我在ASP.NET Core中看到的所有示例都非常复杂,并且依赖于我想避免的部分或全部OAuth,IS,OpenIddict和EF.

任何人都可以指出我如何在ASP.NET Core中执行此操作或帮助我开始这个?

编辑:回答 我最终使用这个答案:https://stackoverflow.com/a/33217340/373655

Ste*_*ger 50

注意/更新:

下面的代码是针对.NET Core 1.1的,
因为.NET Core 1非常RTM,身份验证随着从.NET Core 1跳转到2.0(也就是[部分?]修复了突破性更改而改变).
这就是为什么波纹管代码不再适用于.NET Core 2.0的原因.
但它仍然是一个有用的阅读.

2018年更新

同时,您可以在我的github测试存储库中找到ASP.NET Core 2.0 JWT-Cookie-Authentication的工作示例.配备了BouncyCastle的MS-RSA和MS-ECDSA抽象类的实现,以及RSA和ECDSA的密钥生成器.


Necromancing.
我深入研究了JWT.以下是我的发现:

您需要添加Microsoft.AspNetCore.Authentication.JwtBearer

然后你可以设置

app.UseJwtBearerAuthentication(bearerOptions);
Run Code Online (Sandbox Code Playgroud)

在Startup.cs => Configure中

其中bearerOptions由您定义,例如as

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

// Optional 
// bearerOptions.SecurityTokenValidators.Clear();
// bearerOptions.SecurityTokenValidators.Add(new MyTokenHandler());
Run Code Online (Sandbox Code Playgroud)

其中CustomBearerEvents是您可以将标记数据添加到httpContext/Route的位置

// 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

并且tokenValidationParameters由您定义,例如

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, 
};
Run Code Online (Sandbox Code Playgroud)

如果您想自定义令牌验证,可以选择MyTokenHandler,例如

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


}
Run Code Online (Sandbox Code Playgroud)

棘手的部分是如何获取AsymmetricSecurityKey,因为您不想传递rsaCryptoServiceProvider,因为您需要加密格式的互操作性.

创作顺应着

// 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);
Run Code Online (Sandbox Code Playgroud)

例如,使用DER证书的BouncyCastle:

    // 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;
    }
Run Code Online (Sandbox Code Playgroud)

随后,您可以添加包含JWT-Bearer的自定义cookie格式:

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);
    //}
    //),
});
Run Code Online (Sandbox Code Playgroud)

CustomJwtDataFormat就是这样的

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


}
Run Code Online (Sandbox Code Playgroud)

您还可以使用Microsoft.IdentityModel.Token创建JWT令牌:

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



    }

}
Run Code Online (Sandbox Code Playgroud)

请注意,因为您可以在cookie和http-headers(Bearer)中指定其他用户,或者您指定的任何其他身份验证方法,实际上您可以拥有多个用户!


看看这个:https:
//stormpath.com/blog/token-authentication-asp-net-core

它应该是你正在寻找的.

还有这两个:

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

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

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

而JWT-Bearer来源 https://github.com/aspnet/Security/tree/master/src/Microsoft.AspNetCore.Authentication.JwtBearer


If you need ultra-high security, you should protect against replay-attacks by renewing the ticket on each request, and invalidate old tickets after a certain timeout, and after user logout (not just after validity expiration).


For those of you who end up from here via google, you can implement a TicketDataFormat in cookie-authentication when you want to use your own version of JWT.

I had to look into JWT for work, because we needed to secure our application.
Because I still had to use .NET 2.0, I had to write my own library.

I've ported the result of that to .NET Core this weekend. You find it here: https://github.com/ststeiger/Jwt_Net20/tree/master/CoreJWT

It doesn't use any database, that's not the job of a JWT libary.
Getting and setting DB data is your job.
The library allows for JWT authorization and verification in .NET Core with all algorithms specified in the JWT RFC listed on the IANA JOSE assignment.
As for adding authorization to the pipeline and adding values to route - these are two things which should be done separately, and I think you best do that yourselfs.

You can use custom authentication in ASP.NET Core.
Look into the "Security" category of docs on docs.asp.net.

Or you can look into the Cookie Middleware without ASP.NET Identity or into Custom Policy-Based Authorization.

You can also learn more in the auth workshop on github or in the social login section or in this channel 9 video tutorial.
If all else fails, the source code of asp.net security is on github.


The original project for .NET 3.5, which is where my library derives from, is here:
https://github.com/jwt-dotnet/jwt
I removed all references to LINQ + extension methods, because they are not supported in .NET 2.0. If you include either LINQ, or ExtensionAttribute in the sourcecode, then you can't just change the .NET runtime without getting warnings; that's why I have completely removed them.
Also, I've added RSA + ECSD JWS-methods, for that reason the CoreJWT-project depends on BouncyCastle.
If you limit yourselfs to HMAC-SHA256 + HMAC-SHA384 + HMAC-SHA512, you can remove BouncyCastle.

JWE is not (yet) supported.

Usage is just like jwt-dotnet/jwt, except I changed the namespace JWT to CoreJWT.
I also added an internal copy of PetaJSON as serializer, so there is no interference with other people's project's dependencies.

Create a 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);
Run Code Online (Sandbox Code Playgroud)

Verify a 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!");
}
Run Code Online (Sandbox Code Playgroud)

For RSA & ECSA, you'll have to pass the (BouncyCastle) RSA/ECSD private key instead of secretKey.

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


}
Run Code Online (Sandbox Code Playgroud)

For how to generate/export/import RSA/ECSD-keys with BouncyCastle, see the project called "BouncyCastleTests" in the same repository. I leave it to you to safely store and retrieve your own RSA/ECSD private keys.

I've verified my library's results for HMAC-ShaXXX and RSA-XXX with JWT.io - it looks like they are OK.
ECSD should be OK, too, but I didn't test it against anything.
I did not run extensive tests anyway, FYI.

  • 谢谢你的描述性答案! (3认同)
  • 正是这样的代码让我明白为什么人们喜欢使用 Node.js。我是 .NET 的粉丝。:-\ (2认同)
  • 这一切都非常复杂,我为此而苦苦挣扎。显然不成熟,恕我直言。让我想起了 Windows 3 hello world 应用程序 http://www.charlespetzold.com/blog/2014/12/The-Inknown-Windows-Hello-World-Program.html (2认同)

Sea*_*ean 13

我到目前为止找到的最简单的选项是OpenIddict.你说你想要避免使用Entity Framework和OpenIddict - 那么你将自己做很多编码,有效地重写OpenIddict和ASOS(OpenIddict使用的)部分来做他们正在做的事情.

如果你没有使用OpenIddict,这几乎就是你需要的所有配置,如下所示.这很简单.

如果您不想使用EF,则可以使用OpenIddict.我不知道怎么样,但你必须要弄明白.

ConfigureServices:

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

配置

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/";
});
Run Code Online (Sandbox Code Playgroud)

还有一两个其他小问题,例如你的DbContext需要派生出来OpenIddictContext<ApplicationUser, Application, ApplicationRole, string>.

您可以在此博客文章中查看完整的解释(包括指向github repo的链接):http: //capesean.co.za/blog/asp-net-5-jwt-tokens/


Tse*_*eng 9

如果您只需要对外部OAuth/OpenID提供商(例如Google,GitHub,Facebook,Microsoft帐户等)进行身份验证,那么您就不需要任何第三方工具.

最常用的OAuth和OpenID提供程序的身份验证提供程序已在Microsoft.AspNetCore.Authorization.*程序包中提供ASP.NET Core .查看" 安全 "存储库的GitHub存储库中提供的示例

如果您需要创建自己的JWT令牌,那么您需要一个OAuth/OpenID服务器.OpenIddict是一个易于设置的授权服务器.为此,您需要某种形式的数据库,因为外部提供程序将用于对此人进行身份验证,但您还需要他们在您的授权服务器上拥有一个帐户.

如果您需要更多的自定义和更多的流控制,您必须使用ASOS或IdentityServer4(目前仅在完全使用.NET Framework或Mono时支持ASP.NET Core.据我所知,目前还不支持Core运行时.

https://gitter.im/openiddict/corehttps://gitter.im/aspnet-contrib/AspNet.Security.OpenIdConnect.Server for ASOS上还有一个用于OpenIddict的Gitter聊天室 .