首页 > 其他分享 >JWT

JWT

时间:2024-03-21 18:58:52浏览次数:26  
标签:string JWT jwt claims new public

1、JWT定义

JWT(Json Web Token)是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。JWT作为一个开放的标准( RFC 7519 ),定义了一种简洁的,自包含的方法用于通信双方之间以Json对象的形式安全的传递信息。因为数字签名的存在,这些信息是可信的,JWT可以使用HMAC算法或者是RSA的公私秘钥对进行签名。

1.1、JWT结构

JWT由三部分组成,这些部分由点(.)分隔,分别是:Header(头部包含算法信息) .Payload(负载包含实际传递信息).Signature(对前面两部分的签名)

例如:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

 

2、JWT使用

生成JWT
 public static string CreateNewJwt()
{
    var claims = new List<Claim>();
    //添加负载
    claims.Add(new Claim(ClaimTypes.NameIdentifier, "6"));
    claims.Add(new Claim(ClaimTypes.Name, "Panda"));
    claims.Add(new Claim(ClaimTypes.Role, "User"));
    claims.Add(new Claim(ClaimTypes.Role, "Manager"));
    claims.Add(new Claim(ClaimTypes.Role, "Admin"));
    claims.Add(new Claim("SomeCode", "Panda666com"));
    //密钥
    string key = "dkdls()dlfj%sldfj#sdlfnbmlkepkkqaopxd@9094";
    //设置过期时间
    DateTime expires = DateTime.Now.AddDays(1);

    byte[] secBytes = Encoding.UTF8.GetBytes(key);
    var secKey = new SymmetricSecurityKey(secBytes);
    var credentials = new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature);
    var tokenDescriptor = new JwtSecurityToken(claims: claims,
        expires: expires, signingCredentials: credentials);
    //生成jwt字符串
    string jwt = new JwtSecurityTokenHandler().WriteToken(tokenDescriptor);
    return jwt;
}
解码JWT
 //不使用私钥,直接解码
public static string DecodeJwt(string jwtString)
{
    string jwt = jwtString;
    string[] segments = jwt.Split('.');
    string head = JwtDecode(segments[0]);
    string payload = JwtDecode(segments[1]);
    Console.WriteLine("--------head--------");
    Console.WriteLine(head);
    Console.WriteLine("--------payload--------");
    Console.WriteLine(payload);
    string JwtDecode(string s)
    {
        s = s.Replace('-', '+').Replace('_', '/');
        switch (s.Length % 4)
        {
            case 2:
                s += "==";
                break;
            case 3:
                s += "=";
                break;
        }
        var bytes = Convert.FromBase64String(s);
        return Encoding.UTF8.GetString(bytes);
    }

    return "";
}

 由此可见,JWT中payload是明文保存的,不要把不能被客户端知道的信息放到JWT中。

私钥校验JWT并解码
/// <summary>
/// 验证Jwt字符串
/// </summary>
/// <param name="jwtString"></param>
public static Dictionary<string, string> ValidJwt(string jwtString)
{
    Console.WriteLine("校验JWT");
    string secKey = "dkdls()dlfj%sldfj#sdlfnbmlkepkkqaopxd@9094";
    JwtSecurityTokenHandler tokenHandler = new();
    TokenValidationParameters valParam = new();
    var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secKey));
    valParam.IssuerSigningKey = securityKey;
    valParam.ValidateIssuer = false;
    valParam.ValidateAudience = false;

    //返回值
    Dictionary<string, string> result = new Dictionary<string, string>();

    try
    {
        //解析Jwt
        ClaimsPrincipal claimsPrincipal = tokenHandler.ValidateToken(jwtString,
            valParam, out SecurityToken secToken);

        foreach (var claim in claimsPrincipal.Claims)
        {
            result[claim.Type] = claim.Value;
            Console.WriteLine($"{claim.Type}={claim.Value}");
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("failed");
    }
    finally
    {

    }
    return result;
}

测试:

