首页 分享 前端必备技能:全面解析 Token 在 Web 开发中的应用

前端必备技能:全面解析 Token 在 Web 开发中的应用

来源:花匠小妙招 时间:2024-12-07 18:48

对于许多人来说,Token依然是一个模糊的概念:它是如何工作的?为什么它如此重要?它和JWT(JSON Web Token)又有什么关系?如果你也曾对这些问题产生过好奇,那这篇文章将带你深入了解前端开发中的 Token 机制,解锁身份认证的背后秘密。

目录

初识Token

初识JWT

无感刷新

初识Token

        token是什么:token的意思是”令牌“,是服务端生成的一串字符串作为客户端进行请求的一个标识,当用户第一次登录后,服务器生成一个token并将此token返回给客户端,以后客户端只需带上整个token前来请求数据即可,无需再次带上用户名和密码,简单的token由以下三部分组成:

1)uid:用户唯一的身份标识

2)time:当前时间的时间戳

3)sign:签名—将请求URL、时间戳、uid进行一定的算法加密

token进行身份验证的流程大致如下:

        token的优势:与传统的cookie和session认证方式相比,token具有一系列显著的优势,以下是token相较于cookie和session的主要优势:

1)无状态

        token是无状态的,意味着服务器不需要存储任何关于用户会话的信息,每次请求都携带自包含的token且其内部包含了用户的所有认证信息。

        cookie/session通常需要服务器存储用户的会话状态,服务器必须维持一个会话存储,这种状态管理增加了服务器的负担。

2)跨域支持

        token不依赖浏览器的Same-Origin Policy,可以跨域传递。

        cookie/session通常受限于同源策略,跨域请求时浏览器需要做额外的配置才能传递cookie,如果没有正确设置可能会导致跨域问题。

3)适合移动端与多平台

        token适用于各种客户端,不仅限于浏览器还包括移动端应用或桌面应用等。

        cookie/session主要依赖浏览器的存储机制,在非浏览器环境中使用会受限,通常需要额外的处理。

4)避免跨站请求伪造(CSRF)攻击

        token是作为HTTP请求头中的Authorization字段传递的,而不是通过cookie自动附加到请求中的,因此它不容易受到 CSRF(跨站请求伪造)攻击。

5)灵活的过期和刷新机制

        token通常会嵌入过期时间允许对token的生命周期进行精确控制,一旦过期客户端可以通过刷新机制来获得新的认证令牌,而不需要重新登录。

        cookie/session通常依赖于服务器的会话过期时间,客户端和服务器之间需要保持会话状态,若过期用户通常需要重新登录,刷新机制不像token那么灵活。

6)安全性

        token可以被加密或签名,保证传输过程中数据的完整性和安全性,即使被截获,只要没有解密或签名密钥攻击者也无法篡改其中的数据。

        cookie/session虽然可以设置HttpOnly和Secure属性来增强安全性,但其本身依赖于浏览器的安全机制可能受到 XSS(跨站脚本攻击)的影响。

        token登录流程:前端使用token进行登录的流程通常如下:

1)用户提交登录请求:用户在前端页面上输入用户名和密码,并提交登录表单。

fetch('/api/login', {

method: 'POST',

headers: {

'Content-Type': 'application/json',

},

body: JSON.stringify({

username: 'user',

password: 'password',

}),

})

.then(response => response.json())

.then(data => {

});

2)后端验证用户信息:后端收到登录请求后验证用户名和密码是否正确,如果验证成功后端生成一个token并将其返回给前端,该token通常包含了用户的信息(如用户 ID、角色等),并且在一定时间内有效。

const jwt = require('jsonwebtoken');

const secretKey = 'yourSecretKey';

const token = jwt.sign(

{ userId: user.id, role: user.role },

secretKey,

{ expiresIn: '1h' }

);

res.json({ token });

3)前端保存token:前端接收到后端返回的token后通常会将其保存在浏览器的存储中,常见的存储方式有:LocalStorage、SessionStorage和Cookie。

localStorage.setItem('token', data.token);

document.cookie = `token=${data.token}; path=/; secure; HttpOnly`;

4)使用token访问受保护资源:在后续的请求中前端会将token附加到HTTP请求的Authorization头部,以便后端可以验证该请求是否授权。

const token = localStorage.getItem('token');

fetch('/api/protected-resource', {

method: 'GET',

headers: {

'Authorization': `Bearer ${token}`,

},

})

.then(response => response.json())

.then(data => {

});

 5)后端验证token:后端在接收到带有token的请求后会验证该token的有效性,常见的验证方式包括:检查token是否存在、是否已经过期、是否合法。

const jwt = require('jsonwebtoken');

const secretKey = 'yourSecretKey';

const token = req.headers['authorization']?.split(' ')[1];

if (!token) {

return res.status(401).json({ message: 'Token not provided' });

}

jwt.verify(token, secretKey, (err, decoded) => {

if (err) {

return res.status(401).json({ message: 'Invalid or expired token' });

}

req.user = decoded;

next();

});

6)token过期与刷新:如果token过期后端会返回一个错误提示(如 401 Unauthorized),前端可以通过以下方式处理,提供刷新token的机制,在token过期时前端可以发送Refresh Token请求来获取新的Access Token;如果没有使用刷新token,用户需要重新登录以获得新的token。

fetch('/api/refresh-token', {

method: 'POST',

headers: {

'Content-Type': 'application/json',

},

body: JSON.stringify({

refreshToken: localStorage.getItem('refreshToken'),

}),

})

.then(response => response.json())

.then(data => {

localStorage.setItem('token', data.newToken);

});

7)登出:当用户登出时,前端需要清除存储的 Token。

localStorage.removeItem('token');

