JWT认证(System.IdentityModel.Tokens.Jwt)

用到的命名空间

using Microsoft.AspNetCore.Authentication.JwtBearer;

using Microsoft.IdentityModel.Tokens;

using System.IdentityModel.Tokens.Jwt;

using System.Security.Claims;

生成TOKEN方法

[HttpGet("auth")]
public IActionResult Get(Tmodel mod)
{
    if (mod.user == "AngelaDaddy" && mod.pass == "123456")
    {
        // push the user’s name into a claim, so we can identify the user later on.
        var claims = new[]
        {
            new Claim(ClaimTypes.Name, mod.user),
            new Claim(ClaimTypes.Role, "useradmin"),
            new Claim(ClaimTypes.SerialNumber, "123123123"),
            new Claim(ClaimTypes.Role, "useradmin1"),
            new Claim(ClaimTypes.Role, "useradmin2"),
            new Claim(ClaimTypes.Role, "useradmin3"),
            new Claim(ClaimTypes.Name, mod.user + "1"),
            new Claim(ClaimTypes.Name, mod.user + "2"),
            new Claim(ClaimTypes.Name, mod.user + "3")

       };
        //sign the token using a secret key.This secret will be shared between your API and anything that needs to check that the token is legit.
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["SecurityKey"]));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        //.NET Core’s JwtSecurityToken class takes on the heavy lifting and actually creates the token.
        /**
         * Claims (Payload)
            Claims 部分包含了一些跟这个 token 有关的重要信息。 JWT 标准规定了一些字段,下面节选一些字段:

            iss: The issuer of the token,token 是给谁的  发送者
            audience: 接收的
            sub: The subject of the token,token 主题
            exp: Expiration Time。 token 过期时间,Unix 时间戳格式
            iat: Issued At。 token 创建时间, Unix 时间戳格式
            jti: JWT ID。针对当前 token 的唯一标识
            除了规定的字段外,可以包含其他任何 JSON 兼容的字段。
         * */
        var token = new JwtSecurityToken(
            issuer: "jwttest",
            audience: "jwttest",
            claims: claims,
            notBefore: DateTime.UtcNow,
            expires: DateTime.UtcNow.AddSeconds(10),
            signingCredentials: creds);

        return Ok(new
        {
            token = new JwtSecurityTokenHandler().WriteToken(token)
        });
    }

    return BadRequest("用户名密码错误");
}

new Claim时,可以设置失效时间 JwtRegisteredClaimNames.Exp,值为Unix时间戳

认证时需要添加生命周期校验

LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters) => expires > DateTime.UtcNow

var d = securityToken as JwtSecurityToken

var res1 = d.Claims.Where(s => s.Type == ClaimTypes.Role && s.Value == "useradmin2").Count()

生成Token

var token = new JwtSecurityToken(
issuer: "jwttest",
audience: "jwttest",
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.AddSeconds(30),
signingCredentials: creds);

失效时间可以为本地时间或UTC时间

//添加jwt验证:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,//是否验证Issuer
ValidateAudience = true,//是否验证Audience
ValidateLifetime = false,//是否验证失效时间
ValidateIssuerSigningKey = true,//是否验证SecurityKey
ValidAudience = "jwttest",//Audience
ValidIssuer = "jwttest",//Issuer,这两项和前面签发jwt的设置一致
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["SecurityKey"])),//拿到SecurityKey
LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters) => expires > DateTime.UtcNow
//LifetimeValidator = (DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters) =>
//{
// var d = securityToken as JwtSecurityToken;
// var res1 = d.Claims.Where(s => s.Type == ClaimTypes.Role && s.Value == "useradmin2").Count();
// var res2 = d.Claims.Where(s => s.Type == ClaimTypes.Role && s.Value == "useradmin3").Count();
// var res3 = d.Claims.Where(s => s.Type == ClaimTypes.Name && s.Value == "useradmin2").Count();
// var res4 = d.Claims.Where(s => s.Type == ClaimTypes.Role && s.Value == "useradmin8").Count();
// return expires > DateTime.UtcNow;
//}
};
});

生成TOKEN

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using IdentityModel;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;


