0
点赞
收藏
分享

微信扫一扫

.NET JWT入坑

吓死我了_1799 04-13 10:00 阅读 1
.net后端

前言

JWT (JSON Web Token) 是一种安全传输信息的开放标准,由Header、Payload和Signature三部分组成。它主要用于身份验证、信息交换和授权。JWT可验证用户身份,确保访问权限,实现单点登录,并在客户端和服务器之间安全地交换信息。因其简单、安全和便捷,JWT在现代Web应用中广泛使用。

用JWT有多个原因:

  1. 无状态的身份验证:JWT允许服务器无需保存用户的会话信息,因为所有必要的信息都存储在令牌本身中。这降低了服务器的存储需求,并提高了系统的可扩展性。

  2. 跨域身份验证:由于JWT是自我包含的,并且可以被轻松传递,因此它非常适合跨域身份验证。用户可以在一个服务上验证身份,然后使用相同的令牌访问另一个服务,从而实现单点登录(SSO)。

  3. 安全性:JWT可以通过使用强大的加密算法(如HS256, RS256等)进行签名,以确保其完整性和真实性。服务器可以使用公钥验证令牌的签名,从而确保它没有被篡改,并且确实是由受信任的颁发者签发的。

  4. 减少数据库查询:由于用户的身份信息都存储在JWT中,服务器无需每次都去数据库中查询用户的身份信息,从而减少了数据库的压力和查询时间。

  5. 可定制性:JWT的Payload部分可以包含自定义的信息,如用户角色、权限等,这使得JWT非常灵活,并可以根据具体需求进行定制。

  6. 易于分发和共享:JWT可以轻松地通过网络传输,并且可以在多个服务和客户端之间共享,这使得它在微服务架构和分布式系统中非常有用。

  7. 标准化和互操作性:JWT是一个开放标准(RFC 7519),这意味着不同的系统和语言都可以使用相同的方式生成和验证JWT,从而提高了系统的互操作性。

环境 Win10  VS2022  .NET8 

✨ 建立项目jwttest

1.创建TestJwtController

2.下载JWT 

3.建实体类

/// <summary>
/// 用户信息类
/// </summary>
public class LoginRs
{
    /// <summary>
    /// 用户ID
    /// </summary>
    public string UserId { get; set; }
   /// <summary>
   /// 用户密码
   /// </summary>
    public string PasswordMD5 { get; set; }
}
/// <summary>
/// 用户登录信息类
/// </summary>
public class LoginInfo
{
    /// <summary>
    /// 用户信息
    /// </summary>
    public string UserId { get; set; }
    /// <summary>
    /// 检验时间
    /// </summary>
    public DateTime Expires { get; set; }
}
/// <summary>
/// rsmodel
/// </summary>
public class RsModel
{
    /// <summary>
    /// 是否成功
    /// </summary>
    public bool isOk { get; set; }
    /// <summary>
    /// 返回值
    /// </summary>
    public int code { get; set; }
    /// <summary>
    /// 返回消息
    /// </summary>
    public string msg { get; set; }
    /// <summary>
    /// 返回数据  
    /// </summary>
    public object rsData { get; set; }


}

4.添加post login

      // POST api/<ValuesController>
      [HttpPost]
      public string Login([FromBody] LoginRs loginRequest)
      {
          if (loginRequest == null) return JsonConvert.SerializeObject(new RsModel() { code = 0, isOk = false, msg = "登录信息为空!" });

          #region  判断userid pwd

          if (loginRequest.UserId != "admin" || loginRequest.PasswordMD5 != "admin")
          {
              return JsonConvert.SerializeObject(new RsModel() { code = 0, isOk = false, msg = "用户名和密码不正确!" });
          }
          #endregion
          LoginInfo Info = new LoginInfo()
          {
              UserId = loginRequest.UserId,
              Expires = DateTime.Now.AddDays(1)
          };
          const string secretKey = "myseckey";//口令加密秘钥
          byte[] key = Encoding.UTF8.GetBytes(secretKey);
          IJwtAlgorithm algorithm = new HMACSHA256Algorithm();//加密方式
          IJsonSerializer serializer = new JsonNetSerializer();//序列化Json
          IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();//base64加解密
          IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);//JWT编码
          var token = encoder.Encode(Info, key);//生成令牌

          return JsonConvert.SerializeObject(new RsModel() { code = 1, isOk = true, rsData = token, msg = "登录成功!" });
      }

