无感知刷新Token示例简析

目录
  • 引言
  • Token认证的原理
  • 什么是无感知刷新Token
  • 实现步骤
    • 步骤一:获取Access Token和Refresh Token
    • 步骤二:在请求中携带Access Token
    • 步骤三:拦截401 Unauthorized响应
    • 步骤四:服务器处理Refresh Token请求
    • 步骤五:设置定时刷新Token
  • 安全性考虑

引言

在前后端分离的应用中,使用Token进行认证是一种较为常见的方式。但是,由于Token的有效期限制,需要不断刷新Token,否则会导致用户认证失败。为了解决这个问题,可以实现无感知刷新Token的功能,本文将介绍如何实现无感知刷新Token。

Token认证的原理

在Web应用中,常见的Token认证方式有基于Cookie和基于Token的认证。基于Cookie的认证方式是将认证信息保存在Cookie中,每次请求时将Cookie发送给服务器进行认证;而基于Token的认证方式是将认证信息保存在Token中,每次请求时将Token发送给服务器进行认证。

在基于Token的认证方式中,客户端将认证信息保存在Token中,而不是保存在Cookie中。在认证成功后,服务器将生成一个Access Token和一个Refresh Token,并将它们返回给客户端。Access Token用于访问受保护的API,Refresh Token用于获取新的Access Token。

什么是无感知刷新Token

无感知刷新Token是指,在Token过期之前,系统自动使用Refresh Token获取新的Access Token,从而实现Token的无感知刷新,用户可以无缝继续使用应用。

在实现无感知刷新Token的过程中,需要考虑以下几个方面:

  • 如何判断Token是否过期?
  • 如何在Token过期时自动使用Refresh Token获取新的Access Token?
  • 如何处理Refresh Token的安全问题?

下面将介绍如何实现无感知刷新Token的具体步骤。

实现步骤

步骤一:获取Access Token和Refresh Token

在认证成功后,需要将Access Token和Refresh Token发送给客户端。Access Token用于访问受保护的API,Refresh Token用于获取新的Access Token。可以使用JWT(JSON Web Token)或OAuth2(开放授权)等方式实现认证。

在JWT中,可以使用如下代码生成Access Token和Refresh Token:

const accessToken = jwt.sign({userId: '123'}, 'ACCESS_TOKEN_SECRET', {expiresIn: '15m'});
const refreshToken = jwt.sign({userId: '123'}, 'REFRESH_TOKEN_SECRET', {expiresIn: '7d'});

步骤二:在请求中携带Access Token

在每个需要认证的API请求中,需要在请求头中携带Access Token,如下所示:

GET /api/user HTTP/1.1
Host: example.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

在前端中,可以使用Axios等库设置请求头:

axios.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;

步骤三:拦截401 Unauthorized响应

在服务器返回401 Unauthorized响应时,说明Access Token已经过期,需要使用Refresh Token获取新的Access Token。可以使用Axios拦截器或Fetch API的中间件实现拦截。

在Axios中,可以使用如下代码实现拦截器:

axios.interceptors.response.use(response => {
  return response;
}, error => {
  const originalRequest = error.config;
  if (error.response.status === 401 && !originalRequest._retry) {
    originalRequest._retry = true; //防止无限调用
    return axios.post('/api/refresh_token', {refreshToken})
      .then(response => {
        const { access_token, refresh_token } = response.data;
        localStorage.setItem('access_token', access_token);
        localStorage.setItem('refresh_token', refresh_token);
        axios.defaults.headers.common['Authorization'] = `Bearer ${access_token}`;
        originalRequest.headers.Authorization = `Bearer ${access_token}`;
        return axios(originalRequest);
      });
  }
  return Promise.reject(error);
});

在Fetch中,可以使用如下代码实现中间件:

