Nodejs 在实战中的校验用户信息(JWT、localStorage、Cookie)
qiyuwang 2024-10-31 15:51 16 浏览 0 评论
本文分别站在了客户端(reactjs)与服务端(nodejs)的角度,总结了整个用户校验过程各自的操作。
一 概念明晰
1.1 localStorage 和 Cookie
都是存储数据的方式
- localStorage:储存在客户端(浏览器)本地
- Cookie:存储在服务端,安全性更高。(是一个 HTTP 请求标头,由服务器通过 Set-Cookie 设置,存储到客户端的 HTTP cookie)
1.2 Token/JWT 和 SessionId
都是用户信息标识
- Token:一个通用术语,是代表用户身份的字符串。它通常由服务器在用户成功登录后生成,并在用户进行后续请求时发送给服务器以验证其身份。
- JWT(JSON Web Token):一种特殊的 Token。由三部分组成的字符串:Header(令牌类型和签名算法)、Payload(用户信息)、Signature组成
- SessionId:用来识别和追踪用户会话的一串唯一的字符
本文主要讲JWT
二 JWT的生成与使用
jwt.io/
- 安装JWT库
npm i jsonwebtoken
2.登录时生成JWT
const jwt = require('jsonwebtoken');
const login = async (req, res) => {
// ...登录成功后
const token = jwt.sign(
{ userId: <userId>, username: <username> }, // 填入想存储的用户信息
process.env.JWT_SECRET, // 秘钥,可以为随机一个字符串
{
expiresIn: "7d", // 其他选项,如过期时间
}
);
// ...
};
接着就是选择存储方式:1.将token返回到客户端让客户端存储在localStorage;2.将token存储在服务端Cookie
3.调用其他请求时验证Token
// 验证的中间件
const authToken = async (req, res, next) => {
// ... 根据存储方式拿到token
const token = "your_token"
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET); // 传入token和秘钥
// 拿到解出来的 { userId, username }
// ... 进一步从数据库中判断这个用户信息是否存在
// 将信息挂载req.user中供后续接口使用
req.user = { userId, username, ... };
next();
} catch (error) {
res.status(401).json({msg:"用户验证失败"})
}
};
三 应用场景
- JWT & localStorage
- JWT & Cookie
3.1 存储在localStorage
- 服务端:将token返回给客户端
const login = async (req, res) => {
// ...登录成功后
// ...生成完token
const token = "your_token"
// 将token返回给客户端
res.status(StatusCodes.OK).json({
msg: '登录成功',
token,
});
};
2.客户端:将token存储到localStorage,并在后续请求中将token发送给服务端
为了方便管理,这里简单封装了下aixos:
import toast from 'react-hot-toast';
// 创建axios实例,把本地的token放在header中:
const axiosInstance = axios.create({
baseURL: '/api/v1',
timeout: 3000,
headers: { 'Authorization': 'Bearer ' + localStorage.getItem('token') }, // 每个请求都自动携带token
});
// 是否显示成功的提示或者失败的提示
const defaultConfig = {
showError: true,
showSuccess: false
}
const request = (url: string, config= {}) => {
const _config = {
...defaultConfig,
...config
}
const { data, params } = _config
const method = _config.method || 'get'
return axiosInstance.request({
url,
method,
data: data || {},
params: params || {},
}).then((res) => {
const data = res.data;
_config.success && _config.success(data);
if (_config.showSuccess) toast.success(data.msg || '请求成功');
return data as TResData<T>
}).catch((err) => {
if (err.response.status >= 500) {
toast.error('服务器发生错误,请稍后再试')
}
// 如果用户校验失败,重新返回登录页
if (err.response.status === 401) {
toast.error('用户凭证出现问题,请重新登录')
location.href = '/login'
}
// 其他错误
let data = err.response.data
_config.error && _config.error(data)
if (_config.showError) toast.error(data.msg || '未知错误')
return data
})
}
现在基于这个封装好的request,写一下示例:
(1) 登录时存储token
request('/login', {
method: 'POST',
data: {
username,
password,
},
showSuccess: true,
success: (data) => {
localStorage.setItem('token', data.token); // 登录成功后将token存储
location.href = '/home'; // 跳转到主页
},
});
(2)其他请求:自动在Header上携带token
request('/stats');
(3)退出登录:清除localstorage的token
request('/logout', {
success: (data) => {
localStorage.removeItem('token'); // 清除tokn
location.href = '/login'; // 跳转到登录页
},
});
3.服务端:拿到客户端发过来的token进行验证
// 用户验证中间件
const authToken = async (req, res, next) => {
// 获取token
const authHeader = req.headers.authorization;
if (!authHeader || !authHeader.startsWith('Bearer ')) {
res.status(401).json({msg:"No token provided"})
}
const token = authHeader.split(' ')[1];
// 验证token
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// 以mongose为例
const user = await User.findById(decoded.userId).select('-password');
req.user = { userId: user._id, username: user.username, email: user.email };
next();
} catch (error) {
res.status(401).json({msg:"用户验证失败"})
}
};
在其他请求中加上中间件:
app.use('/api/v1/jobs', authToken, jobsRoute);
3.2 存储在Cookie
- (可选)服务端:安装Cookie解析库
npm i cookie-parser
// app.js
const cookieParser = require('cookie-parser');
app.use(cookieParser());
// 或加密
// app.use(cookieParser(process.env.COOKIE_SECRET, { signedCookies: true }));
服务端:将token存储在Cookie中
const login = async (req, res) => {
// ...登录成功后
// ...生成完token
const token = "your_token"
// 安装cookie-parser后可以这样写
const oneDay = 1000 * 60 * 60 * 24;
res.cookie('token', token, {
httpOnly: true,
expires: new Date(Date.now() + oneDay),
secure: process.env.NODE_ENV === 'production',
signed: true,
});
// 它实际上进行操作是:
/**
let cookieString = `token=${token}; Expires=${oneDay}; HttpOnly`;
if (process.env.NODE_ENV === 'production') {
cookieString += '; Secure';
}
res.setHeader('Set-Cookie', cookieString);
*/
res.status(StatusCodes.OK).json({
msg: '登录成功'
});
};
3.客户端:不需要存储token,也不需要在请求头携带token了,只需要根据服务端返回的status code来判断是否跳转回登录页
// 依旧是使用上面封装好的request
const axiosInstance = axios.create({
baseURL: '/api/v1',
timeout: 1000,
// headers: { 'Authorization': 'Bearer ' + localStorage.getItem('token') },
});
// ...
.catch(()=>{
if (err.response.status === 401) {
toast.error('用户凭证出现问题,请重新登录')
location.href = '/login'
}
})
4.服务端:对于其他请求,拿到Cookie的token进行验证
// 用户验证中间件
const authToken = async (req, res, next) => {
const token = req.cookie.token;
// 等同于:req.headers.cookie.split('=')[1]
// 如果上面的signed为true, 则 const token = req.signedCookies.token;
if (!token) {
res.status(401).json({msg:"No token provided"})
}
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET); // 传入token和秘钥
// 拿到解出来的 { userId, username }
// 将信息挂载req.user中供后续接口使用
req.user = { userId, username, ... };
next();
} catch (error) {
res.status(401).json({msg:"用户验证失败"})
}
};
使用中间件
app.use('/api/v1/groups', authToken, groupsRoute);
5.服务端:对于退出登录,还需要清除Cookie的token
const logout = async (req, res) => {
res.clearCookie('token')
res.status(StatusCodes.OK).json({
msg:'成功退出'
})
}
文章转自:https://juejin.cn/post/7372842988685688871
相关推荐
- 基于Docker方式安装与部署Camunda流程引擎
-
1Camunda简介官网:https://docs.camunda.org/manual/7.19/installation/docker/Camunda是一个轻量级、开源且高度灵活的工作流和决策自...
- 宝塔Linux面板如何部署Java项目?(宝塔面板 linux)
-
通过宝塔面板部署Java还是很方便的,至少不需要自己输入tomcat之类的安装命令了。在部署java项目前,我还是先说下目前的系统环境,如果和我的系统环境不一样,导致部署不成功,那你可能需要去找其他资...
- 浪潮服务器如何用IPMI安装Linux系统
-
【注意事项】此处以浪潮服务器为例进行演示所需使用的软件:Chrome浏览器个人PC中需要预先安装java,推荐使用jdk-8u181-windows-x64.exe【操作步骤】1、在服务器的BIOS中...
- Centos7环境Hadoop3集群搭建(hadoop集群环境搭建实验报告)
-
由于项目需要存储历史业务数据,经过评估数据量会达到100亿以上,在原有mongodb集群和ES集群基础上,需要搭建Hbase集群进行调研,所以首先总结一下Hadoop集群的搭建过程。一、三个节点的集群...
- Hadoop高可用集群搭建及API调用(hadoop高可用原理)
-
NameNodeHA背景在Hadoop1中NameNode存在一个单点故障问题,如果NameNode所在的机器发生故障,整个集群就将不可用(Hadoop1中虽然有个SecorndaryNameNo...
- 使用Wordpress搭建一个属于自己的网站
-
现在开源的博客很多,但是考虑到wordpress对网站的seo做的很好,插件也多。并且全世界流量排名前1000万的网站有33.4%是用Wordpress搭建的!所以尝试用Wordpress搭建一个网站...
- Centos 安装 Jenkins(centos 安装ssh)
-
1、Java安装查看系统是否已安装Javayumlistinstalled|grepjava...
- Java教程:gitlab-使用入门(java中的git)
-
1导读本教程主要讲解了GitLab在项目的环境搭建和基本的使用,可以帮助大家在企业中能够自主搭建GitLab服务,并且可以GitLab中的组、权限、项目自主操作...
- Dockerfile部署Java项目(docker部署java应用)
-
1、概述本文主要会简单介绍什么是Docker,什么是Dockerfile,如何安装Docker,Dockerfile如何编写,如何通过Dockerfile安装jar包并外置yaml文件以及如何通过do...
- 如何在Eclipse中搭建Zabbix源码的调试和开发环境
-
Zabbix是一款非常优秀的企业级软件,被设计用于对数万台服务器、虚拟机和网络设备的数百万个监控项进行实时监控。Zabbix是开放源码和免费的,这就意味着当出现bug时,我们可以很方便地通过调试源码来...
- Java路径-02-Java环境配置(java环境搭建及配置教程)
-
1Window环境配置1.1下载...
- 35.Centos中安装python和web.py框架
-
文章目录前言1.Centos7python:2.Centos8python:3.进行下载web.py框架然后应用:4.安装好之后进行验证:5.总结:前言...
- 《我的世界》服务器搭建(我的世界服务器如何搭建)
-
1.CentOS7环境1.1更改YUM源#下载YUM源文件curl-o/etc/yum.repos.d/CentOS-Base.repohttps://mirrors.aliyun.com...
- CentOS 7 升级 GCC 版本(centos7.4升级7.5)
-
1.GCC工具介绍GCC编译器:...
- Linux安装Nginx详细教程(linux安装配置nginx)
-
环境准备1.因为Nginx依赖于gcc的编译环境,所以,需要安装编译环境来使Nginx能够编译起来。命令:yuminstallgcc-c++显示完毕,表示安装完成:2.Nginx的http模块需要...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- 基于Docker方式安装与部署Camunda流程引擎
- 宝塔Linux面板如何部署Java项目?(宝塔面板 linux)
- 浪潮服务器如何用IPMI安装Linux系统
- Centos7环境Hadoop3集群搭建(hadoop集群环境搭建实验报告)
- Hadoop高可用集群搭建及API调用(hadoop高可用原理)
- 使用Wordpress搭建一个属于自己的网站
- Centos 安装 Jenkins(centos 安装ssh)
- Java教程:gitlab-使用入门(java中的git)
- Dockerfile部署Java项目(docker部署java应用)
- 如何在Eclipse中搭建Zabbix源码的调试和开发环境
- 标签列表
-
- navicat无法连接mysql服务器 (65)
- 下横线怎么打 (71)
- flash插件怎么安装 (60)
- lol体验服怎么进 (66)
- ae插件怎么安装 (62)
- yum卸载 (75)
- .key文件 (63)
- cad一打开就致命错误是怎么回事 (61)
- rpm文件怎么安装 (66)
- linux取消挂载 (81)
- ie代理配置错误 (61)
- ajax error (67)
- centos7 重启网络 (67)
- centos6下载 (58)
- mysql 外网访问权限 (69)
- centos查看内核版本 (61)
- ps错误16 (66)
- nodejs读取json文件 (64)
- centos7 1810 (59)
- 加载com加载项时运行错误 (67)
- php打乱数组顺序 (68)
- cad安装失败怎么解决 (58)
- 因文件头错误而不能打开怎么解决 (68)
- js判断字符串为空 (62)
- centos查看端口 (64)