简述token和如何使用token

news2024/10/8 11:35:26

一、什么是token(理论)

  • 解决http短连接,无状态管理的问题。

  • Jeb web token(JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开发标准,JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些科瓦ide其他业务逻辑所必须的声明信息。

👍传统的session认证 请添加图片描述

基于session认证所显露的问题

Session:每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言,seesion都是保存在内存中,而随着认证用户的增多,服务器的开销会明显增大。

扩展性:用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求这台服务器上,这个才能拿到授权,这样在分布式的应用上,相应的限制了负载均衡的能力,这也意味着限制了应用的扩展能力。

CSRF:因为基于cookie来进行用户识别的,cookie如果截获,用户就会很容易受到跨站请求伪造的攻击。

👍基于token认证的鉴权机制

基于token的鉴权机制不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

token鉴权流程如下

请添加图片描述

优点:

  • 因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
  • JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息
  • 便于传输,jwt的构成非常简单,就是一个字符串,字节占用很小,所以它是。
  • 非常便于传输的,它不需要在服务器保存会话信息,所以易于应用的扩展。

👍JWT的结构

请添加图片描述

JWT 是由三段信息构成的,将三段信息文本用.链接一起就构成了JWT字符串,就像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

  • 第一部分我们称它为头部(header)
  • 第二部分我们称其为载荷(payload)
  • 第三部分是签证(signature)

header

jwt的头部承载着两部分的信息:

  • 声明类型
  • 声明加密的算法(通常直接使用HMAC SHA256

完整的头部就像下面这样的JSON


{
   'typ':'JWT',
   'alg':'HS256'
}

将头部进行base64加密(该加密是可以对称解密的),构成了第一部分。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 base64加密后变成一个完整的字符串。

payload

载荷就是存放有效信息的地方,这个名字是指飞机上承载的货品,有效信息包含三个部分

  • 标准中注册的声明

    • iss:jwt签发者
    • sub:jwt所面向的用户
    • aud:接收jwt的一方
    • exp:jwt的过期时间
    • nbf:定义在什么时间之前,这过期时间必须大于签发时间
    • iat:jwt的签发时间
    • jti:jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
  • 公共的声明

    • 公共的声明可以添加任何信息,一般添加用户的相关信息或其他业务需要的必要信息,但不建议添加敏感信息,因为该部分客户端可解密。
  • 私有的声明

  • 例如,定义一个payload json:

       {
       	"sub":"1234567890",
       	"name""john Doe",
       	admin:true
       }
    

然后将其进行base64加密,得到jwt的第二部分

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

signature

jwt 的第三部分是一个签证信息,这个签证信息由三部分组成

  • header(base64后的)
  • payload(base64后的)
  • secret

这个部分需要base64加密后的header和base64加密后的payload使用,使用.连接组成的字符串,然后通过header声明的加密方式加密secret组合加密,然后就构成了jwt的第三部分。


var encodedString=base64UrlEncode(header)+'.'+base64UrlEncode(payload)
var  signature = HMACHA256(encodedString,'secret')

将这三部分用 . 连接成一个完整的字符串,构成了最终的jwt:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIi wiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

👍客户端获取到token之后

  • Token

    token是服务端生成的一串字符串,以做客户端进行请求的一个令牌,当第一次登录后,服务器生成一个Token便将此Token返回给客户端,以后客户端只需带上这个token前来请求数据即可,无需再次带上用户名和密码。token可以设置在cookie或者headers中,都可以。

  • 公参

    公共参数,一般放在headers中,让所有的请求都带上这个参数,服务器会对他做一些处理,比如常用的比如:会在headers中设置app的版本,用于服务器进行接口的版本兼容。

  • 客户端对于token的存储方式

    • 存储在webStorage中,每次调用接口都当成一个字段传给后台

    • 存储在cookie中,让他自动发送,缺点就是不能跨域

      • 将token存放在cookie中可以指定 httponly,来防止被Javascript读取,也可以指定secure,来保证token只在HTTPS下传输。缺点是不符合Restful最佳实践,容易受到CSRF攻击。
      • CSRF就是恶意攻击者盗用已经认证过的用户信息,以用户信息名义进行一些操作〈如发邮件、转账、购买商品等等)。由于身份已经认证过,所以目标网站会认为操作都是真正的用户操作的。CSRF并不能拿到用户信息,它只是盗用用户凭证去进行操作。
    • 拿到以后存储在webStorage中,每次调用接口的时候放在HTTP请求头的Authorization字段里

      • 将token存放在webStorage中,可以通过js来访问,这样会导致很容易受到xss攻击,如果js脚本被盗用,攻击者就可以轻易访问你的网站, webStroage作为一种储存机制,在传输过程中不会执行任何安全标准
      • xss攻击是一种注入代码攻击,恶意攻击者在目标网站上注入script代码,当访问者浏览王网站的时候通过执行注入的script代码达到窃取用户信息,盗用用户身份等。

二、如何使用token?(案例)

以下使用两个小demo来简述后端生成token到客户端获取token到携带token去发送请求获取数据的整体流程。

后台服务环境基于node,需要安装的第三方npm包如下

{
  "name": "demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5", 
    "express": "^4.18.2", //web服务框架
    "jsonwebtoken": "^9.0.1", //生成和验证token
    "mysql": "^2.18.1", //数据库
    "svg-captcha": "^1.4.0" //生成验证码
  }
}