public static void Main(string[] args)
{
    //创建新的Jwt
    string jwtEncodeString = CreateNewJwt();
    Console.WriteLine(jwtEncodeString);

    //读取Jwt
    string jwtDecodeString = DecodeJwt(jwtEncodeString);

    //验证Jwt
    Dictionary<string, string> result = ValidJwt(jwtEncodeString);  
}
结果
 eyJhbGciOiJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNobWFjLXNoYTI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjYiLCJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1lIjoiUGFuZGEiLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW1zL3JvbGUiOlsiVXNlciIsIk1hbmFnZXIiLCJBZG1pbiJdLCJTb21lQ29kZSI6IlBhbmRhNjY2Y29tIiwiZXhwIjoxNzExMDEwNzE4fQ.qpJWz8aEefmUycBYb1qlQz5GBuU5wARNJ-FHvHF6abA
--------head--------
{"alg":"http://www.w3.org/2001/04/xmldsig-more#hmac-sha256","typ":"JWT"}
--------payload--------
{"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier":"6","http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name":"Panda","http://schemas.microsoft.com/ws/2008/06/identity/claims/role":["User","Manager","Admin"],"SomeCode":"Panda666com","exp":1711010718}
校验JWT
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier=6
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name=Panda
http://schemas.microsoft.com/ws/2008/06/identity/claims/role=User
http://schemas.microsoft.com/ws/2008/06/identity/claims/role=Manager
http://schemas.microsoft.com/ws/2008/06/identity/claims/role=Admin
SomeCode=Panda666com
exp=1711010718

注意:

  • 生成jwt时候的key必须在16位以上,否则会因为长度不够抛出异常。
  • jwt本身是不加密的,里面包含的信息任何人都可以读取到。
  • jwt的签名部分是对前两部分的签名,防止数据被篡改。

 

3、.Net Core JWT 授权

1、Nuget 安装 Microsoft.AspNetCore.Authentication.JwtBearer

2、在appsettings.json中配置JWT 参数,如下:

"JwtConfig": {
  "SecretKey": "d0ecd23c-dfdb-4005-a2ea-0fea210c858a", // 密钥   可以是guid 也可以是随便一个字符串
  "Issuer": "zhangsan", // 颁发者
  "Audience": "zhangsan", // 接收者
  "Expired": 30 // 过期时间(30min)
}
JwtConfig
 /// <summary>
/// jwt配置
/// </summary>
public class JwtConfig : IOptions<JwtConfig>
{
    public JwtConfig Value => this;
    public string SecretKey { get; set; }
    public string Issuer { get; set; }
    public string Audience { get; set; }
    public int Expired { get; set; }
    public DateTime NotBefore => DateTime.UtcNow;
    public DateTime IssuedAt => DateTime.UtcNow;
    public DateTime Expiration => IssuedAt.AddMinutes(Expired);
    private SecurityKey SigningKey => new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey));
    public SigningCredentials SigningCredentials =>
        new SigningCredentials(SigningKey, SecurityAlgorithms.HmacSha256);
}

3、实体类

LoginUserModel
public class LoginUserModel
{
    public string userid { get; set; }
    public string username { get; set; }
    public string phone { get; set; }
    public string roles { get; set; }
}
JwtTokenResult
 public class JwtTokenResult
{
    public string access_token { get; set; }
    public string refresh_token { get; set; }
    /// <summary>
    /// 过期时间(单位秒)
    /// </summary>
    public int expires_in { get; set; }
    public string token_type { get; set; }
    public LoginUserModel user { get; set; }
}

 4、创建JWT服务类

