应无所住,而生其心
排名
1
文章
860
粉丝
112
评论
163
net core webapi post传递参数
庸人 : 确实坑哈,我也是下班好了好几次,发现后台传递对象是可以的,但...
百度编辑器自定义模板
庸人 : 我建议换个编辑器,因为现在百度富文本已经停止维护了,用tinymec...
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术

net core使用jwt

7098人阅读 2019/11/6 12:15 总访问:5179561 评论:2 收藏:0 手机
分类: .NET Core

吃亏绝不亏,惜福才有福


jwt优势:

服务器不用存储,非常方便于分布式开发,给APP提供数据,前后台分离的项目等。登录产生jwt token的项目完全可以独立与其他项目,所谓的单点登录,jwt可以非常方便的实现,可以和项目和语言无关,用统一的解析方式就可以了,更标准化。


jwt是怎么验证用户信息的

当用户访问登录接口的时候会返回一个token,然后访问其他需要登录的接口都会带上这个token,后台进行验证如果token是有效的我们就认为用户是正常登录的,然后我们可以从token中取出来一些携带的信息进行操作。

当然这些携带的信息都可以通过其他额外的字段进行传递,但是用token传递的话,不用其他额外加其他字段了,这样数据传递也要小一点



jwt是怎么防止被伪造的:

jwt服务器不存储,用户不登陆直接随便找一个jwt发送到服务器不就可以用了?

服务器有个验证签名的过程,签名是headers , payloads用一个密钥加密而成的


服务器每次收到后在通过header和body加密后和用户传递过程的token匹配一下就知道jwt是否真实有效了

也就是说只有知道密钥才能构建一个被服务器认可的token。


但是前台已经知道了token每部分的组成,也就是说前台可以得到一个明文和一个加密和的字符串,为了防止被反推,

所以我们应该使用不可逆的摘要算法。


当然也不是说jwt就绝对的安全,只要客户端能够拿到加密的秘钥或者其他手段构建一个可以被正确验证的token,就能被绕过,

所以我们不要在jwt中去存储太敏感的信息。还有就是比较重要的信息,我们处理验证jwt正确性以为还要把用户的身份进去验证

访问重要数据被非法方法



Net Core登录生成JWT Token

net core中自带的库是:System.IdentityModel.Tokens.Jwt,基本上现在的版本都自带了,如果没有,用nuget下载即可,或者你想要用单独一个库去封装jwt的帮助类,也需要下载一下。


我们把jwt帮助类相关的可以弄到一个文件夹下面

下面分别贴一下这四个类的代码:

JWTConfig:用来保存读取jwt相关配置

  1. public class JWTConfig
  2. {
  3.     public string Issuer { getset; }
  4.     public string Audience { getset; }
  5.     public string IssuerSigningKey { getset; }
  6.     public int AccessTokenExpiresMinutes { getset; }
  7. }

TnToken :存放需要返回的字段,很简单就一个token和一个过期时间

  1. public class TnToken
  2. {
  3.     public string TokenStr{ getset; }
  4.     public DateTime Expires { getset; }
  5. }

ITokenHelper:token工具类的接口,方便使用依赖注入,很简单提供两个常用的方法

  1. public interface ITokenHelper
  2. {
  3.     /// <summary>
  4.     /// 根据一个对象通过反射提供负载生成token
  5.     /// </summary>
  6.     /// <typeparam name="T"></typeparam>
  7.     /// <param name="user"></param>
  8.     /// <returns></returns>
  9.     TnToken CreateToken<T>(T user) where T : class;
  10.     /// <summary>
  11.     /// 根据键值对提供负载生成token
  12.     /// </summary>
  13.     /// <param name="keyValuePairs"></param>
  14.     /// <returns></returns>
  15.     TnToken CreateToken(Dictionary<stringstring> keyValuePairs);
  16. }