[HttpGet("token")]
        public ActionResult<string> Token(InputData inputData)
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.UTF8.GetBytes("1111111111");
            var authTime = DateTime.UtcNow;
            var expiresAt = authTime.AddSeconds(3000);
             第一种
            //var token = new JwtSecurityToken(
            //        issuer: "发送者(TokenCreate)",
            //        audience: "接收者(TokenServer)",
            //        claims: new Claim[]
            //        {
            //            new Claim("uname", inputData.Username)
            //        },
            //        notBefore: authTime,
            //        expires: expiresAt,
            //        signingCredentials: new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature)
            //    );
            // 第二种
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                    new Claim(JwtClaimTypes.Audience,"Client2"),
                    //new Claim(JwtClaimTypes.Issuer,"发送者(TokenCreate)"),
                    //new Claim("uname", inputData.Username)
                }),
                Expires = expiresAt,
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            var tokenString = tokenHandler.WriteToken(token);
            return Ok(new
            {
                access_token = tokenString,
                token_type = "Bearer",
                profile = new
                {
                    uname = inputData.Username,
                    upass = inputData.Password,
                    auth_time = new DateTimeOffset(authTime).ToUnixTimeSeconds(),
                    expires_at = new DateTimeOffset(expiresAt).ToUnixTimeSeconds()
                }
            });
        }

注册TOKEN

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using IdentityModel;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;

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

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(o =>
            {
                o.TokenValidationParameters = new TokenValidationParameters
                {
                    //NameClaimType = JwtClaimTypes.Name,
                    //RoleClaimType = JwtClaimTypes.Role,

                    ValidIssuer = "发送者(TokenCreate)",
                    ValidAudience = "接收者(TokenServer)",
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("abc123!@#abc123!@#abc123!@#")),

                    RequireExpirationTime = true,
                    ClockSkew = TimeSpan.Zero,
                    ValidateLifetime = true

                    /***********************************TokenValidationParameters的参数默认值***********************************/
                    // RequireSignedTokens = true,
                    // SaveSigninToken = false,
                    // ValidateActor = false,
                    // 将下面两个参数设置为false,可以不验证Issuer和Audience,但是不建议这样做。
                    // ValidateAudience = true,
                    // ValidateIssuer = true, 
                    // ValidateIssuerSigningKey = false,
                    // 是否要求Token的Claims中必须包含Expires
                    // RequireExpirationTime = true,
                    // 允许的服务器时间偏移量
                    // ClockSkew = TimeSpan.FromSeconds(300),
                    // 是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
                    // ValidateLifetime = true
                };
            });
            services.AddAuthorization(options =>
            {
                options.AddPolicy("Author", policy =>
                {
                    policy.RequireClaim("uname");
                });
            });
            services.AddControllers();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthentication();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}

WebApi使用JWT认证(二)

这是第二部:实现NetCore上的WebApi使用JWT认证

1、NetCore新建一个WebApi的项目
在这里插入图片描述
2、打开AppSettings.json,添加Jwt的信息,这里为了演示而已

{
  "Logging": {
    "IncludeScopes": false,
    "Debug": {
      "LogLevel": {
        "Default": "Warning"
      }
    },
    "Console": {
      "LogLevel": {
        "Default": "Warning"
      }
    }
  },
  "JwtSettings": {
    "Issuer": "XXX",
    "Audience": "XXXX",
    "SecretKey": "To live is to change the world!"
  }
}

3、Models下新建两个类,一个用于登录,一个用于获取配置文件中的值

namespace NerCoreJwt.Models
{
    public class LoginViewModel
    {
        public string UserName { get; set; } = "wangshibang";

        public string Password { get; set; } = "123456";
    }
}
namespace NerCoreJwt.Models
{
    public class JwtSettings
    {
        /// <summary>
        /// 证书颁发者
        /// </summary>
        public string Issuer { get; set; }

        /// <summary>
        /// 允许使用的角色
        /// </summary>
        public string Audience { get; set; }

        /// <summary>
        /// 加密字符串
        /// </summary>
        public string SecretKey { get; set; }
    }

}