5.登录验证

这里使用swagger方便检验    👉    .NET MVC API Swagger入坑

6.测试没问题,写个JwtHelper

 public static class JwtHelper
 {

     private static readonly string JwtKey = "mysecret";
     /// <summary>
     /// 获取加密解密
     /// </summary>
     /// <returns></returns>
     private static IJwtEncoder GetEncoder()
     {
         IJwtAlgorithm algorithm = new HMACSHA256Algorithm();//加密方式
         IJsonSerializer serializer = new JsonNetSerializer();//序列化Json
         IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();//base64加解密
         IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);//JWT编码
         return encoder;
     }

     /// <summary>
     /// 获取解密密钥
     /// </summary>
     /// <returns></returns>
     private static IJwtDecoder GetDecoder()
     {
         IJsonSerializer serializer = new JsonNetSerializer();
         IDateTimeProvider provider = new UtcDateTimeProvider();
         IJwtValidator validator = new JwtValidator(serializer, provider);
         IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
         IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
         IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
         return decoder;
     }

     /// <summary>
     /// 加密
     /// </summary>
     public static string Encode(object payload)
     {
         var encoder = GetEncoder();
         var token = encoder.Encode(payload, JwtKey);
         return token;
     }

     /// <summary>
     /// 解密
     /// </summary>
     public static T Decode<T>(string token)
     {
         var decoder = GetDecoder();
         var data = decoder.Decode(token, JwtKey);
         var res = JsonConvert.DeserializeObject<T>(data);
         return res;
     }

     /// <summary>
     /// 解密,只返回Json文本
     /// </summary>
     /// <param name="token"></param>
     /// <returns></returns>
     public static string Decode(string token)
     {

         var decoder = GetDecoder();
         var data = decoder.Decode(token, JwtKey);
         return data;
     }

 }

把中间的加密算法替换成helper的Encode

   var token = JwtHelper.Encode(Info);

7.添加token加密类

调用Decode方法 解密token

8.测试JWT

