在吗?认识一下JWT(JSON Web Token) ?
什么是JSON Web Token ?
官网介绍:
JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间安全地将信息作为JSON对象传输。由于此信息是经过数字签名的,因此可以被验证和信任。可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公用/专用密钥对对JWT进行签名。
尽管可以对JWT进行加密以在各方之间提供保密性,但我们将重点关注已签名的令牌。签名的令牌可以验证其中包含的声明的完整性,而加密的令牌则将这些声明隐藏在其他方的面前。当使用公钥/私钥对对令牌进行签名时,签名还证明只有持有私钥的一方才是对其进行签名的一方。
emmmm.......balabala一堆文字,那么我们来简单总结下:
JWT是一个JSON信息传输的开放标准,它可以使用密钥对信息进行数字签名,以确保信息是可验证和可信任的。
JWT的结构是什么?
JWT由三部分构成:header(头部)、payload(载荷)和signature(签名)。 以紧凑的形式由这三部分组成,由“.“分隔。
因此,JWT通常如下所示。
xxxxx.yyyyy.zzzzz
让我们把这串奇奇怪怪的东西分解开来:
header
header通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法,例如HMAC SHA256或RSA等等。
例如:
{ "alg": "HS256", "typ": "JWT" }
显而易见,这货是一个json数据,然后这货会被Base64编码形成JWT的第一部分,也就是xxxxx.yyyyy.zzzzz
中的xxxxxx。
Payload
这货是JWT的第二部分,叫载荷(负载),内容也是一个json对象,它是存放有效信息的地方,它可以存放JWT提供的现成字段 :
-
iss: 该JWT的签发者。
-
sub: 该JWT所面向的用户。
-
aud: 接收该JWT的一方。
-
exp(expires): 什么时候过期,这里是一个Unix时间戳。
-
iat(issued at): 在什么时候签发的。
举个例子:
{ "iss": "www.baidu.com", "sub": "you", "aud": "me", "name": "456", "admin": true, "iat": 1584091337, "exp": 1784091337, }
这货同样会被Base64编码,然后形成JWT的第二部分,也就是xxxxx.yyyyy.zzzzz
中的yyyyyy。
Signature
这是JWT的第三部分,叫做签名,此部分用于防止JWT内容被篡改。将上面的两个编码后的字符串都用英文句号.连接在一起(头部在前),就形成了
xxxxxx.yyyyyy
然后再使用header中声明签名算法进行签名。 如果要使用HMAC SHA256算法,则将通过以下方式创建签名:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
当然,在加密的时候,我们还需要提供一个密钥(secret),我们可以自己随意指定。这样就形成了JWT的第三部分,也就是xxxxx.yyyyy.zzzzz
中的zzzzzz。
最后,我们把这三个部分拼在一起,就形成了一个完整的JWT。
下面展示了一个完整的JWT,它先对header和payload进行编码,最后用一个密钥形成了签名。
如果我们想试验一下的话,可以在JWT的官网进行debugger。贴一下官网: https://jwt.io/
JSON Web Token认证流程
什么时候应该使用JSON Web Token?
以下是JSON Web Token 有用的一些情况:
-
授权:这是使用JWT的最常见方案。一旦用户登录,每个后续请求将包括JWT,从而允许用户访问该令牌允许的路由,服务和资源。单一登录是当今广泛使用JWT的一项功能,因为它的开销很小并且可以在不同的域中轻松使用。
-
信息交换:JSON Web Token是在各方之间安全地传输信息的好方法。因为可以对JWT进行签名(例如,使用公钥/私钥对),所以您可以确定发件人是他们所说的人。此外,由于签名是使用标头和有效负载计算的,因此您还可以验证内容是否遭到篡改。
那么,有人就会说了,道理我都懂,我应该怎样去实现呢?莫慌。。
如何实现?
接下来我会用python实现JWT,不想拉仇恨,但是,python大法好啊。。。。
在前后端分离的项目中,我们需要与前端约定一种身份认证机制。当用户登录的时候,后端会生成token,然后返回给前端,前端需要将token拿到并按照一定规则放到header中,在下一次请求的时候一并发送给后端,后端进行token身份校验。
这里我们约定前端请求后端服务时需要添加头信息Authorization ,内容为token。
我用的是fastapi web框架,搭建项目非常快。
from datetime import timedelta, datetime import jwt from fastapi import FastAPI, HTTPException, Depends from starlette.status import HTTP_401_UNAUTHORIZED from starlette.requests import Request app = FastAPI() SECRET_KEY = "sdifhgsiasfjaofhslio" # JWY签名所使用的密钥,是私密的,只在服务端保存 ALGORITHM = "HS256" # 加密算法,我这里使用的是HS256 @app.get("/") async def root(): return {"message": "Hello World"} @app.post("/create_token") def create_token(username,password): if username == "123" and password == "123": access_token_expires = timedelta(minutes=60) expire = datetime.utcnow() + access_token_expires payload = { "sub": username, "exp": expire } # 生成Token,返回给前端 access_token = jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM) return {"access_token": access_token, "token_type": "bearer"} else: raise HTTPException( status_code=HTTP_401_UNAUTHORIZED, detail="username or password are not true", headers={"WWW-Authenticate": "Bearer"} ) def authorized_user(token): try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) username: str = payload.get("sub") print(username) if username == "123": return username except jwt.PyJWTError: raise HTTPException( status_code=HTTP_401_UNAUTHORIZED, detail="认证失败,无权查看", headers={"WWW-Authenticate": "Bearer"},) @app.get("/app") def create_token(request: Request): print(request.headers.get("host"), request.headers.get("Authorization")) user = authorized_user(request.headers.get("Authorization")) # 验证Token if user: return {"username": user,"detail": "JWT通过,查询成功"}
这里,由于现有的JWT库已经帮我们封装好了,我们可以使用JWT直接生成 token,不用手动base64加密和拼接。
测试一下:
启动项目之后,我们打开http://127.0.0.1:8000/docs# ,就会看到以下我们编写好的api:
首先,我们先验证一下create_token接口
当我们输入用户名,密码后,后端进行验证,验证成功后会返回给前端一个token,也就是JWT。当前端拿到这个token之后,下次在请求的时候就必须要带上这个token了,因为前后端已经约定好了。接下来我们试一下:
认证失败???
什么原因导致的呢??让我们点开检查抓一下包看看:
恍然大悟,刚才我们说过,前后端事先约定好的,请求的header中一定要带上token,在Authorization ,内容token。我们现在这个请求的header中并没有带上token,那这种debug模式下又是改不了请求header信息的,我们可以使用接口测试工具进行测试,我主推Postman!!!,让我们来试一下:
至此,JWT介绍以及使用梳理完毕。
最后,感谢女朋友在生活中,工作上的包容、理解与支持 !
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
CNCF 2019 年度报告重磅发布 | 云原生生态周报 Vol. 41
作者 | 孙健波、陈有坤、李鹏、丁海洋、高相林 业界要闻 Istio 1.5 正式发布 大量重大更新,包括控制面组件重新回归单体,整体变得更简单、更易用,性能提升等等。 CNCF 2019 年度调查报告发布 其中包含了几条重要信息: Cloud Native 社区项目在生产环境中应用成为新常态,超过 50% 的 Cloud Native 项目在生产中应用; Service Mesh 真正进入生产实践,超过 18% 的受访者表示已经在生产环境中使用 Service Mesh; Serverless 技术正逐渐成为主流,超过 40% 的受访者表示在使用 Serverless 技术; 容器在生产环境中的使用显著提升,相比于 2018 年的 73% 上升到了 84%; 越来越多的应用开始通过 CI/CD 工具自动发布。 附:报告 pdf 下载链接 OCI 完成
- 下一篇
nest.js 7.0.0 发布,第三大node.js 框架
nest.js 是目前star 仅次于koa 和 express 的node.js 框架,也是使用最多的后端 ts 框架。 特征 common:使用自动转换基元(数字,布尔值)ValidationPipe 通用添加ParseArrayPipe和ParseBoolPipe#4113 核心:按路径排除中间件 核心:传递ExecutionContext给自定义装饰器#3070 改进之处 核心:使内置异常可序列化#3053 核心:标准化 http 异常架构#4045 微服务:引入更多描述性微服务通道#3040 微服务:更多轻量级数据包(请求/响应)#3071 其他 常见:移除不推荐使用的@ReflectMetadata装饰器 graphql:内置代码优先支持CLI 插件nestjs / graphql#634 突破性变化 在此处阅读更多信息https://docs.nestjs.com/migration-guide
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- MySQL8.0.19开启GTID主从同步CentOS8
- 设置Eclipse缩进为4个空格,增强代码规范
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- Hadoop3单机部署,实现最简伪集群
- CentOS8安装Docker,最新的服务器搭配容器使用
- Docker快速安装Oracle11G,搭建oracle11g学习环境