function authMiddleware(request) {
  const access_token = localStorage.getItem('access_token');
  if (access_token) {
    request.headers.set('Authorization', `Bearer ${access_token}`);
  }
  return request;
}
function tokenRefreshMiddleware(response) {
  if (response.status === 401) {
    const refreshToken = localStorage.getItem('refresh_token');
    return fetch('/api/refresh_token', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ refreshToken })
    }).then(response => {
      if (response.ok) {
        return response.json();
      }
      throw new Error('Refresh Token failed');
    }).then(data => {
      localStorage.setItem('access_token', data.access_token);
      localStorage.setItem('refresh_token', data.refresh_token);
      return Promise.resolve('refreshed');
    }).catch(error => {
      localStorage.removeItem('access_token');
      localStorage.removeItem('refresh_token');
      return Promise.reject(error);
    });
  }
  return Promise.resolve('ok');
}
fetch('/api/user', {
  method: 'GET',
  headers: {
    'Content-Type': 'application/json'
  },
  middleware: [authMiddleware, tokenRefreshMiddleware]
}).then(response => {
  console.log(response);
}).catch(error => {
  console.error(error);
});

在上述代码中,使用Axios或Fetch拦截器拦截401 Unauthorized响应,如果发现Access Token已经过期,则发送Refresh Token请求获取新的Access Token,并将新的Access Token设置到请求头中,重新发送请求。

步骤四:服务器处理Refresh Token请求

在服务器端,需要编写API处理Refresh Token请求,生成新的Access Token,并返回给客户端。

JWT中,可以使用如下代码生成新的Access Token:

const accessToken = jwt.sign({userId: '123'}, 'ACCESS_TOKEN_SECRET', {expiresIn: '15m'});

在刷新Token时,需要验证Refresh Token的合法性,可以使用如下代码验证Refresh Token:

try {
  const payload = jwt.verify(refreshToken, 'REFRESH_TOKEN_SECRET');
  const accessToken = jwt.sign({userId: payload.userId}, 'ACCESS_TOKEN_SECRET', {expiresIn: '15m'});
  const refreshToken = jwt.sign({userId: payload.userId}, 'REFRESH_TOKEN_SECRET', {expiresIn: '7d'});
  res.json({access_token: accessToken, refresh_token: refreshToken});
} catch (err) {
  res.sendStatus(401);
}

在上述代码中,使用JWT的verify方法验证Refresh Token的合法性,如果验证成功,则生成新的Access Token和Refresh Token,并返回给客户端。

步骤五:设置定时刷新Token

为了避免Access Token过期时间太长,可以设置定时刷新Token的功能。可以使用定时器或Web Workers等方式实现定时刷新Token。在每次刷新Token时,需要重新获取新的Access Token和Refresh Token,并保存到客户端。

function refreshToken() {
  const refreshToken = localStorage.getItem('refresh_token');
  axios.post('/api/refresh_token', {refreshToken})
    .then(response => {
      const { access_token, refresh_token } = response.data;
      localStorage.setItem('access_token', access_token);
      localStorage.setItem('refresh_token', refresh_token);
      axios.defaults.headers.common['Authorization'] = `Bearer ${access_token}`;
    })
    .catch(error => {
      console.error(error);
    });
}
setInterval(refreshToken, 14 * 60 * 1000); // 每14分钟刷新Token

在上述代码中,使用定时器每14分钟刷新Token。在刷新Token成功后,将新的Access Token和Refresh Token保存到客户端,并将新的Access Token设置到请求头中。

安全性考虑

在实现无感知刷新Token的过程中,需要考虑到Refresh Token的安全性问题。因为Refresh Token具有长期的有效期限,一旦Refresh Token被泄露,攻击者就可以使用Refresh Token获取新的Access Token,从而绕过认证机制,访问受保护的API。

为了增加Refresh Token的安全性,可以考虑以下几种措施:

  • 将Refresh Token保存在HttpOnly Cookie中,可以避免在客户端被JavaScript获取;
  • 对Refresh Token进行加密或签名,可以增加其安全性。
  • 将Refresh Token保存在后端,前端通过接口和后端交互,实现刷新Access Token。