{"isOk":true,"code":1,"msg":"登录成功!","rsData":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJVc2VySWQiOiJhZG1pbiIsIkV4cGlyZXMiOiIyMDI0LTA0LTEwVDAxOjUxOjUwLjk5NDgxNzQrMDA6MDAifQ.eYJovquJFezVhfdLp-Hro2vnMoQsUwgXLkYcZSYEy7U"}

测试解密

解密成功

⭐️JwtBearer

9、添加NuGet包Microsoft.AspNetCore.Authentication.JwtBearer

10、在appsettings.json中添加JWT配置节点

  "JWT": {
    "SecKey": "im6666666!#@$%@%^^&*(~Czmjklneafguvioszb%yuv&*6WVDf5dw#5dfw6f5w6faW%FW^f5wa65f^AWf56", //密钥
    "Issuer": "im666", //发行者
    "ExpireSeconds": 7200 //过期时间 2h
  },

11.添加jwt类


    using Microsoft.IdentityModel.Tokens;
    using System.Diagnostics;
    using System.IdentityModel.Tokens.Jwt;
    using System.Security.Claims;
    using System.Text;

namespace webapijwttest.Models
{
    /// <summary>
    /// 授权JWT类
    /// </summary>
    public class JwtHelper2
        {
            private readonly IConfiguration _configuration;
            /// <summary>
            /// Token配置
            /// </summary>
            /// <param name="configuration"></param>
            public JwtHelper2(IConfiguration configuration)
            {
                _configuration = configuration;
            }
            /// <summary>
            /// 创建Token 这里面可以保存自己想要的信息
            /// </summary>
            /// <param name="username"></param>
            /// <param name="mobile"></param>
            /// <returns></returns>
            public string CreateToken(string username, string mobile)
            {
                try
                {
                    // 1. 定义需要使用到的Claims
                    var claims = new[]
                    {
                    new Claim("username", username),
                    new Claim("mobile", mobile),
                    /* 可以保存自己想要信息,传参进来即可
                    new Claim("sex", "sex"),
                    new Claim("limit", "limit"),
                    new Claim("head_url", "xxxxx")
                    */
                };
                    // 2. 从 appsettings.json 中读取SecretKey
                    var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecKey"]));
                    // 3. 选择加密算法
                    var algorithm = SecurityAlgorithms.HmacSha256;
                    // 4. 生成Credentials
                    var signingCredentials = new SigningCredentials(secretKey, algorithm);
                    // 5. 根据以上,生成token
                    var jwtSecurityToken = new JwtSecurityToken(
                        _configuration["Jwt:Issuer"],    //Issuer
                        _configuration["Jwt:ExpireSeconds"],  //ExpireSeconds
                        claims,                          //Claims,
                        DateTime.Now,                    //notBefore
                        DateTime.Now.AddSeconds(30),     //expires
                        signingCredentials               //Credentials
                    );
                    // 6. 将token变为string
                    var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
                    return token;
                }
                catch (Exception)
                {
                    throw;
                }
            }
            /// <summary>
            /// 获取信息
            /// </summary>
            /// <param name="jwt"></param>
            /// <returns></returns>
            public static string ReaderToken(string jwt)
            {
                var str = string.Empty;
                try
                {
                    //获取Token的三种方式
                    //第一种直接用JwtSecurityTokenHandler提供的read方法
                    var jwtHander = new JwtSecurityTokenHandler();
                    JwtSecurityToken jwtSecurityToken = jwtHander.ReadJwtToken(jwt);
                    str = jwtSecurityToken.ToString();
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
                return str;
            }
            /// <summary>
            /// 解密jwt
            /// </summary>
            /// <param name="jwt"></param>
            /// <returns></returns>
            public string JwtDecrypt(string jwt)
            {
                StringBuilder sb = new StringBuilder();
                try
                {
                    JwtSecurityTokenHandler tokenHandler = new();
                    TokenValidationParameters valParam = new();
                    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:SecKey"]));
                    valParam.IssuerSigningKey = securityKey;
                    valParam.ValidateIssuer = false;
                    valParam.ValidateAudience = false;
                    //解密
                    ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(jwt,
                            valParam, out SecurityToken secToken);
                    foreach (var claim in claimsPrincipal.Claims)
                    {
                        sb.Append($"{claim.Type}={claim.Value}");
                    }
                }
                catch (Exception ex)
                {
                    Debug.WriteLine(ex.Message);
                }
                return sb.ToString();
            }
        }
}

12.Program.cs注册JWT服务

#region JWT服务
// 注册JWT服务
builder.Services.AddSingleton(new JwtHelper2(builder.Configuration));
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
    options.TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateIssuer = true, //是否验证Issuer
        ValidIssuer = builder.Configuration["Jwt:Issuer"], //发行人Issuer
        ValidateAudience = false, //是否验证Audience      
        ValidateIssuerSigningKey = true, //是否验证SecurityKey
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:SecKey"])), //SecurityKey
        ValidateLifetime = true, //是否验证失效时间
        ClockSkew = TimeSpan.FromSeconds(30), //过期时间容错值,解决服务器端时间不同步问题(秒)
        RequireExpirationTime = true,
    };
}
);
#endregion

添加swagger authorization