public class GenerateJwt
{
    private readonly JwtConfig _jwtConfig;
    public GenerateJwt(IOptions<JwtConfig> jwtConfig)
    {
        _jwtConfig = jwtConfig.Value;
    }
    /// <summary>
    /// 生成token
    /// </summary>
    /// <param name="sub"></param>
    /// <param name="customClaims">携带的用户信息</param>
    /// <returns></returns>
    public string GenerateEncodedToken(LoginUserModel customClaims)
    {
        //创建用户身份标识,可按需要添加更多信息
        var claims = new List<Claim>();
        claims.Add(new Claim("phone",customClaims.phone));
        claims.Add(new Claim(ClaimTypes.NameIdentifier, customClaims.userid));
        claims.Add(new Claim(ClaimTypes.Name, customClaims.username));
        foreach (var role in customClaims.roles.Split(','))
        {
            claims.Add(new Claim(ClaimTypes.Role, role));
        }
        //创建令牌
        var jwt = new JwtSecurityToken(
            issuer: _jwtConfig.Issuer,
            audience: _jwtConfig.Audience,
            claims: claims,
            notBefore: _jwtConfig.NotBefore,
            expires: _jwtConfig.Expiration,
            signingCredentials: _jwtConfig.SigningCredentials);
        //生成JWT
        string access_token = new JwtSecurityTokenHandler().WriteToken(jwt);
        //return new JwtTokenResult()
        //{
        //    access_token = access_token,
        //    expires_in = _jwtConfig.Expired * 60,
        //    token_type = JwtBearerDefaults.AuthenticationScheme,
        //    user = customClaims
        //};
        return access_token;
    }
}

5、控制器代码

[Route("api/[controller]/[action]")]
[ApiController]
[Authorize()]//鉴权
public class JwtController : ControllerBase
{
    private readonly GenerateJwt _generateJwt;
    public JwtController(GenerateJwt generate)
    {
        this._generateJwt = generate;
    }

    [AllowAnonymous]//可匿名
    [HttpPost]
    public ActionResult Login([FromBody] LoginUserModel loginUser)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest("Invalid Request");
        }

        var refreshToken = Guid.NewGuid().ToString();
        /*
		生成token之前要验证一下账户是否存在
		*/
        try
        {
            var jwtTokenResult = _generateJwt.GenerateEncodedToken(loginUser);
            ////客户端每次登陆都刷新jwt guid值,与保存的guid相比较
            ////若不相同,则说明是不同客户端登陆,之前登陆的客户端jwt过时,需重新登陆
            //jwtTokenResult.refresh_token = refreshToken;
            //这里可按需返回
            return Ok(jwtTokenResult);
        }
        catch (Exception e) { return BadRequest("Invalid Request"); }
    }

    [Authorize(Roles = "admin")]//角色,可叠加
    [HttpGet]
    public ActionResult GetAuthorization()
    {
        var claims = new LoginUserModel()
        {
            username = User.FindFirst(ClaimTypes.Name).Value,
            userid = User.FindFirst(ClaimTypes.NameIdentifier).Value,
            roles = string.Join(',', User.FindAll(ClaimTypes.Role).Select(c => c.Value)),
            phone = User.FindFirst("phone").Value,
        };
        return Ok(claims);
    }

    [HttpGet]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
}

6、在Startup.cs 中启用Jwt认证

//注入jwt服务
services.AddScoped<GenerateJwt>();
//读取配置文件中的JwtConfig字段
services.Configure<JwtConfig>(Configuration.GetSection("JwtConfig"));

//将字段中的值赋值给 JwtConfig 实体类
var jwtConfig = new JwtConfig();
Configuration.Bind("JwtConfig", jwtConfig);
//var jwtConfig = Configuration.GetSection("JwtConfig").Get<JwtConfig>();

#region jwt认证
services
    .AddAuthentication(option =>
    {
        //认证middleware配置
        option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            //是否验证SecurityKey
            ValidateIssuerSigningKey = true,
            //Token颁发机构
            ValidIssuer = jwtConfig.Issuer,
            //颁发给谁
            ValidAudience = jwtConfig.Audience,
            //这里的key要进行加密
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfig.SecretKey)),
            //是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
            ValidateLifetime = true,
            ////过期时间容错值,解决服务器端时间不同步问题(秒)
            //ClockSkew = TimeSpan.FromSeconds(30),
            //RequireExpirationTime = true,
        };
    });
#endregion

启用认证、授权中间件:

app.UseAuthentication();
app.UseAuthorization();

7、配置Swagger全局授权

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication1", Version = "v1" });
    #region 启用swagger验证功能
    //添加一个必须的全局安全信息,和AddSecurityDefinition方法指定的方案名称一致即可。
    c.AddSecurityRequirement(new OpenApiSecurityRequirement
    {
        {
            new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference {
                    Type = ReferenceType.SecurityScheme,
                    Id = "Bearer"
                }
            },
            new string[] { }
        }
    });
    c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
    {
        Description = "JWT授权(数据将在请求头中进行传输) 在下方输入Bearer {token} 即可,注意两者之间有空格",
        Name = "Authorization",//jwt默认的参数名称
        In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
        Type = SecuritySchemeType.ApiKey,
        BearerFormat = "JWT",
        Scheme = "Bearer",

    });
    #endregion
});

