zoukankan      html  css  js  c++  java
  • JWT权限验证

    JWT(Json Web Token)
    什么是JWT,它是一种对API的保护方案,为什么要进行保护呢
    1. 防泄漏:你肯定不希望你的数据能被别人随意调用,比如公司的机密信息,不可能每个人都可以访问到
    2. 防攻击:防止被人伪装恶意调用接口,利用网关就把请求拦截在外面,防止对服务器造成资源压力
    3. 防止被人篡改,导致请求不到信息,防重放攻击(案例:在公共网络环境中,请求被截获,稍后被重放或多次重放)
    设计原则
    1. 轻量级
    2. 易于开发、测试和部署
    3. 适合于异构系统(跨操作系统、多语言简易实现)
    4. 所有写操作接口(增、删、改 操作)
    5. 非公开的读接口(如:涉密/敏感/隐私 等)
    JWT核心知识
    claim:claim就是声明,就像身份证上的地址,个人信息
    Httpcontext是如何通过claim鉴权的:我们去办业务的时候,需要出示自己的身份证,这个身份证就相当于自己的令牌进行访问
    JWT由三部分组成
    第一部分是头部,头部分为两部分(Header
    1. 算法、声明
    2. 类型type:JWT类型
    第二部分是载荷相当于HTML中的body(Payload
    第三部分就是签名也是就是密钥(Signature
    基于.NetCore WebApi创建一个简单的token令牌
    public ActionResult<IEnumerable<string>>Get()
    {
    //创建声明Token数组
    var claim =newClaim[]
    {
    newClaim(ClaimTypes.Name,"ylc"),
    newClaim(JwtRegisteredClaimNames.Email,"1234567@11.com"),
    newClaim(JwtRegisteredClaimNames.Sub,"Sub")
    };
    //实例化一个token对象
    var token =newJwtSecurityToken(claims:claim);
    //生成token
    var jwtToken =newJwtSecurityTokenHandler().WriteToken(token);
    returnnewstring[]{ jwtToken };
    }
    启动项目之后我们会得到一个token令牌
    粘贴到jwt官网中可以解密,下面介绍了另一种解密方法
    token令牌分为两部分,红色部分解析出来代表头部,粉色代表载荷,我们探入的信息
    虽然得到令牌,但是头部的加密算法显示none,也没有数字签名,所以下面显示无效签名
    到底这个加密算法怎么配置呢,接下来进行扩展
    通过查看实例化token的函数发现它有五个重写的构造函数
    
    
    publicJwtSecurityToken(string issuer =null, string audience =null, IEnumerable<Claim> claims =null, DateTime? notBefore =default(DateTime?), DateTime? expires =default(DateTime?), SigningCredentials signingCredentials =null)
    {
    if(expires.HasValue && notBefore.HasValue && notBefore >= expires)
    {
    throw LogHelper.LogExceptionMessage(newArgumentException(LogHelper.FormatInvariant("IDX12401: Expires: '{0}' must be after NotBefore: '{1}'.", expires.Value, notBefore.Value)));
    }
                Payload =newJwtPayload(issuer, audience, claims, notBefore, expires);
                Header =newJwtHeader(signingCredentials);
                RawSignature = string.Empty;
    }

     我们就声明五个参数

    [HttpGet]
    public ActionResult<IEnumerable<string>>Get()
    {
    //创建声明Token数组
    var claim =newClaim[]
    {
    newClaim(ClaimTypes.Name,"ylc"),
    newClaim(JwtRegisteredClaimNames.Email,"1234567@11.com"),
    newClaim(JwtRegisteredClaimNames.Sub,"Sub")
     
    };
    var key =newSymmetricSecurityKey(Encoding.UTF8.GetBytes("yanglingcong@qq.com"));//密钥大小要超过128bt,最少要16位
     
    //实例化一个token对象
    var token =newJwtSecurityToken(
                    issuer:"http://localhost:5000",//发起人:当前项目
                    audience:"http://localhost:5000",//订阅:我们需要谁去使用这个Token
                    claims: claim,//声明的数组
                    expires:DateTime.Now.AddDays(1),//当前时间加一小时,一小时后过期
                    signingCredentials:newSigningCredentials(key,SecurityAlgorithms.HmacSha256)//数字签名 第一部分是密钥,第二部分是加密方式
    );
    var jwtToken =newJwtSecurityTokenHandler().WriteToken(token);
    returnnewstring[]{ jwtToken };
    }
    可能会出现一下报错:IDX10603: Decryption failed. Keys tried: '[PII is hidden]'. Exceptions caught: '[PII is hidden]'. token: '[PII is hidden]' Parameter name: KeySize
    安装最新版Microsoft.IdentityModel.Logging nuget包
    最后成功运行,加密算法已经显示出HS256
    但是最下方还是显示数字签名无效,还要怎么做呢
    我们对令牌解密不一定要看官网通过浏览器控制台打印出来也可以
    将令牌的一部分放入atob中就可以进行解密
    相信做完这些对JWT的三大部分有了一定的了解
    声明Claim的两种方式
    开始在声明Claim的时候用到了ClaimTypes和JwtRegisteredClaimNames这两种
    var claim =newClaim[]
    {
    newClaim(ClaimTypes.Name,"ylc"),
    newClaim(JwtRegisteredClaimNames.Email,"1234567@11.com"),
    newClaim(JwtRegisteredClaimNames.Sub,"Sub")
    };
    F12查看ClaimTypes源码里面写的都是.net Core中提供的常用的静态变量
    查看JwtRegisteredClaimNames源码都是JWT自己提供的
    但是可能有人想获取令牌中的Email的值,获取不到
    接下来就说到获取令牌的三种方式,在这之前要使用http进行上下文注入
    [HttpGet("{str}")]
    public ActionResult<IEnumerable<string>>Get(string str)
    {
    ///获取Token的三种方式
     
    //第一种直接用JwtSecurityTokenHandler提供的read方法
    var jwtHander =newJwtSecurityTokenHandler();
                JwtSecurityToken jwtSecurityToken = jwtHander.ReadJwtToken(str);
     
    //第二种 通过User对象获取
    var sub = User.FindFirst(d => d.Type =="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name")?.Value;
     
    //第三种 通过Httpcontext上下文中直接获取
    var name = _accessor.HttpContext.User.Identity.Name;
    var Claims = _accessor.HttpContext.User.Claims;
    var claimstype =(from item in Claims where item.Type == JwtRegisteredClaimNames.Email select item.Value).ToList();
     
    returnnewstring[]{ JsonConvert.SerializeObject(jwtSecurityToken), sub, name, JsonConvert.SerializeObject(claimstype)};
    }
    然后在postman进行测试,路径后面传入Token令牌,传入的Token的string参数实际是为了方法一,第二三种是没有调用str的,所以它们为空跟Token没有任何关系
    除了第一种JwtSecurityTokenHandler获取的值不为空,其他都为空这是为什么呢
    刚刚只是生成了令牌并没有出现内存中,也就是在http上下文中,下面就是要说到HttpContext是如何鉴权的
    首先我们必须在服务里注册一个Bealer认证,也就是说我们必须注册一个认证才可以获取内容
    如何进行 Jwt Bealer认证呢,需要在配置服务的做相应的配置
    之前在声明Token的时候指明了发起人订阅人,这里也要对应上,就相当于解密的过程
    publicvoidConfigureServices(IServiceCollection services)
    {
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
                services.AddSingleton<IHttpContextAccessor,HttpContextAccessor>();
     
    var keyBase64 ="yanglingcong@qq.com";
    var keyByeArray = Encoding.ASCII.GetBytes(keyBase64);
    var signkey =newSymmetricSecurityKey(keyByeArray);
     
    var tokenValidationParameters =newTokenValidationParameters//生成了一个Token验证的参数
    {
                    ValidateIssuerSigningKey =true,
                    IssuerSigningKey = signkey,//数字签名
                    ValidateIssuer =true,
                    ValidIssuer ="http://localhost:5000",//发行人
                    ValidateAudience =true,
                    ValidAudience ="http://localhost:5000",//订阅人
                    ValidateLifetime =true,
                    ClockSkew = TimeSpan.FromSeconds(30),
                    RequireExpirationTime =true,
    };
     
                services.AddAuthentication("Bearer")//注入服务  1.开启Bearer认证 2.注册Bearer服务
    .AddJwtBearer(o =>
    {
                     o.TokenValidationParameters = tokenValidationParameters;
    });
    }
    完成Bearer以后,我们再进行postman测试,第二种第三种还是为空,这是什么原因呢
    我们通过三步创建令牌之后,通过注入完成我们的认证,还需要开启中间件管道,如果不开启的话,Token令牌还是不能传送到HttpContext上下文,中间件实际就是操作Http上下文。
     app.UseAuthentication();//开启中间件

    还差最后一步就是登录,只有登录认证了Bearer才能将Token转化成相应的服务

    服务对象在经过中间件的时候添加到HttpContext中,然后赋值给User
     
    通过登录生成Token令牌,返回给客户端,客户端拿着Token,放在header里面,传输给服务器进行校验,校验成功返回数据
    返回了三个参数,最后一个还是空
    通过项目调试,发现我们之前的Email参数被改名了,原本是JwtRegisteredClaimNames变成了ClaimTypes的声明方法,这就需要解除,.NetCore自己的映射匹配,使用JWT,在ConfigureServices加上
     JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();//把 JwtSecurityToken清除
    显示成功
    我们在当前GET方法中进行测试加上 [Authorize],把Authorization取消勾选运行
    得到401无状态,我们再把钩点上,成功授权
     
     
  • 相关阅读:
    【Java-JVM】定量分析解决OutOfMemoryError: PermGen space, 来看科学量化分析
    Oracle11g 主机身份证明问题
    html标签的嵌套规则
    提高程序员职场价值的10大技巧
    IT人应当知道的10个行业小内幕
    趣文:如果编程语言是车
    去除inline-block元素间间距的N种方法
    《大型网站SEO优化实践》学习分享
    如何通过预加载器提升网页加载速度
    网页爬虫及其用到的算法和数据结构
  • 原文地址:https://www.cnblogs.com/cg-ww/p/12654364.html
Copyright © 2011-2022 走看看