builder.Services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "Web API", Version = "v1" });
    //开启注释
    var xmlFile = $"{Assembly.GetEntryAssembly().GetName().Name}.xml";
    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);//需要 生成 目录生成XML
    c.IncludeXmlComments(xmlPath, true);
    // 配置 JWT Bearer 授权
    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Description = "JWT Authorization header using the Bearer scheme",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.Http,
        Scheme = "bearer"
    });
    var securityScheme = new OpenApiSecurityScheme
    {
        Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Bearer" }
    };
    var securityRequirement = new OpenApiSecurityRequirement { { securityScheme, new string[] { } } };
    c.AddSecurityRequirement(securityRequirement);




});


var app = builder.Build();


//启用验证中间件
app.UseAuthentication();
app.UseAuthorization();

13.添加jwt测试api

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity.Data;
using Microsoft.AspNetCore.Mvc;
using webapijwttest.Models;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace webapijwttest.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class Jwt2Controller : ControllerBase
    {
        private readonly JwtHelper2 _jwt;
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="jwtHelper"></param>
        public Jwt2Controller(JwtHelper2 jwtHelper)
        {
            _jwt = jwtHelper;
        }
        /// <summary>
        /// 获取Token
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        public IActionResult GetToken(LoginRs user)
        {
            //参数验证等等....
            if (string.IsNullOrEmpty(user.UserId))
            {
                return Ok("参数异常!");
            }
            //这里可以连接mysql数据库做账号密码验证
            //这里可以做Redis缓存验证等等
            //这里获取Token,当然,这里也可以选择传结构体过去
            var token = _jwt.CreateToken(user.UserId, user.PasswordMD5);
            //解密后的Token
            var PWToken = _jwt.JwtDecrypt(token);
            return Ok(token + "解密后:" + PWToken);
        }
        /// <summary>
        /// 获取自己的详细信息,其中 [Authorize] 就表示要带Token才行
        /// </summary>
        /// <returns></returns>
        [HttpPost]
        [Authorize]
        public IActionResult GetSelfInfo()
        {
            //执行到这里,就表示已经验证授权通过了
            /*
             * 这里返回个人信息有两种方式
             * 第一种:从Header中的Token信息反向解析出用户账号,再从数据库中查找返回
             * 第二种:从Header中的Token信息反向解析出用户账号信息直接返回,当然,在前面创建        Token时,要保存进使用到的Claims中。
            */
            return Ok("授权通过了!");
        }
    }
}

调用

检测控制器

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using webapijwttest.Models;

// For more information on enabling Web API for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860

namespace webapijwttest.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AuthController : ControllerBase
    {
        private ILogger<AuthController> _logger = null;
        private JwtHelper2 _iJWTService = null;
        private readonly IConfiguration _configuration;

        public AuthController(ILogger<AuthController> logger, JwtHelper2 jWTService, IConfiguration configuration)
        {
            this._logger = logger;
            _iJWTService = jWTService;
            _configuration = configuration;
        }

        [Route("Get")]
        [HttpGet]
        public IEnumerable<int> Get()
        {//未加授权认证
            return new List<int>() { 1, 3, 5, 7, 9 };
        }

        [Route("GetData")]
        [HttpGet]
        [Authorize]
        public List<object> GetData()
        {//添加了授权认证,需要使用token
            return new List<object>() { new { userName = "123", remark = "1234" } };
        }

        [Route("Login")]
        [HttpGet]
        public string Login(string name, string password)
        {
            if (!string.IsNullOrEmpty(name) && !string.IsNullOrEmpty(password))
            {
                string token = this._iJWTService.CreateToken(name,password);
                return JsonConvert.SerializeObject(new { result = true, token });
            }
            else
            {
                return JsonConvert.SerializeObject(new { result = false, token = "" });
            }
        }


    }
}

调用

把token放进 

测试GetData

当超过时间调用则GetData失败

END🐟🐟🐟

举报

相关推荐

0 条评论