👍demo1:模拟前后端生成,获取和验证token

成功获取到token,并且检验成功。
请添加图片描述

前端代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js"></script>
</head>
<body>
    <button id="btn">点我发送请求,认证</button>
    <script>
        btn.addEventListener('click',()=>{
            let config={
                headers:{
                    'Authorizition':localStorage.getItem('token')//从缓存中取
                }
            }
            axios.get('http://localhost:3000/verifytoken',config).then(res=>{
                console.log(res)
            })
        })

        // dom元素加载完就发送请求
        document.addEventListener('DOMContentLoaded',function(res){
            axios.get('http://localhost:3000/gettoken').then((res)=>{
                console.log(res)
                //从res中解析token,并且存在localStorage 供后续请求使用
                let token=res.data.token
                console.log(token)
                localStorage.setItem('token',token) //放到缓存
            })
        })
    </script>
</body>   
</html>

服务端代码(出现的问题和解决的方法)

出现问题
1.跨域问题,
2.客户端请求头设置参数,后端没有处理的问题

请添加图片描述
请添加图片描述
服务端设置响应控制头,cors方法防止跨域 (什么是cors方法?⏩点击此处查看交互专栏里的上一篇文章)


// 设置响应头,cors方法,防止跨域
app.use((req,res,next)=>{
    // 允许任何来源跨域
    res.header('Access-Control-Allow-Origin','*')
    // 如果请求中设置了请求头,那么这个首部是必要的
    res.header('Access-Control-Allow-Headers','*')
    next()
})
app.use(express.static('public'))

结果:成功获取到token

请添加图片描述

整体代码展示

// 模拟 加载页面拿到token,再向后台发请求时验证token

// 生成和验证token
const jwt=require('jsonwebtoken')
// 生成验证码
const captcha=require('svg-captcha')
// 启动web服务的框架
const express=require('express')

// 定义密钥
const key='my key'

// 启动服务
const app=express()

// 设置响应头,cors方法,防止跨域
app.use((req,res,next)=>{
    // 允许任何来源跨域
    res.header('Access-Control-Allow-Origin','*')
    // 如果请求中设置了请求头,那么这个首部是必要的
    res.header('Access-Control-Allow-Headers','*')
    next()
})
app.use(express.static('public'))


// 基于jsonwebtoken模块,生成token,将token返回给客户端
app.get('/gettoken',(req,res)=>{
    // 声明携带的载荷
    let payload={
        name:'dema',
        userId:1003,
        exp:Date.now()/1000+3600*24  // 设置过期时间
    }
    
    // sign方法用于办法token
    let token=jwt.sign(payload,key)
    res.send({
        code:0,
        result:'ok',
        token
    })

})    