TokenHelper:实现类

  1. public class TokenHelper : ITokenHelper
  2. {
  3.     private IOptions<JWTConfig> _options;
  4.     public TokenHelper(IOptions<JWTConfig> options)
  5.     {
  6.         _options = options;
  7.     }
  8.     /// <summary>
  9.     /// 根据一个对象通过反射提供负载生成token
  10.     /// </summary>
  11.     /// <typeparam name="T"></typeparam>
  12.     /// <param name="user"></param>
  13.     /// <returns></returns>
  14.     public TnToken CreateToken<T>(T user) where T:class
  15.     {
  16.         //携带的负载部分,类似一个键值对
  17.         List<Claim> claims = new List<Claim>();
  18.         //这里我们用反射把model数据提供给它
  19.         foreach (var item in user.GetType().GetProperties())
  20.         {
  21.             object obj = item.GetValue(user);
  22.             string value = "";
  23.             if (obj != null)
  24.                 value = obj.ToString();
  25.             claims.Add(new Claim(item.Name, value));
  26.         }
  27.         //创建token
  28.         return CreateToken(claims);
  29.     }
  30.     /// <summary>
  31.     /// 根据键值对提供负载生成token
  32.     /// </summary>
  33.     /// <param name="keyValuePairs"></param>
  34.     /// <returns></returns>
  35.     public TnToken CreateToken(Dictionary<string,string> keyValuePairs)
  36.     {
  37.         //携带的负载部分,类似一个键值对
  38.         List<Claim> claims = new List<Claim>();
  39.         //这里我们通过键值对把数据提供给它
  40.         foreach (var item in keyValuePairs)
  41.         {
  42.             claims.Add(new Claim(item.Key,item.Value));
  43.         }
  44.         //创建token
  45.         return CreateToken(claims);
  46.     }
  47.     private TnToken CreateToken(List<Claim> claims)
  48.     {
  49.         var now = DateTime.Now; var expires = now.Add(TimeSpan.FromMinutes(_options.Value.AccessTokenExpiresMinutes));
  50.         var token = new JwtSecurityToken(
  51.             issuer: _options.Value.Issuer,//Token发布者
  52.             audience: _options.Value.Audience,//Token接受者
  53.             claims: claims,//携带的负载
  54.             notBefore: now,//当前时间token生成时间
  55.             expires: expires,//过期时间
  56.             signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.IssuerSigningKey)), SecurityAlgorithms.HmacSha256));
  57.         return new TnToken { TokenStr = new JwtSecurityTokenHandler().WriteToken(token), Expires = expires };
  58.     }
  59. }

这里封装了两个提供携带负载数据的方法,反射对象和键值对,当然你也可以封装一些常用的方法进去,看项目和需求了。


在Startup中去配置jwt相关:

ConfigureServices中:

  1. #region jwt相关
  2. services.AddTransient<ITokenHelper, TokenHelper>();
  3. //读取配置文件配置的jwt相关配置
  4. services.Configure<JWTConfig>(Configuration.GetSection("JWT"));
  5. //启用JWT
  6. services.AddAuthentication(Options =>
  7. {
  8.     Options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  9.     Options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  10. }).
  11. AddJwtBearer();
  12. #endregion

如果找不到JwtBearerDefaults.AuthenticationScheme与AddJwtBearer();下载两个依赖即可,具体版本根据项目使用的版本

  1. install-package Microsoft.Extensions.DependencyInjection
  2. install-package Microsoft.AspNetCore.Authentication.JwtBearer -version 3.0


Configure中去启用验证中间件:

  1. //启用认证中间件
  2. app.UseAuthentication();

appsettings中简单配置一下jwt相关的信息:

  1. "JWT": {
  2.   "Issuer""TNBLOG"//Token发布者
  3.   "Audience""AXJ"//Token接受者
  4.   "IssuerSigningKey""签名秘钥",//(很重要,拿到秘钥就可以构建服务器认可的token),注意签名秘钥长度不能太短了否则报错
  5.   "AccessTokenExpiresMinutes""30" //过期时间
  6. }


然后在登录api的地方就可以使用了:

  1. [ApiVersion("1.0")]
  2. [Route("api/v1/[controller]")]
  3. [ApiController]
  4. public class LoginController : ControllerBase
  5. {
  6.     private ITokenHelper tokenHelper = null;
  7.     private IUserDAL userDAL;
  8.     public LoginController(ITokenHelper _tokenHelper, IUserDAL _userDAL)
  9.     {
  10.         tokenHelper = _tokenHelper;
  11.         userDAL = _userDAL;
  12.     }
  13.     [HttpGet("{username}/{pwd}")]
  14.     public ReturnModel<TnToken> Get(string username, string pwd)
  15.     {
  16.         ReturnModel<TnToken> returnModel = new ReturnModel<TnToken>();
  17.         if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(pwd))
  18.         {
  19.             returnModel.Code = 201;
  20.             returnModel.Msg = "用户名密码不能为空";
  21.             return returnModel;
  22.         }
  23.         UserInfo userInfo = new UserInfo() { UserName = username, UserPwd = pwd };
  24.         //实现登录
  25.         UserInfo user = userDAL.Login(userInfo);
  26.         if (user != null)
  27.         {
  28.                 //给jwt提供携带的数据
  29.             Dictionary<stringstring> keyValuePairs = new Dictionary<stringstring>();
  30.             keyValuePairs.Add("userName", user.UserName);
  31.             TnToken tnToken = tokenHelper.CreateToken(keyValuePairs);
  32.             returnModel.Code = 200;
  33.             returnModel.Msg = "登录成功!";
  34.             returnModel.Value = tnToken;
  35.             return returnModel;
  36.         }
  37.         else
  38.         {
  39.             returnModel.Code = 300;
  40.             returnModel.Msg = "登录失败!";
  41.             return returnModel;
  42.         }
  43.     }
  44. }

