如何使用JWT进行身份验证与授权

简介

JWT定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

工作流程

1、用户使用账号、密码登录应用,登录的请求发送到认证服务器。

2、认证服务器进行用户验证,然后创建JWT字符串返回给客户端。

3、客户端请求接口时,在请求头带上JWT。应用服务器验证JWT合法性,如果合法则继续调用应用接口返回结果。

数据结构

JWT由3部分组成:标头(Header)、有效载荷(Payload)和签名(Signature)。在传输的时候,会将JWT的3部分分别进行Base64编码后用.进行连接形成最终传输的字符串JWT由3部分组成:标头(Header)、有效载荷(Payload)和签名(Signature)。在传输的时候,会将JWT的3部分分别进行Base64编码后用.进行连接形成最终传输的字符串JWT一般是这样一个字符串,分为三个部分,以"."隔开:

xxxxx.yyyyy.zzzzz
JWTString=Base64(Header).Base64(Payload).HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret)

token认证的优势

相⽐于 Session 认证的⽅式来说,使⽤ jwt 进⾏⾝份认证主要有下⾯优势

1.⽆状态

2.有效避免了CSRF 攻击

3.适合移动端应⽤

4.单点登录友好

NETCore使用JWT

添加数据访问模拟api,ValuesController

其中api/value1是可以直接访问的,api/value2添加了权限校验特性标签 [Authorize]

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;namespace Demo.Jwt.Controllers
{[ApiController]public class ValuesController : ControllerBase{[HttpGet][Route("api/value1")]public ActionResult<IEnumerable<string>> Get(){return new string[] { "value1", "value1" };}[HttpGet][Route("api/value2")][Authorize]public ActionResult<IEnumerable<string>> Get2(){return new string[] { "value2", "value2" };}}
}

添加模拟登陆,生成Token的api,AuthController