Authotrize授权,Value:Bearer {jwt字符串},注意:中间加一个空格

8、测试

Login接口:

入参:出参:

Authotrize授权后,GetAuthorization接口:

get接口未授权:

标签:string,JWT,jwt,claims,new,public
From: https://www.cnblogs.com/xixi-in-summer/p/18088028

相关文章

  • JWT(JSON WEB TOKEN)是玩具吗
    JWT当然不是玩具,理解其设计意图,和适用场景自然会发现存在的就是有价值的JWT:JSONWebToken起源和定义JWT(JSONWebToken)是由IETF(InternetEngineeringTaskForce)基于RFC7519规范定义的。它是一种用于在网络应用间传递信息的标准方法。JWT最初由无状态的分布式应用场......
  • JWTBearer
    JWTBearer框架是.NET中一种基于JSONWebToken(JWT)实现的身份验证和授权框架。JWT是一种开放标准,用于在不同系统之间安全地传输信息。它使用JSON对象来表示声明,声明包含关于实体(通常是用户)的信息以及与该实体相关的元数据。这些声明可以被签名和/或加密,以确保只有授权用户可......
  • SSM整合Jwt
    #导入jwt依赖创键Util123#4.测试......
  • JWT令牌-登录认证
    1.JWT令牌组成Header(头),记录令牌类型和签名算法等PayLoad(载荷),携带自定义的信息Signature(签名),对头部和载荷进行加密计算得来用于登录认证承载业务数据,减少后续请求查询数据库的次数防篡改,保证信息的合法性和有效性2.使用引入java-jwt坐标调用API生成或验证......
  • JWT登录认证-项目BotBattle
    目录session授权认证原理密码存储与加密jwt(JSONWebToken)验证JWT的无状态认证机制实践与调试实现目标:在没有判断登录认证的情况下,访问任意界面,直接跳转到登录界面。添加SpringSecurity依赖来实现登录认证session授权认证原理实现config.SecurityConfig类SessionID相当......
  • Asp.net core使用Authentication使用jwt简单登录认证
    研究了两天,简单使用就这些,如果需要token续期或者刷新或者自定义校验处理需要重写比较麻烦。在controller中单独获取请求头可使用 HttpContext.Request.Headers["Authorization"]使用流程是:先认证登录->再校验权限Authentication->Authorization 安装依赖,.net8版......
  • jwt
    [jsonwebtoken挖坑]token令牌,注册时生成,登陆验证通过后下发//installnpminstalljsonwebtoken//生成consttoken='Bearer'+jwt.sign({userid:1},secret)//secret生成令牌加密用到的字符串,尽可能复杂一点//解析constdecode=jwt.ver......
  • 使用JWT进行授权认证
    .Net6WebAPI中1、安装组件(Nuget)Microsoft.AspNetCore.Authentication.JwtBearer2、Program.cs配置//授权认证(使用JWT)builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(o=>{//私钥varsecretByte=Encoding.UTF8.GetBytes......
  • 在springboot中使用拦截器+JWT验证token的流程
    我的计算机设计大赛的项目需要用到JWT来进行用户身份验证,项目采用springboot技术,因为我没学过springSrcurity所以只能用原生的拦截器+JWT技术进行验证,我是跟着【SpringBoot整合JWT】这篇文章做的,老师讲的很详细跟着一步一步来也可以实现JWT身份验证,但是对于验证过程的整个流程......
  • 使用Golong轻松实现JWT身份验证
    使用Golong轻松实现JWT身份验证JSON Web Tokens (JWT)是一种流行的安全方法,用于在两个方之间表示声明。在Web应用程序领域,它们通常用作从客户端向服务器传输身份信息(声明)的方式。本教程将引导您逐步实现Go应用程序中的JWT身份验证过程。什么是JWT?JSONWebToken(JWT......