以上就是无感知刷新Token的详细内容,更多关于无感知刷新Token的资料请关注我们其它相关文章!

(0)

相关推荐

  • Vue前端登录token信息验证功能实现

    用户在首次访问网站时,应在登录页面填写账号密码,前端携带用户信息向服务器请求. 1.服务器验证用户信息 验证失败:给前端响应数据 验证通过:对该用户创建token,并以响应数据返回给前端 2.前端接受后端响应的数据 错误信息:提示错误消息 正确信息:页面进行跳转至首页,同时保存token(可以保存在cookie或localstorage) 3.用户点击某功能模块的触发请求(比如某功能有权限设置或是是否需要token) 利用路由守卫beforeEach() 将保存的token添加至请求拦截器的请求

  • 如何让每个Http请求都自动带上token

    目录 让每个Http请求都自动带上token 1.将token放到cookie中 2.将token放到某个http请求的header中 3.使用哪种方式更好呢? token一般存放在哪里 Token是什么? Token存放位置 Token 放在 cookie.localStorage.sessionStorage中的不同点? 总结 让每个Http请求都自动带上token 1.将token放到cookie中 这样每个http请求就都可以带上token信息了. access_token="eyJhb

  • vue项目中存储与使用后端传递过来的token

    目录 前言 后端关于token的设置 前端页面取用token token存储 前端使用token实现路由守卫 请求拦截和响应拦截 总结 前言 以前一直都是在postman中测试验证token,现在用在真正的项目中,记录一下在vue项目中token的存储和使用 后端关于token的设置 app.js中需要设置token的地方 const expressJWT = require('express-jwt') const app = express(); const config = require

  • node.js配置Token验证的2种方式总结

    目录 1. 生成Token jwt passport实现生成和验证Token 2. 使用passpport-jwt||passport验证Token 总结 1. 生成Token jwt passport实现生成和验证Token jsonwebtoken 1.安装 npm i jsonwebtoken 2.引入 const jwt = require('jsonwebtoken')s 3.定义规则 const rule = {<!--{C}%3C!%2D%2D%20%2D%2D%3E--> id

  • 无感知刷新Token示例简析

    目录 引言 Token认证的原理 什么是无感知刷新Token 实现步骤 步骤一:获取Access Token和Refresh Token 步骤二:在请求中携带Access Token 步骤三:拦截401 Unauthorized响应 步骤四:服务器处理Refresh Token请求 步骤五:设置定时刷新Token 安全性考虑 引言 在前后端分离的应用中,使用Token进行认证是一种较为常见的方式.但是,由于Token的有效期限制,需要不断刷新Token,否则会导致用户认证失败.为了解决这个问题,

  • 如何实现无感刷新token

    目录 1.需求 方法一 方法二 方法三 2.实现 3.问题解决 问题一:如何防止多次刷新token 问题二:同时发起两个或者两个以上的请求时,其他接口怎么解决 前言: 最近在做需求的时候,涉及到登录token,产品提出一个问题:能不能让token过期时间长一点,我频繁的要去登录. 前端:后端,你能不能把token 过期时间设置的长一点. 后端:可以,但是那样做不安全,你可以用更好的方法. 前端:什么方法? 后端:给你刷新token的接口,定时去刷新token 前端:好,让我思考一下 1.需求 当

  • C#多线程及同步示例简析

    60年代,在OS中能拥有资源和独立运行的基本单位是进程,然而随着计算机技术的发展,进程出现了很多弊端,一是由于进程是资源拥有者,创建.撤消与切换存在较大的时空开销,因此需要引入轻型进程:二是由于对称多处理机(SMP)出现,可以满足多个运行单位,而多个进程并行开销过大. 因此在80年代,出现了能独立运行的基本单位--线程(Threads).        线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元.一个标准的线程由线程ID,当前指令指针(P

  • GoLang jwt无感刷新与SSO单点登录限制解除方法详解

    目录 前言 为什么使用JWT Cookie和Session token (header.payload.signature) token 安全性 基于token安全性的处理 客户端与服务端基于无感刷新流程图 golang实现atoken和rtoken 颁发token 校验token 无感刷新token 完整实现代码 SSO(Single Sign On)单用户登录以及无感刷新token 实现思路 实战代码 小结 前言 为什么使用JWT Jwt提供了生成token以及token验证的方法,而tok

  • 详细聊聊前端如何实现token无感刷新(refresh_token)

    目录 关于无感刷新的理解: 下面是关于使用vuex来实现的写法 axios工具函数(请求拦截器与响应拦截器) 总结 关于无感刷新的理解: 实现token无感刷新对于前端来说是一项非常常用的技术,其本质是为了优化用户体验,当token过期时不需要用户跳回登录页重新登录,而是当token失效时,进行拦截,发送刷新token的ajax,获取最新的token进行覆盖,让用户感受不到token已经过期,今天写了一个简陋的demo,给大家提供一个参考 下面是关于使用vuex来实现的写法 步骤: 1.先搭好a

  • axios如何利用promise无痛刷新token的实现方法

    需求 最近遇到个需求:前端登录后,后端返回token和token有效时间,当token过期时要求用旧token去获取新的token,前端需要做到无痛刷新token,即请求刷新token时要做到用户无感知. 需求解析 当用户发起一个请求时,判断token是否已过期,若已过期则先调refreshToken接口,拿到新的token后再继续执行之前的请求. 这个问题的难点在于:当同时发起多个请求,而刷新token的接口还没返回,此时其他请求该如何处理?接下来会循序渐进地分享一下整个过程. 实现思路 由于

  • js无痛刷新Token的实现

    这个需求场景很常见,几乎很多项目都会用上,之前项目也实现过,最近刚好有个项目要实现,重新梳理一番. 需求 对于需要前端实现无痛刷新Token,无非就两种: 请求前判断Token是否过期,过期则刷新 请求后根据返回状态判断是否过期,过期则刷新 处理逻辑 实现起来也没多大差别,只是判断的位置不一样,核心原理都一样: 判断Token是否过期 没过期则正常处理 过期则发起刷新Token的请求 拿到新的Token保存 重新发送Token过期这段时间内发起的请求 重点: 保持Token过期这段时间发起请求状

  • 游戏和服备忘问题简析

    今天游戏和服,发现数据备份好后,导入不到目标库中, mysql -h10.66.125.733 --port 3306 -u sanda -pX12234455 --default-character-set=utf8 sanda_s10 < /data/mysql/8/user.sql 返回 ERROR 1044 (42000) at line 20: Access denied for user 'sanda'@'10.105.%' to database 'sanda_s10' 经查缺少了

  • shp2sqlserver 用法简析

    shp2sqlserver用法简析 官方说明: shp2sqlserver is a command line tool for loading shapefiles into Microsoft SQL Server 2008. It is modeled after PostGIS's shp2pgsql, except that it loads directly into the database instead of writing sql to stdout. http://code

  • 基于Oracle的面向对象技术入门基础简析开发者网络Oracle

    正在看的ORACLE教程是:基于Oracle的面向对象技术入门基础简析开发者网络Oracle.一.概述 对象是Oracle8i以上版本中的一个新的特性,对象实际是对一组数据和操作的封装,对象的抽象就是类.在面向对象技术中,对象涉及到以下几个重要的特性:  封装性 通过对数据和操作的封装,将用户关心的数据和操作暴露出来作为接口,其他数据和操作则隐藏到对象内部,这样便于用户使用和维护.  继承性 对象具有继承性,通过这一特性可以增强程序的可扩展性,适合大型项目的开发.  多态性 同一操作在运行时刻有

随机推荐