草庐IT

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

coder 2023-07-08 原文

我正在寻找设置 Web API 服务器的最简单方法,该服务器使用 JWT 在 ASP.NET Core(又名 ASP.NET 5)中进行身份验证。这个项目( blog post/github )完全符合我的要求,但它使用 ASP.NET 4。

我只想能够:

  • 设置一个登录路由,该路由可以创建 JWT token 并在 header 中返回它。我正在将此与现有的 RESTful 服务集成,该服务会告诉我用户名和密码是否有效。在 ASP.NET 4 项目中,我认为这可以通过以下路线完成 https://github.com/stewartm83/Jwt-WebApi/blob/master/src/JwtWebApi/Controllers/AccountController.cs#L24-L54
  • 拦截对需要授权的路由的传入请求,解密和验证 header 中的 JWT token ,并使路由可以访问 JWT token 的有效负载中的用户信息。例如像这样: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

    最佳答案

    注意/更新:

    以下代码适用于 .NET Core 1.1
    由于 .NET Core 1 非常 RTM,身份验证随着从 .NET Core 1 到 2.0 的跳跃而改变(也就是[部分?] 修复了重大更改)。
    这就是为什么下面的代码不再适用于 .NET Core 2.0。
    但它仍然是一个有用的阅读。

    2018 更新

    同时,您可以找到 ASP.NET Core 2.0 JWT-Cookie-Authentication on my github test repo 的工作示例.
    随附带有 BouncyCaSTLe 的 MS-RSA&MS-ECDSA 抽象类的实现,以及 RSA&ECDSA 的 key 生成器。

    死灵法术。
    我深入研究了 JWT。以下是我的发现:

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

    然后你可以设置

    app.UseJwtBearerAuthentication(bearerOptions);
    

    在 Startup.cs => 配置

    其中 bearerOptions 由您定义,例如作为
    var bearerOptions = new JwtBearerOptions()
    {
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        TokenValidationParameters = tokenValidationParameters,
        Events = new CustomBearerEvents()
    };
    
    // Optional 
    // bearerOptions.SecurityTokenValidators.Clear();
    // bearerOptions.SecurityTokenValidators.Add(new MyTokenHandler());
    

    其中 CustomBearerEvents 是您可以将 token 数据添加到 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);
        }
    }
    

    并且 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, 
    };
    

    如果您想自定义 token 验证,例如,您可以选择定义 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();
        }
    
    
    }
    

    棘手的部分是如何获取 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);
    

    例如使用来自 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;
        }
    

    随后,您可以添加包含 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);
        //}
        //),
    });
    

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

    您还可以使用 Microsoft.IdentityModel.Token 创建 JWT token :
    // 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)
            };
    
    
    
        }
    
    }
    

    请注意,因为您可以在 cookie 与 http-headers (Bearer) 或您指定的任何其他身份验证方法中提供不同的用户,所以您实际上可以拥有超过 1 个用户!

    看看这个:
    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

    如果您需要超高的安全性,您应该通过在每个请求上更新票证来防止重放攻击,并在一定超时后和用户注销后(不仅仅是在有效期到期后)使旧票证失效。

    对于那些通过谷歌从这里结束的人,当您想使用自己的 JWT 版本时,可以在 cookie 身份验证中实现 TicketDataFormat。

    我不得不考虑 JWT 的工作,因为我们需要保护我们的应用程序。
    因为我仍然必须使用 .NET 2.0,所以我必须编写自己的库。

    本周末我已将结果移植到 .NET Core。
    你可以在这里找到它:
    https://github.com/ststeiger/Jwt_Net20/tree/master/CoreJWT

    它不使用任何数据库,这不是 JWT 库的工作。
    获取和设置 DB 数据是您的工作。
    该库允许在 .NET Core 中使用所有算法进行 JWT 授权和验证 specified in the JWT RFC listed on the IANA JOSE assignment .
    至于向管道添加授权并为路由添加值 - 这是两件应该分开完成的事情,我认为你最好自己做。

    您可以在 ASP.NET Core 中使用自定义身份验证。
    查看 "Security" category of docs on docs.asp.net.

    或者您可以查看 Cookie Middleware without ASP.NET Identity或进入 Custom Policy-Based Authorization .

    您还可以在 auth workshop on github 中了解更多信息或在 social login部分或在 this channel 9 video tutorial .
    如果一切都失败了,asp.net security的源代码是on github .

    .NET 3.5 的原始项目,这是我的库的来源,在这里:
    https://github.com/jwt-dotnet/jwt
    我删除了对 LINQ + 扩展方法的所有引用,因为 .NET 2.0 不支持它们。如果您在源代码中包含 LINQ 或 ExtensionAttribute,那么您不能在没有收到警告的情况下更改 .NET 运行时;这就是我完全删除它们的原因。
    另外,我添加了 RSA + ECSD JWS 方法,因此 CoreJWT 项目依赖于 BouncyCaSTLe。
    如果您将自己限制为 HMAC-SHA256 + HMAC-SHA384 + HMAC-SHA512,则可以删除 BouncyCaSTLe。

    JWE(尚)不受支持。

    用法就像 jwt-dotnet/jwt, 除了我将命名空间 JWT 更改为 CoreJWT .
    我还添加了 PetaJSON 的内部副本作为序列化程序,因此不会干扰其他人项目的依赖项。

    创建一个 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);
    

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

    对于 RSA 和 ECSA,您必须传递 (BouncyCaSTLe) RSA/ECSD 私钥而不是 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;
            }
        }
    
    
    }
    

    有关如何使用 BouncyCaSTLe 生成/导出/导入 RSA/ECSD key ,请参阅同一存储库中名为“BouncyCaSTLeTests”的项目。我把它留给你来安全地存储和检索你自己的 RSA/ECSD 私钥。

    我已经使用 JWT.io 验证了我的库的 HMAC-ShaXXX 和 RSA-XXX 结果 - 看起来它们没问题。
    ECSD 也应该没问题,但我没有针对任何东西对其进行测试。
    无论如何,我没有进行广泛的测试,仅供引用。

    关于c# - ASP.NET Core 1.0 Web API 中的简单 JWT 身份验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35307143/

    有关c# - ASP.NET Core 1.0 Web API 中的简单 JWT 身份验证的更多相关文章

    1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

      总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

    2. ruby - 其他文件中的 Rake 任务 - 2

      我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

    3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

      作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

    4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

      Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

    5. ruby - 具有身份验证的私有(private) Ruby Gem 服务器 - 2

      我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..

    6. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

      我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

    7. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

      我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

    8. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

      刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

    9. ruby-on-rails - form_for 中不在模型中的自定义字段 - 2

      我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢

    10. ruby - rspec 需要 .rspec 文件中的 spec_helper - 2

      我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只

    随机推荐