tip:ReturnModel只是我自己封装的一个统一的接口返回格式标准而已不必在意


访问下登录接口试试

可以看到我们成功生成了token,我们可以把生成的token拿去jwt官网解密试试:


tip:一般情况下jwt只做身份证验证,jwt里边携带的数据也是为了辅助身份验证,不会直接取出来在客户端用,不需要加其他业务信息在里面,前台需要用户展示的数据比如登录成功后需要拿到用户名和设置的头像等,我们单独给字段提供就好,前台也方便直接解析。

比如像这样多提供几个字段,和token一起返回即可,当然也可以另外提供一个单独的接口在调用一次,看自己项目的业务逻辑了


注意报错:

[PII is hidden]'. Exceptions caught:  '[PII is hidden]'. token: '[PII is hidden]

是因为签名秘钥长度不能太短了否则报错


net core使用jwt2:验证前台传递的token

http://www.tnblog.net/aojiancc2/article/details/2845



欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739。有需要软件开发,或者学习软件技术的朋友可以和我联系~(Q:815170684)

评价

Murphy

2020/6/26 20:05:28

mvc也可以吗?api倒是可以,但是mvc的话普通路由请求我怎么把token写到header里

剑轩:@Murphy不一定要放到header里边哇,看怎么用,用这个来实现单点登录什么的也很方便

2020/6/27 12:03:29 回复

net core 使用 EF Code First

下面这些内容很老了看这篇:https://www.tnblog.net/aojiancc2/article/details/5365 项目使用多层,把数据库访问...

.net mvc分部页,.net core分部页

.net分部页的三种方式第一种:@Html.Partial(&quot;_分部页&quot;)第二种:@{ Html.RenderPartial(&quot;分部页&quot;);}...

StackExchange.Redis操作redis(net core支持)

官方git开源地址https://github.com/StackExchange/StackExchange.Redis官方文档在docs里边都是官方的文档通过nuget命令下...

.net core 使用session

tip:net core 2.2后可以直接启用session了,不用在自己添加一次session依赖,本身就添加了使用nuget添加引用Microsoft.AspN...

通俗易懂,什么是.net?什么是.net Framework?什么是.net core?

朋友圈@蓝羽 看到一篇文章写的太详细太通俗了,搬过来细细看完,保证你对.NET有个新的认识理解原文地址:https://www.cnblo...

asp.net core2.0 依赖注入 AddTransient与AddScoped的区别

asp.net core主要提供了三种依赖注入的方式其中AddTransient与AddSingleton比较好区别AddTransient瞬时模式:每次都获取一...

.net core 使用 Kestrel

Kestrel介绍 Kestrel是一个基于libuv的跨平台web服务器 在.net core项目中就可以不一定要发布在iis下面了Kestrel体验可以使...

net core使用cookie

net core中可以使用传统的cookie也可以使用加密的cookieNET CORE中使用传统cookie设置:HttpContext.Response.Cookies.Appe...

net core项目结构简单分析

一:wwwrootwwwroot用于存放网站的静态资源,例如css,js,图片与相关的前端插件等lib主要是第三方的插件,例如微软默认引用...

net core使用EF之DB First

一.新建一个.net core的MVC项目新建好项目后,不能像以前一样直接在新建项中添加ef了,需要用命令在添加ef的依赖二.使用Nug...

.net core使用requestresponse下载文件下载excel等

使用request获取内容net core中request没有直接的索引方法,需要点里边的Query,或者formstringbase64=Request.Form[&quot;f...

iframe自适应高度与配合net core使用

去掉iframe边框frameborder=&quot;0&quot;去掉滚动条scrolling=&quot;no&quot;iframe 自适应高度如果内容是固定的,那么就...

net core启动报错Unable to configure HTTPS endpoint. No server certificate was specified

这是因为net core2.1默认使用的https,如果使用Kestrel web服务器的话没有安装证书就会报这个错其实仔细看他的错误提示,其...

net core使用url编码与解码操作

net core中暂时还没有以前asp.net与mvc中的server对象。获取url的编码与解码操作不能使用以前的server对象来获取。使用的是...

下载net core

官方下载地址:https://dotnet.microsoft.com/download 进来之后就可以看到最新的下载版本可以直接点击下载,也可以下载其...

net core使用依赖注入来装载EF的上下文对象

妹子情人节快乐~.net core中用了不少的依赖注入,官方文档中也推荐使用。这样使用依赖注入来管理ef对象,还是比较科学,比如...