// 验证token
app.get('/verifytoken',(req,res)=>{
    // 获取Authorization消息头
    // console.log(req)
    let token=req.headers.authorization
    // 验证token,获取token中存储的payload数据
    jwt.verify(token,key,(err,decoded)=>{
        console.log(err) //若验证失败,则err将不是null
        console.log(decoded)
        res.send('ok')
    })
})

app.listen(3000,()=>{
    console.log('server is running....')
})

👍demo2:获取token,携带token去验证输入的验证码是否正确

实现的步骤

    1. 加载页面,客户端获取token,并存入本地缓存
    1. 加载页面,获取验证码图片并渲染到页面
    1. 客户端再次发送请求,验证码+携带token,如果得到的响应是验证码输入成功,即为验证码验证成功

实现的效果

在这里插入图片描述

前端代码完整展示

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://cdn.bootcss.com/axios/0.19.0-beta.1/axios.min.js"></script>
</head>  
    <input type="text" id="text">
    <div id="img">
     <!-- svg -->
    </div>
    <button id="btn">点我认证</button>
    <script>
        // 验证验证码
        btn.addEventListener('click',()=>{
            let config={
                headers:{
                    'Authorizition':localStorage.getItem('token')//从缓存中取
                }
            }
            
            axios.get('http://localhost:3000/resgister?ucode='+text.value,config).then(res=>{
                console.log(res)
            })
        })

        

        // dom元素加载完就发送请求
        document.addEventListener('DOMContentLoaded',function(res){
            axios.get('http://localhost:3000/gettoken').then((res)=>{
                let token=res.data.token
                localStorage.setItem('token',token) 
                console.log('token',token) 
            })
        })

        // 页面加载完获取验证码
        window.onload=function(){
            axios.get('http://localhost:3000/getcode').then((res)=>{
                 let svg=res.data.svg 
                 console.log('svg',svg)
                 let img=document.getElementById('img')
                 img.innerHTML=svg
            })
        }
    </script>
</body>   
</html>

服务端代码完整展示

// 生成和验证token
const jwt=require('jsonwebtoken')
// 生成验证码
const captcha=require('svg-captcha')
// 启动web服务的框架
const express=require('express')


// 定义密钥
const key='my key'

// 启动服务
const app=express()

// 设置响应头,cors方法,防止跨域
app.use((req,res,next)=>{
    // 允许任何来源跨域
    res.header('Access-Control-Allow-Origin','*')
    // 如果请求中设置了请求头,那么这个首部是必要的
    res.header('Access-Control-Allow-Headers','*')
    next()
})
app.use(express.static('public'))


//模拟redis数据库
let redis={} //模拟redis数据库


// 基于jsonwebtoken模块,生成token,将token返回给客户端

let token

app.get('/gettoken',(req,res)=>{
    // 声明携带的载荷
    let payload={
        name:'dema',
        userId:1003,
        exp:Date.now()/1000+3600*24  // 设置过期时间
    }
    
    // sign方法用于办法token
    token=jwt.sign(payload,key)
    res.send({
        code:0,
        result:'ok',
        token
    })

})    

// 接收请求,返回验证码图片
app.get('/getcode',(req,res)=>{
    // 生成验证码
    let cap=captcha.create() //生成一个验证码图片
    console.log('生成的token',token)
    // token验证成功
    // 缺一步,把正确答案和token做配对存入redis里
    redis[token]=cap.text
    console.log('当前redis',redis)
    res.send({
        svg:cap.data
    })
})

// 验证token,验证验证码是否一致
app.get('/resgister',(req,res)=>{
    // 获取用户输入的验证码
    let ucode=req.query.ucode
    // 从请求头获取token,验证成功,执行后续业务
    let token=req.headers.authorizition
    // 验证token,获取token中存储的payload数据
    jwt.verify(token,key,(err,decoded)=>{
        console.warn(err)
        if(err!=null){// 验证失败
            res.send('刷新重试')
            return
        }
    })
    //token验证成功
    let answer=redis[token]
    if(ucode.toLocaleLowerCase()==answer.toLocaleLowerCase()){
        res.send('验证码输入正确')
    }else{
        res.send('验证码输入错误')
    }
})
 


app.listen(3001,()=>{
    console.log('server is running....')
})

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

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

