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

C# ASP.NET Core 1.0 Web API中的简单JWT身份验证,c#,asp.net,authentication,asp.net-web-api,asp.net-core,C#,Asp.net,Authentication,Asp.net Web Api,Asp.net Core,我正在寻找一种最简单的方法来设置一个Web API服务器,该服务器在ASP.NET核心(也称为ASP.NET 5)中使用JWTs进行身份验证。这个项目(/)完全符合我的要求,但它使用ASP.NET 4 我只想能够: 设置可以创建JWT令牌并在标头中返回它的登录路由。我正在将其与现有的RESTful服务集成,该服务将告诉我用户名和密码是否有效。在ASP.NET4项目中,我看到可以通过以下途径来实现 拦截对需要授权的路由的传入请求,解密和验证来自报头的JWT令牌,并使路由可以访问JWT令牌有效负载中

我正在寻找一种最简单的方法来设置一个Web API服务器,该服务器在ASP.NET核心(也称为ASP.NET 5)中使用JWTs进行身份验证。这个项目(/)完全符合我的要求,但它使用ASP.NET 4

我只想能够:

  • 设置可以创建JWT令牌并在标头中返回它的登录路由。我正在将其与现有的RESTful服务集成,该服务将告诉我用户名和密码是否有效。在ASP.NET4项目中,我看到可以通过以下途径来实现

  • 拦截对需要授权的路由的传入请求,解密和验证来自报头的JWT令牌,并使路由可以访问JWT令牌有效负载中的用户信息。e、 g.类似这样的情况:

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

    有人能给我举一个如何在ASP.NET Core中实现这一点的例子,或者帮助我开始使用它吗

    编辑:回答
    我最后用了这个答案:

    到目前为止,我找到的最简单的选择是。你说你想避免实体框架和OpenIddict,然后你将自己编写大量代码,有效地重写OpenIddict和OpenIddict(OpenIddict使用的)的部分内容来完成它们正在做的事情

    如果您可以使用OpenIddict,下面就是您需要的所有配置。这很简单

    如果您不想使用EF,那么使用OpenIddict是可能的。我不知道怎么做,但这是你必须弄清楚的一点

    配置服务:

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

    还有一件或两件小事,比如DbContext需要从OpenIddictContext派生,如果您只需要针对外部OAuth/OpenID提供商(如Google、GitHub、Facebook、Microsoft帐户等)进行身份验证,那么您不需要任何第三方工具

    最常用的OAuth和OpenID提供程序的身份验证提供程序已经在
    Microsoft.AspNetCore.Authorization.*
    包中提供了ASP.NET核心。请查看“”存储库的GitHub存储库中提供的示例

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

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


    还有一个Gitter聊天室,用于在和为ASOS提供OpenIddict。

    注意/更新:

    下面的代码是针对.NET Core 1.1的
    由于.NET Core 1非常适合RTM,身份验证随着从.NET Core 1到2.0的跳转而改变(aka[部分地?]修复了中断更改)。
    这就是为什么下面的代码不再适用于.NET Core 2.0。
    但它仍然是一本有用的书

    2018年更新 同时,您可以找到ASP.NET Core 2.0 JWT Cookie身份验证的工作示例。 带有BouncyCastle的MS-RSA和MS-ECDSA抽象类的实现,以及RSA和ECDSA的密钥生成器


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

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

    然后你可以设置

    app.UseJwtBearerAuthentication(bearerOptions);
    
    在Startup.cs=>Configure中

    其中BearOptions由您定义,例如

    var bearerOptions = new JwtBearerOptions()
    {
        AutomaticAuthenticate = true,
        AutomaticChallenge = true,
        TokenValidationParameters = tokenValidationParameters,
        Events = new CustomBearerEvents()
    };
    
    // Optional 
    // bearerOptions.SecurityTokenValidators.Clear();
    // bearerOptions.SecurityTokenValidators.Add(new MyTokenHandler());
    
    其中CustomBeareEvents是可以向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);
        }
    }
    
    如果您想要自定义令牌验证,则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();
        }
    
    
    }
    
    e、 g.使用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承载的自定义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");
        }
    
    
    }
    
    对于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密钥,请参阅同一存储库中名为“BouncyCastleTests”的项目。我让您安全地存储和检索自己的RSA/ECSD私钥

    我已经用JWT.io验证了我的库对HMAC SHAXX和RSA-XXX的结果-看起来它们还可以。
    ECSD也应该可以,但我没有对它进行任何测试。

    无论如何,我没有运行广泛的测试,仅供参考。

    有一个完整的ASP.NET Core+JWT Auth+SQL Server+Swagger示例:


    希望这能对您有所帮助。

    使用基于标准JWT承载令牌的身份验证来保护ASP.NET Core 2.0 Web API

    &按如下方式应用授权筛选器

     [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    

    这是一个包裹

    • 将JWT承载令牌安全性集成到您的Asp Net Core 2.0+应用程序中变得轻而易举
    • Azure Active Directory身份验证集成
    • Facebook身份验证集成
    • 还有,大摇大摆的UI集成
    它被称为AspNetCore.Security.Jwt

    GitHub:

    该软件包将JWT承载令牌集成到您的应用程序中,如下所示:

    1.在应用程序中实现IAAuthentication接口 然后,您将自动获取端点:

    /代币

    /脸谱网

    当您调用这些端点并成功进行身份验证时,您将获得一个JWT承载令牌

    在要保护的控制器中 必须使用Authorize属性标记要保护的控制器或操作,如:

        using Microsoft.AspNetCore.Mvc;
        .
        .
        .
    
        namespace XXX.API.Controllers
        {
            using Microsoft.AspNetCore.Authorization;
    
            [Authorize]
            [Route("api/[controller]")]
            public class XXXController : Controller
            {
                .
                .
                .
            }
        }
    
    在Swagger UI中,您将自动看到这些端点


    谢谢您的回复。我会给您
    // 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)
            };
    
    
    
        }
    
    }
    
    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);
    
    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!");
    }
    
    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;
            }
        }
    
    
    }
    
     [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    
    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;
            }
        }
    }
    
    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();
    }
    
     {
         "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
        },
        .
        .
        .
    }
    
        using Microsoft.AspNetCore.Mvc;
        .
        .
        .
    
        namespace XXX.API.Controllers
        {
            using Microsoft.AspNetCore.Authorization;
    
            [Authorize]
            [Route("api/[controller]")]
            public class XXXController : Controller
            {
                .
                .
                .
            }
        }