4、新建一个Controller,用来写登录后生成Token逻辑

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using NerCoreJwt.Models;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace NerCoreJwt.Controllers
{
    [Route("api/[controller]/[action]")]
    public class AuthorizeController : Controller
    {
        private JwtSettings setting;
        public AuthorizeController(IOptions<JwtSettings> options)
        {
            setting = options.Value;
        }

        [HttpPost]
        public IActionResult Login(LoginViewModel login)
        {
            if (ModelState.IsValid)
            {
                if (login.UserName == "wangshibang" && login.Password == "123456")
                {
                    var claims = new Claim[] {
                        new Claim(ClaimTypes.Name, login.UserName),
                        new Claim(ClaimTypes.Role, "admin, Manage")
                    };
                    var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(setting.SecretKey));
                    var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                    var token = new JwtSecurityToken(
                        setting.Issuer,
                        setting.Audience,
                        claims,
                        DateTime.Now,
                        DateTime.Now.AddMinutes(30),
                        creds);
                    return Ok(new { Token = new JwtSecurityTokenHandler().WriteToken(token) });
                }
            }
            return BadRequest();
        }

        [HttpGet]
        public IActionResult NoValidate()
        {
            return Ok();
        }
    }
}

5、StartUp类里面添加从Configure<JwtSettings>中获取Section才可以使用IOptions获取里面的内容,为了省事就全部贴出来了

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using NerCoreJwt.Models;
using System.Linq;
using System.Threading.Tasks;

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

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<JwtSettings>(Configuration.GetSection("JwtSettings"));
            JwtSettings setting = new JwtSettings();
            Configuration.Bind("JwtSettings", setting);
            services.AddAuthentication(option =>
            {
                option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(config =>
            {
                /*
                config.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidAudience = setting.Audience,
                    ValidIssuer = setting.Issuer,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(setting.SecretKey))
                };
                */
                config.SecurityTokenValidators.Clear();
                config.SecurityTokenValidators.Add(new MyTokenValidate());
                config.Events = new JwtBearerEvents()
                {
                    OnMessageReceived = context =>
                    {
                        var token = context.Request.Headers["myToken"];
                        context.Token = token.FirstOrDefault();
                        return Task.CompletedTask;
                    }

                };
            });

            services.AddMvc();
        }

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

6、Token生成了,可以用PostMan调用接口试试,把生成的Token粘到jwt.io官网看看里面的信息

下面我们来进行授权

7、为了自定义授权方法,我们需要新建一个类,继承自ISecurityTokenValidator接口

using Microsoft.AspNetCore.Authentication.JwtBearer;
 using Microsoft.IdentityModel.Tokens;
 using System.IdentityModel.Tokens.Jwt;
 using System.Linq;
 using System.Security.Claims;
 
 namespace NerCoreJwt
 {
     public class MyTokenValidate : ISecurityTokenValidator
     {
         public bool CanValidateToken => true;
 
         public int MaximumTokenSizeInBytes { get ; set ; }
 
         public bool CanReadToken(string securityToken)
         {
             return true;
         }
 
         public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
         {
             ClaimsPrincipal principal;
             try
             {
                 validatedToken = null;
                 //这里需要验证生成的Token
                 /*
 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoid2FuZ3NoaWJhbmciLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOiJhZG1pbiwgTWFuYWdlIiwibmJmIjoxNTIyOTI0MDgxLCJleHAiOjE1MjI5MjU4ODEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMCIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTAwMCJ9.fa0jDYt_MqHFcwQfsMS30eCsjEwQt_uiv96bGtMQJBE
                 */
                 var token = new JwtSecurityToken(securityToken);
                 //获取到Token的一切信息
                 var payload = token.Payload;
                 var role = (from t in payload where t.Key == ClaimTypes.Role select t.Value).FirstOrDefault();
                 var name = (from t in payload where t.Key == ClaimTypes.Name select t.Value).FirstOrDefault();
                 var issuer = token.Issuer;
                 var key = token.SecurityKey;
                 var audience = token.Audiences;
                 var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme);
                 identity.AddClaim(new Claim(ClaimTypes.Name, name.ToString()));
                 identity.AddClaim(new Claim(ClaimsIdentity.DefaultRoleClaimType, "admin"));
                 principal = new ClaimsPrincipal(identity);
             }
             catch
             {
                 validatedToken = null;48                 principal = null;
             }
             return principal;
         }
     }
 }

8、然后注释掉上面代码我注册的部分,因为这是原生的Authorize验证特性,添加后面的自定义验证逻辑

9、在接口上面添加Authorize特性,用PostMan调用接口传入生成的Token,设置断点看看效果吧

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

namespace NerCoreJwt.Controllers
{
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        // GET api/values
        [Authorize(Roles = "admin")]
        [HttpGet]
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        [HttpGet("{id}")]
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        [HttpPost]
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        [HttpPut("{id}")]
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        [HttpDelete("{id}")]
        public void Delete(int id)
        {
        }
    }
}