相关文章

ChatGPT在法律行业的市场潜力

​ChatGPT现在已经成为我们的文字生成辅助工具、搜索引擎助手&#xff0c;许多体验过它的朋友会发现对它越来越依赖&#xff0c;并将其逐渐融入到自己的日常工作、生活。但有一点值得注意&#xff1a;这种人工智能除了技术可行、经济价值可行还要与相关规范即人类普遍的价值观念…

JVM复习(史上最全!!!)

一、JDK、JRE、JVM的区别 JDK: 全称Java Development Kit&#xff0c;是 Java 语言的软件开发工具包&#xff0c;主要用于移动设备、嵌入式设备上的Java应用程序。JDK是整个Java开发的核心。 JRE: JRE&#xff0c;全称Java Runtime Environment&#xff0c;是指Java的运行环境&…

vue3如何封装框架

在Vue 3中&#xff0c;你可以通过创建一个基础的框架来封装一些常用的功能、组件和样式&#xff0c;以便在不同的项目中重复使用。下面是一个简单的步骤来封装一个Vue 3框架&#xff1a; 创建一个新的Vue项目&#xff1a;首先&#xff0c;使用Vue CLI创建一个新的Vue项目。 v…

eam资产管理系统,eam资产管理系统功能介绍

基于固定资产管理系统PDA并结合RFID技术固定资产管理信息系统将固定资产管理、低价值消耗品管理和设备维护融为一体。根据先进的射频识别技术&#xff0c;从资产购买公司到资产退出的整个生命周期&#xff0c;每一个固定资产唯一的条形码资产标签都被赋予了后续管理&#xff0c…

【多模态】23、RO-ViT | 基于 Transformer 的开发词汇目标检测(CVPR2023)

文章目录 一、背景二、方法2.1 基础内容2.2 Region-aware Image-text Pretraining2.3 Open-vocabulary Detector Finetuning 三、效果3.1 细节3.2 开放词汇目标检测效果3.3 Image-text retrieval3.4 Transfer object detection3.5 消融实验 论文&#xff1a;Region-Aware Pretr…

大数据课程D4——hadoop的YARN

文章作者邮箱&#xff1a;yugongshiyesina.cn 地址&#xff1a;广东惠州 ▲ 本章节目的 ⚪ 了解YARN的概念和结构&#xff1b; ⚪ 掌握YARN的资源调度流程&#xff1b; ⚪ 了解Hadoop支持的资源调度器&#xff1a;FIFO、Capacity、Fair&#xff1b; ⚪ 掌握YA…

4090Ti被取消,NVIDIA还要推出新“甜品卡“

不知不觉距离 NVIDIA RTX 40 系显卡发布已快一年&#xff0c;4090 到 4060 从旗舰到甜品也都差不多了。 不过每个男孩子都想要的礼物 - RTX 4090 Ti &#xff0c;至今仅在春晚发布。 从核心架构上来看&#xff0c;RTX 4090 上的 AD 102-300 也确实不是完全体。 仅拥有144组 S…

模拟一个一维排斥场

( A, B )---3*30*2---( 1, 0 )( 0, 1 ) 让网络的输入只有3个节点&#xff0c;AB训练集各由5张二值化的图片组成&#xff0c;让A有6个1&#xff0c;B有4个1&#xff0c;比较迭代次数的顺序。 其中有12组数据 差值结构 迭代次数 全0行 位置 构造平均列 平均列 列排斥能 …

手机照片转换成pdf怎么做?了解这几种方法就可以了

手机照片转换成pdf怎么做&#xff1f;转换照片为PDF的需求在日常生活中很常见。无论是收集有关旅行、家庭或工作的照片&#xff0c;将它们组织成一个PDF文件可以更方便地分享给朋友或同事。那么下面就给大家分享几个手机照片转换成pdf的方法。 虽然有多种软件和工具可以将照片转…

八大排序算法--直接插入排序(动图理解)

目录 直接插入排序 概念 算法思路 动画演示 代码如下 复杂度分析 时间复杂度测试 运行结果 完整代码 创作不易&#xff0c;如果本篇博客对您有一定的帮助&#xff0c;大家记得留言点赞哦。 直接插入排序 概念 直接插入排序是插入排序的一种。把待排序的数字按大小逐个插…