初识JWT

        JWT(JSON Web Token):是一种特定格式的token,它是基于json的开放标准用于在网络应用环境中安全地传输声明(如用户身份、权限等信息),token是一个抽象的概念,可以指代任何形式的认证令牌,而JWT是一种特定类型的token,它采用json格式,并且具有标准化的结构,可以用于身份验证和数据传输,其主要包含以下三部分:

1)Header(头部):描述token的类型(通常是JWT)和使用的签名算法(如HMAC SHA256或RSA)。

2)Payload(负载):存放声明通常是用户身份信息、过期时间等,JWT可以通过此部分传递一些必要的信息。

3)Signature(签名):用于验证JWT的来源和数据完整性,它是Header和Payload加密后的结果,确保token没有被篡改。

        JWT工作原理:用户的信息通过token字符串的形式保存在客户端浏览器当中,服务器通过还原token字符串的形式来认证用户的身份,如下图所示:

        JWT使用方式:客户端收到服务器返回的JWT之后通常会将它存储在localStorage或sessionStorage中,此后客户端每次与服务器通信都要带上这个JWT字符串,从而进行身份认证,推荐的做法就是把JWT放在HTTP请求的Authorization字段中,格式如下:

Authorization: Bearer <token>

这里我们可以借助node中的express框架来简单实现以下,终端执行如下命令安装JWT相关的包:

1)jsonwebtoken:用于生成JWT字符串

2)express-jwt:用于将JWT字符串解析还原成JSON对象

npm install jsonwebtoken express-jwt

const jwt = require("jsonwebtoken")

const expressJWT = require('express-jwt')

为了保证JWT字符串的安全性防止JWT字符串在网络传输过程中被别人破解,我们需要专门定义一个用于加密和解密的secret密钥:

1)当生成JWT字符串的时候,需要使用secret密钥对用户的信息进行加密,最终得到加密好的JWT字符串

2)当把JWT字符串解析还原成JSON对象的时候,需要使用secret密码进行解密

const secret = "secret 010 020"

调用jsonwebtoken包提供的sign()方法,将用户的信息加密成JWT字符串响应给客户端:

app.post('/api/login', (req, res) => {

res.send({ status: 200, token: jwt.sign({ name: 'admin' }, secret, { expireIn: '30s' })})

})

客户端每次在访问那些有权限接口的时候,都需要主动通过请求头中的Authorization字段将token字符串发送到服务器进行身份认证,此时服务器可以通过express-jwt这个中间件,自动将客户端发送过来的Token 解析还原成JSON 对象:

app.use(expressJWT({ secret: secrect }).unless({ path: [/^/api/login/, /^/api//] }))

当express-jwt这个中间件配置成功之后,即可在那些有权限的接口中使用req.user对象来访问从JWT字符串中解析出来的用户信息了,示例代码如下:

app.get('/api/admin', (req, res) => {

res.send({ status: 200, message: 'admin', data: req.user })

})

当使用express-jwt解析token字符串时,如果客户端发送过来的token字符串过期或不合法,会产生一个解析失败的错误影响项目的正常运行,我们可以通过express的错误中间件,捕获这个错误并进行相关的处理,示例代码如下:

app.use((err, req, res, next) => {

if (err.name === 'UnauthorizedError') {

res.status(401).send({ status: 401, message: 'token解析失败' })

} else {

res.status(500).send({ status: 500, message: '服务器内部错误' })

}

})

无感刷新

接下来开始实现token的无感刷新,下面这段代码的核心目的是自动刷新Access Token,从而确保在token过期或失效时用户能够继续进行API请求,而无需人工干预,如下所示:

let isRefreshing = false;

let requests = [];

axiosInstance.interceptors.response.use(

(res) => res,

async (err) => {

if (err.response && err.response.status === 401) {

const originalRequest = err.config;

if (isRefreshing) {

return new Promise((resolve) => {

requests.push((token) => {

originalRequest.headers['Authorization'] = `Bearer ${token}`;

resolve(axiosInstance(originalRequest));

});

});

}

isRefreshing = true;

try {

const { access_token } = await refreshToken();

if (access_token) {

axiosInstance.defaults.headers.common['Authorization'] = `Bearer ${access_token}`;

requests.forEach((cb) => cb(access_token));

requests = [];

originalRequest.headers['Authorization'] = `Bearer ${access_token}`;

return axiosInstance(originalRequest);

}

throw err;

} catch (e) {

return Promise.reject(e);

} finally {

isRefreshing = false;

}

}

return Promise.reject(err);

}

);

这种设计非常适合使用JWT或类似认证机制的应用程序,尤其是在前后端分离的Web应用中确保用户在token过期后仍能无缝访问接口,其主要特点是:

1)自动检测401错误,并自动处理token刷新。

2)同时处理多个请求,避免重复刷新token。

3)支持刷新失败的处理,保证系统稳定性。

相关知识

从前端到后端——完整的Web开发指南
快速上手web前端开发(超详细教程)
web前端开发爱尚鲜花.rar资源
「职位对比」花儿绽放 前端开发工程师怎么样
【QT教程】QT6 Web开发入门 QT Web
移动应用开发定位
10大优秀的移动Web应用程序开发框架推荐
响应式婚礼网站:前端开发实战指南
HTML+CSS+JavaScript美食博客网页制作教程:从零开始,超详细代码解析与完整示例,适合初学者!
Python Web开发(详细教程)

网址: 前端必备技能:全面解析 Token 在 Web 开发中的应用 https://www.huajiangbk.com/newsview948822.html

所属分类:花卉
上一篇: 2023版完整版web前端学习路
下一篇: web前端开发工程师工作的岗位职

推荐分享