JWT-生成、校验、解析Token(C#)

重要对象

JwtSecurityToken

代表一个jwt token,可以直接用此对象生成token字符串,也可以使用token字符串创建此对象

SecurityToken

JwtSecurityToken的基类,包含基础数据

JwtSecurityTokenHandler

创建、校验token,返回ClaimsPrincipal

CanReadToken():确定字符串是否是格式良好的Json Web令牌(JWT)

ReadJwtToken(string token)token字符串转为JwtSecurityToken对象

ValidateToken(string token、TokenValidationParameters parameter,out SecurityToken validatedToken):校验token,返回ClaimsIdentity

方式1(推荐)

引用NuGet包:System.IdentityModel.Tokens.Jwt

static void Main(string[] args)
        {
            //引用System.IdentityModel.Tokens.Jwt
            DateTime utcNow = DateTime.UtcNow;
            string key = "f47b558d-7654-458c-99f2-13b190ef0199";
            SecurityKey securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(key));

            var claims = new List<Claim>() {
                new Claim("ID","1"),
                new Claim("Name","fan")
            };
            JwtSecurityToken jwtToken = new JwtSecurityToken(
                issuer: "fan",
                audience: "audi~~!",
                claims: claims,
                notBefore: utcNow,
                expires: utcNow.AddYears(1),
                signingCredentials: new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256)
                );

            //生成token方式1
            string token1 = new JwtSecurityTokenHandler().WriteToken(jwtToken);
            //A Microsoft.IdentityModel.Tokens.SecurityTokenDescriptor that contains details of contents of the token.

            var tokenDescriptor = new SecurityTokenDescriptor // 创建一个 Token 的原始对象
            {
                Issuer = "fan",
                Audience = "audi",
                Subject = new ClaimsIdentity(new[]
                       {
                            new Claim(ClaimTypes.Name, "")
                        }),
                Expires = DateTime.Now.AddMinutes(60),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(Encoding.ASCII.GetBytes(key)), SecurityAlgorithms.HmacSha256)
            };
            //生成token方式2
            SecurityToken securityToken = new JwtSecurityTokenHandler().CreateToken(tokenDescriptor);
            var token2 = new JwtSecurityTokenHandler().WriteToken(securityToken);

            //校验token
            var validateParameter = new TokenValidationParameters()
            {
                ValidateLifetime = true,
                ValidateAudience = true,
                ValidateIssuer = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = "fan",
                ValidAudience = "audi~~!",
                IssuerSigningKey = securityKey,
            };
            //不校验,直接解析token
            //jwtToken = new JwtSecurityTokenHandler().ReadJwtToken(token1);
            try
            {
                //校验并解析token
                var claimsPrincipal = new JwtSecurityTokenHandler().ValidateToken(token1, validateParameter, out SecurityToken validatedToken);//validatedToken:解密后的对象
               var jwtPayload = ((JwtSecurityToken)validatedToken).Payload.SerializeToJson(); //获取payload中的数据 
                
            }
            catch (SecurityTokenExpiredException)
            {
                //表示过期
            }
            catch (SecurityTokenException)
            {
                //表示token错误
            }
        }

方式2

引用Nuget包:JWT

       /// <summary>
        /// 创建token
        /// </summary>
        /// <returns></returns>
        public static string CreateJwtToken(IDictionary<string, object> payload, string secret, IDictionary<string, object> extraHeaders = null)
        {
            IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
            IJsonSerializer serializer = new JsonNetSerializer();
            IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
            IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);
            var token = encoder.Encode(payload, secret);
            return token;
        }
        /// <summary>
        /// 校验解析token
        /// </summary>
        /// <returns></returns>
        public static string ValidateJwtToken(string token, string secret)
        {
            try
            {
                IJsonSerializer serializer = new JsonNetSerializer();
                IDateTimeProvider provider = new UtcDateTimeProvider();
                IJwtValidator validator = new JwtValidator(serializer, provider);
                IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
                IJwtAlgorithm alg = new HMACSHA256Algorithm();
                IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, alg);
                var json = decoder.Decode(token, secret, true);
                //校验通过,返回解密后的字符串
                return json;
            }
            catch (TokenExpiredException)
            {
                //表示过期
                return "expired";
            }
            catch (SignatureVerificationException)
            {
                //表示验证不通过
                return "invalid";
            }
            catch (Exception)
            {
                return "error";
            }
        }