【SpringBoot】笔记2

文章目录 45、web实验-抽取公共页面46、web实验-遍历数据与页面bug修改47、视图解析-【源码分析】-视图解析器与视图[暂时没看]48、拦截器-登录检查与静态资源放行49、拦截器-【源码分析】-拦截器的执行时机和原理50、文件上传-单文件与多文件上传的使用51、文件上传-【源码流程…

jQuery如何获取动态添加的元素

jQuery如何获取动态添加的元素 使用 on()方法 本质上使用了事件委派&#xff0c;将事件委派在父元素身上 自 jQuery 版本 1.7 起&#xff0c;on() 方法是 bind()、live() 和 delegate() 方法的新的替代品&#xff0c;但是由于on()方法必须有事件&#xff0c;没有事件时可选择de…

elasticsearch 官方优化建议

.一般建议 a.不要返回过大的结果集。这个建议对一般数据库都是适用的&#xff0c;如果要获取大量结果&#xff0c;可以使用search_after api&#xff0c;或者scroll &#xff08;新版本中已经不推荐&#xff09;。 b.避免大的文档。 2. 如何提高索引速度 a.使用批量请求。为了…

HCIP中期考试实验

考试需求 1、该拓扑为公司网络&#xff0c;其中包括公司总部、公司分部以及公司骨干网&#xff0c;不包含运营商公网部分。 2、设备名称均使用拓扑上名称改名&#xff0c;并且区分大小写。 3、整张拓扑均使用私网地址进行配置。 4、整张网络中&#xff0c;运行OSPF协议或者BGP…

Java -接口

接口 基本介绍 接口就是给出一些没有实现的方法&#xff0c;封装到一起&#xff0c;到某个类要使用的时候&#xff0c;再根据具体情况把这些方法写出来。 class 类名 implements 接口{自己属性;自己方法;必须实现的接口的抽象方法; // 只需要重写抽象方法即可 }接口中的方法…

【腾讯云 Cloud Studio 实战训练营】永不宕机的IDE,Coding Everywhere

【腾讯云 Cloud Studio 实战训练营】永不宕机的IDE&#xff0c;随时随地写代码&#xff01; 写在最前视频讲解&#xff1a;Cloud Studio活动简介何为腾讯云 Cloud Studio?Cloud Studio简介免费试用&#xff0c;上手无忧Cloud Studio 特点及优势云端开发多种预制环境可选metawo…

C# 定时器改进版

一、概述 前不久写了一篇名为 “C# 定时器封装版” 的帖子&#xff0c;它是用的定时器 事件订阅 的方式完成的&#xff0c;虽然可以实现需求&#xff0c;但是它有个缺点&#xff0c;就是定时器的执行的间隔时间只能用固定的时间&#xff0c;假设你想每个事件有自己的单独间隔…

HEVC 速率控制(码控)介绍

视频编码速率控制 速率控制&#xff1a; 通过选择一系列编码参数&#xff0c;使得视频编码后的比特率满足所有需要的速率限制&#xff0c;并且使得编码失真尽量小。速率控制属于率失真优化的范畴&#xff0c;速率控制算法的重点是确定与速率相关的量化参数&#xff08;Quantiz…

医学影像PACS系统源码:多功能服务器和阅片系统

PACS系统是以最新的IT技术为基础&#xff0c;遵循医疗卫生行业IHE/DICOM3.0和HL7标准&#xff0c;开发的多功能服务器和阅片系统。通过简单高性能的阅片功能&#xff0c;支持繁忙时的影像诊断业务&#xff0c;拥有保存影像的院内Web传输及离线影像等功能&#xff0c;同时具有备…

Python中的列表怎么排序

目录 Python中的列表是什么 python怎么给列表排序 给列表排序需要注意什么 总结 Python中的列表是什么 在Python中&#xff0c;列表&#xff08;List&#xff09;是一种有序且可变的数据类型。它允许存储多个元素&#xff0c;并且可以根据需要进行修改。 列表使用方括号&…