这里模拟一下登陆校验,只验证了用户密码不为空即通过校验,真实环境完善校验用户和密码的逻辑。

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;namespace Demo.Jwt.Controllers
{[Route("api/[controller]")][ApiController]public class AuthController : ControllerBase{[AllowAnonymous][HttpGet]public IActionResult Get(string userName, string pwd){if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(pwd)){var claims = new[]{new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddMinutes(30)).ToUnixTimeSeconds()}"),new Claim(ClaimTypes.Name, userName)};var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey));var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);var token = new JwtSecurityToken(issuer: Const.Domain,audience: Const.Domain,claims: claims,expires: DateTime.Now.AddMinutes(30),signingCredentials: creds);return Ok(new{token = new JwtSecurityTokenHandler().WriteToken(token)});}else{return BadRequest(new { message = "username or password is incorrect." });}}}
}

Startup添加JWT验证的相关配置

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Text;namespace Demo.Jwt
{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){//添加jwt验证:services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => {options.TokenValidationParameters = new TokenValidationParameters{ValidateIssuer = true,//是否验证IssuerValidateAudience = true,//是否验证AudienceValidateLifetime = true,//是否验证失效时间ClockSkew = TimeSpan.FromSeconds(30),ValidateIssuerSigningKey = true,//是否验证SecurityKeyValidAudience = Const.Domain,//AudienceValidIssuer = Const.Domain,//Issuer,这两项和前面签发jwt的设置一致IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Const.SecurityKey))//拿到SecurityKey};});services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);}// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.public void Configure(IApplicationBuilder app, IHostingEnvironment env){///添加jwt验证app.UseAuthentication();if (env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseMvc(routes =>{routes.MapRoute(name: "default",template: "{controller=Home}/{action=Index}/{id?}");});}}
}
namespace Demo.Jwt
{public class Const{/// <summary>/// 这里为了演示,写死一个密钥。实际生产环境可以从配置文件读取,这个是用网上工具随便生成的一个密钥/// </summary>public const string SecurityKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDI2a2EJ7m872v0afyoSDJT2o1+SitIeJSWtLJU8/Wz2m7gStexajkeD+Lka6DSTy8gt9UwfgVQo6uKjVLG5Ex7PiGOODVqAEghBuS7JzIYU5RvI543nNDAPfnJsas96mSA7L/mD7RTE2drj6hf3oZjJpMPZUQI/B1Qjb5H3K3PNwIDAQAB";public const string Domain = "http://localhost:5000";}
}

在实际开发中需要用下列手段来增加JWT的安全性:

1、因为JWT是在请求头中传递的,所以为了避免网络劫持,推荐使用HTTPS来传输,更加安全

2、JWT的哈希签名的密钥是存放在服务端的,所以只要服务器不被攻破,理论上JWT是安全的。因此要保证服务器的安全

3、JWT可以使用暴力穷举来破解,所以为了应对这种破解方式,可以定期更换服务端的哈希签名密钥(相当于盐值)。这样可以保证等破解结果出来了,你的密钥也已经换了

token 过期后,如何自动续期

1、方式1

将 token 过期时间设置为15分钟;

前端发起请求,后端验证 token 是否过期;如果过期,前端发起刷新token请求,后端为前端返回一个新的token;

前端用新的token发起请求,请求成功;

如果要实现每隔72小时,必须重新登录,后端需要记录每次用户的登录时间;用户每次请求时,检查用户最后一次登录日期,如超过72小时,则拒绝刷新token的请求,请求失败,跳转到登录页面。

另外后端还可以记录刷新token的次数,比如最多刷新50次,如果达到50次,则不再允许刷新,需要用户重新授权。

2、方式2

登录成功以后,后端返回 access_token 和 refresh_token,客户端缓存此两种token;

使用 access_token 请求接口资源,成功则调用成功;如果token超时,客户端携带 refresh_token 调用token刷新接口获取新的 access_token;

后端接受刷新token的请求后,检查 refresh_token 是否过期。如果过期,拒绝刷新,客户端收到该状态后,跳转到登录页;如果未过期,生成新的 access_token 返回给客户端。

客户端携带新的 access_token 重新调用上面的资源接口。

客户端退出登录或修改密码后,注销旧的token,使 access_token 和 refresh_token 失效,同时清空客户端的 access_token 和 refresh_toke。

后端实现token过期还可以利用Redis来存储token,设置redis的键值对的过期时间。如果发现redis中不存在token的记录,说明token已经过期了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/288022.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云应用基础技术成熟需七年时间

本文讲的是云应用基础技术成熟需七年时间&#xff0c;【IT168 资讯】市场研究机构Gartner, Inc.近期认为尽管云计算市场目前正处于活跃、增长和高潜力时期……  市场研究机构Gartner,Inc.近期认为尽管云计算市场目前正处于活跃、增长和高潜力时期&#xff0c;但是在云计算或服…

Qt 第一步 HelloWorld 的第一个程序

简言 Qt 是基于C的 GUI 解决方案。QT简单易学&#xff08;底层封装的好&#xff09;、跨平台、相关资料易得到。 开始写Qt 相关的文章的主要原因是&#xff0c;我本人在编写一个视频录制及相关处理的项目&#xff0c;写到一半发现.net winform 相关UI的处理限制较大&#xff…

ArcGIS 10.x属性表乱码问题解决办法

ArcGIS 10.x的版本&#xff0c;文件属性表老出现乱码的问题。 解决方法&#xff1a;在Cmd命令行中输入以下命令&#xff1a; reg add HKEY_CURRENT_USER\Software\ESRI\Desktop10.6\Common\CodePage /v dbfDefault /t REG_SZ /d 936 /f 版本找对应的该就行&#xff0c;10.2 …

SAP MM 采购订单收货被取消了还是不能增加新的delivery cost!

SAP MM 采购订单收货被取消了还是不能增加新的delivery cost! PO# 8500015169, we did GR and cancelled GR, there is no IR for this PO at present. ME22N, try to add a delivery cost ZCIP in the item, You cannot enter new delivery costs Message no. V1631 Diag…

样式中文字和图片对齐问题

html中&#xff0c;在图片和文字对齐的时候&#xff0c;一直没有达到想要的对齐效果&#xff0c;发现使用position中的相对定位绝对定位paddingmargin可以达到需要的效果。转载于:https://www.cnblogs.com/TheoryDance/p/5424456.html

webots仿真报警[ERROR] [1703399199.459991029]: Sampling period is not valid.

一、故障现象 在运行interace传感器使能程序时&#xff0c;报警[ERROR] [1703399199.459991029]: Sampling period is not valid. [ERROR] [1703399199.460080083]: Failed to enable lidar.并发生崩溃。 二、解决方式 1、尝试将程序中的TIME_STEP数值改为与WOrldInfo中的bas…

剑指offer之调整数组顺序使奇数位于偶数前面

1 问题 输入一个整数数组&#xff0c;实现一个函数来调整该数组中数字的顺序&#xff0c;使得所有奇数位于数组的前半部分&#xff0c;所有偶数位于数组的后半部分&#xff0c;比如数组{6、 5 、1、 4、2 、7 、3、8、9}我们调整后变成这样{9、5、1、3、7 、2 、4 、8、6} …

负基础学python编程_【数据科学系统学习】Python # 编程基础[二]

在上一篇中我们讲到了函数&#xff0c;如果你想在所编写的别的程序中重用一些函数的话&#xff0c;应该怎么办&#xff1f;正如你可能想象到的那样&#xff0c;答案是模块(Modules)。我们这一篇就从模块说起。模块为了编写可维护的代码&#xff0c;我们把很多函数分组&#xff…

【JX4G】JX4G摄影测量工作站快捷键大全

本文章总结了JX4G数字摄影测量工作站中常用的快捷键及其用法。 JX4G快捷键一览表序号快捷键作用描述1X删除可以框选&#xff0c;右键删除2C强制闭合可以闭合等高线等3S图形映射开关控制二维图形在三维立体中的显示4Z输入高程值可锁定高程5T流线和折线之间互换流线和折线之间互换…

python3 最简单的实现 模版设计模式

在项目开发过程时&#xff0c;遇见某些子类的逻辑处理流程大致相同&#xff0c;可是用模板模式减少代码冗余&#xff0c;降低耦合。 例如实现某一窗体或者页面启动时&#xff0c;第一步需要加载启动界面图片资源&#xff0c;第二步加载个人信息&#xff0c;第三步加载个人钱包…

《代码整洁之道》读书笔记-1

前言&#xff1a;我最近在读《代码整洁之道》这本书&#xff0c;在读的过程中发现如果只是读&#xff0c;不动手做点什么的话&#xff0c;总感觉少了点什么&#xff0c;于是就写点总结&#xff0c;给自己加深印象。当然&#xff0c;本文只是理论&#xff0c;不会讨论如何写出整…

什么是Freedoc?Freedoc是什么?

本文讲的是什么是Freedoc&#xff1f;Freedoc是什么&#xff1f;&#xff0c;【IT168 资讯】Freedoc是刘鹏提出的一个概念&#xff0c;其目的是建立一种简易的免费文档共享和版权保护机制。  Freedoc的想法来自Freeware和开源软件&#xff1a;既然大量软件可以免费合法共享&a…

玩转CSS选择器(一) 之 使用方法介绍

前言 前几天整理了CSS一些技术关键字&#xff0c;但是因为自己的知识过于单薄&#xff0c;觉得考虑的不充分有欠缺&#xff0c;随后便在sf.gg提出了这个问题《关于CSS核心技术关键字都有哪些&#xff1f;》&#xff0c;也是为了让厉害的人一起参与进来&#xff0c;用他们的经验…

php基础-1

//echo "hello","aaaa";//输出语法&#xff0c;可以输出多个字符串//print "world"; //可以输出&#xff0c;只能输出一个字符串 用"."拼接可以输出&#xff0c;用","拼接直接报错 //数据类型 int,double,float,string,char…

工业相机和普通相机的区别详解_数码单反相机和胶片单反相机的区别

从相机出世到现在&#xff0c;相机的种类可以分为两种&#xff0c;一个是早期的胶片相片&#xff0c;另一个是现在的数码相机&#xff0c;数码相机的种类也是有很多种&#xff0c;其中最为常见就是单反相机了。那么今天我们就来看看胶片机和单反的区别。相机的种类总的来说可以…

剑指offer之二进制中1的个数

1 问题 实现一个函数&#xff0c;输入一个函数&#xff0c;输出该二进制数据中1的个数。例如9表示二进制数据1001&#xff0c;有2位是1&#xff0c;因此输入9&#xff0c;该函数会输出2。 2 分析 我们先了解下计算机里面位运算&#xff0c;有5种 1&#xff09;& 这个是与…

ArcGIS 10.6 Data Interoperability Tools的安装与使用(附安装包下载)

ArcGIS平台中提供了一个数据交互操作工具Data Interoperability Tools,安装Desktop的时候不是一并安装的,这样导致Data Interoperability Tools工具箱下的工具(如Quick Import)全面有一个红色的叉号,无法正常使用,解决办法是手动安装Data Interoperability Tools,位于软…

女朋友强依赖我!我引入IOC后,从此我们的关系微妙而稳固!

此文从面向对象设计角度分析依赖倒置原则&#xff0c;引入依赖注入&#xff0c;IOC相关内容进行探讨&#xff0c;文中引用女朋友案例可能引起分手风险&#xff0c;故理解为 new 对象。想起在学校的时候&#xff0c;有一个任务就是设计一款宠物商店项目。那时候引入三层架构设计…

Qt 第二步 槽与信号(一) 实现点击按钮并弹窗

信号与槽是Qt中的核心&#xff0c;也是Qt的特有的。在Qt中信号与槽的关键字为slots、signals、emit。 具体信号与槽将会在下一节中详细说明&#xff0c;因为担心一些读者在没了解过槽与信号前直接讲述过深导致门槛提高&#xff0c;阅读困难&#xff0c;所以当前这一篇文将在不理…

mvc 返回一个对象 到视图接收

public ActionResult InfoFrame() { List<Users> list new List<Users>(); Users user new Users(); if (Session["UserID"] null)//判断是否没登录 { return RedirectToAction("LoginIndex", "Login"); } else { string sql st…