//-------------客户端调用---------------
public static void Main(string[] args)
        {
            var sign = "123";
            var extraHeaders = new Dictionary<string, object>
                     {
                                          { "myName", "limaru" },
                    };
            //过期时间(可以不设置,下面表示签名后 10秒过期)
            double exp = (DateTime.UtcNow.AddSeconds(10) - new DateTime(1970, 1, 1)).TotalSeconds;
            var payload = new Dictionary<string, object>
                     {
                                         { "userId", "001" },
                         { "userAccount", "fan" },
                         { "exp",exp }
                                     };
            var token = CreateJwtToken(payload, sign, extraHeaders);
            var text = ValidateJwtToken(token, sign);
            Console.ReadKey();
        }

方式3

手写jwt算法
JWT组成
样式:"xxxxxxxxxxxx.xxxxxxxxxxxxx.xxxxxxxxxxxxxxxx"由三部分组成.
(1).Header头部:{"alg":"HS256","typ":"JWT"}基本组成,也可以自己添加别的内容,然后对最后的内容进行Base64编码.
(2).Payload负载:iss、sub、aud、exp、nbf、iat、jti基本参数,也可以自己添加别的内容,然后对最后的内容进行Base64编码.
(3).Signature签名:将Base64后的HeaderPayload通过.组合起来,然后利用Hmacsha256+密钥进行加密。

#region Base64编码
         /// <summary>
         /// Base64编码
         /// </summary>
         /// <param name="text">待编码的文本字符串</param>
         /// <returns>编码的文本字符串</returns>
         public string Base64UrlEncode(string text)
         {
             var plainTextBytes = Encoding.UTF8.GetBytes(text);
             var base64 = Convert.ToBase64String(plainTextBytes).Replace('+', '-').Replace('/', '_').TrimEnd('=');
             return base64;
         }
         #endregion
 
         #region Base64解码
         /// <summary>
         /// Base64解码
         /// </summary>
         /// <param name="base64UrlStr"></param>
         /// <returns></returns>
 
         public string Base64UrlDecode(string base64UrlStr)
         {
             base64UrlStr = base64UrlStr.Replace('-', '+').Replace('_', '/');
             switch (base64UrlStr.Length % 4)
             {
                 case 2:
                     base64UrlStr += "==";
                     break;
                 case 3:
                     base64UrlStr += "=";
                     break;
             }
             var bytes = Convert.FromBase64String(base64UrlStr);
             return Encoding.UTF8.GetString(bytes);
         }
#endregion Base64编码和解码

/// <summary>
        /// 手写JWT算法
        /// </summary>
        public bool TestJwt1()
        {
            string secretKey = Configuration["SecretKey"];
            //1.加密
            //1.1 表头的处理
            string headerBase64Url = this.Base64UrlEncode("{\"alg\":\"HS256\",\"typ\":\"JWT\"}");
            //1.2 PayLoad的处理
            var jwtPayLoad = new
            {
                expire = DateTime.Now.AddMinutes(15),
                userId = "00000000001",
                userAccount = "admin"
            };
            string payloadBase64Url = this.Base64UrlEncode(JsonConvert.SerializeObject(jwtPayLoad));
            //1.3 Sign的处理
            string sign = $"{headerBase64Url}.{payloadBase64Url}".HMACSHA256(secretKey);
            //1.4 最终的jwt字符串
            string jwtStr = $"{headerBase64Url}.{payloadBase64Url}.{sign}";

            //2.校验token是否正确
            bool result;   //True表示通过,False表示未通过
            //2.1. 获取token中的PayLoad中的值,并做过期校验
            JwtData myData = JsonConvert.DeserializeObject<JwtData>(this.Base64UrlDecode(jwtStr.Split('.')[1]));  //这一步已经获取到了payload中的值,并进行转换了
            var nowTime = DateTime.Now;
            if (nowTime > myData.expire)
            {
                //表示token过期,校验未通过
                result = false;
                return result;
            }
            else
            {
                //2.2 做准确性校验
                var items = jwtStr.Split('.');
                var oldSign = items[2];
                string newSign = $"{items[0]}.{items[1]}".HMACSHA256(secretKey);
                result = oldSign == newSign;  //true表示检验通过,false表示检验未通过
                return result;
            }
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值