Express-generator和文件上传和身份认证
Express-generator
express生成器
之前做项目非常麻烦,需要创建,静态资源文件夹,路由文件夹,views视图文件夹,还有各种各样的配置信息,我们在做一个项目的时候,主要关注的是项目后台的逻辑;
我们需要有这样一个工具(express-generator),能够帮助我们快速生成对应的目录结构
使用步骤
- 安装
npm i express-generator -g
- 创建项目
express -e 项目的名字
- 尝试分析代码
- 进入项目,安装相关的包依赖
npm i
- 运行程序
npm run start

- 修改运行命令
"scripts":{
"start":"nodemon ./bin/www"
}
文件上传
在任何的系统中,都会有文件上传的情况,这时候需要使用multer这个包,当然能够解决文件上传的包有很多,不光这一个,我们在这里使用的是multer这个包
创建html页面
<form action="http://127.0.0.1:3000/uploadImg" method="post" enctype="multipart/form-data">
上传头像:<input type="file" name="files">
<input type="file" name="files">
<input type="submit">
</form>
当前页面可以直接放在public文件夹下,这样需要在app.js中配置静态资源文件夹
注意事项:
input 的类型为file,并且需要设置name值
提交方式必须是post
enctype的值必须为multipart/form-data
创建项目入口文件
添加静态资源文件夹路径
文件上传的参数

实现文件上传功能
// 引入express模块
let express = require('express');
// path路径模块
let path = require('path');
// mysql数据库操作
let db = require('./db');
// fs文件操作
let fs = require('fs');
// 文件上传模块
let multer = require('multer');
// 创建app服务
let app = express();
// 配置public为静态资源文件夹
app.use(express.static(path.join(__dirname,'public'),{index:false}));
// 设置public/imgs为文件上传之后保存的路径
let uploader = multer({dest:path.join(__dirname,'public','imgs')});
// 配置ejs
app.set('view engine','ejs');
// 处理文件上传的操作
/*
注意:uploader.single('上传图片的input的name值')
*/
app.post('/uploadImg',uploader.single('files'),(req,res)=>{
// 获取req下面的file属性,返回的是一个对象
let {file} = req;
// 获取后缀名
let extname = path.extname(file.originalname);
// 获取文件名
let filepath = file.path;
// 拼接完整的路径 + 后缀名
let fileName = filepath + extname
// 对上传到imgs的文件进行重命名fs.rename(oldname,newname,callback)
fs.rename(filepath,fileName,(err)=>{
if(!err){
// 拼接文件保存的文件夹和图片名称,用于存储数据库使用
let imgDate = 'imgs/'+path.basename(fileName);
// 保存数据库
db.insert('stu',{name:'ryh',sex:'女',birth:'2000',department:'计算机科学技术',address:'郑州',cid:3,istrue:1,avator:imgDate},(imgres)=>{
// 受影响的行数>1,表示上传成功
if(imgres.affectedRows>0){
res.send('上传成功');
}
});
}else{
res.send('上传失败');
}
});
})
// 用于测试的路由
app.get('/',(req,res)=>{
res.send('hello 首页');
})
// 显示所有的学生信息,主要是为了显示img图片信息
app.get('/show',(req,res)=>{
db.query('select * from stu',(allPerson)=>{
console.log(allPerson);
res.render('show',{allPerson});
})
})
app.listen(3000,()=>{
console.log('hell page');
});
将stu学生信息,渲染到ejs模板中
创建 views - 创建show.ejs
<table width="800" border="1">
<tr>
<td>id</td>
<td>姓名</td>
<td>性别</td>
<td>生日</td>
<td>系别</td>
<td>地址</td>
<td>头像</td>
</tr>
<%= allPerson.forEach(item=>{ %>
<tr>
<td><%=item.id%></td>
<td><%=item.name%></td>
<td><%=item.sex%></td>
<td><%=item.birth%></td>
<td><%=item.department%></td>
<td><%=item.address%></td>
<td><img src="<%=item.avator%>" alt="" width="50"></td>
</tr>
<% }) %>
</table>
文件上传中,不仅可以上传图片,还可以上传txt,docx等任意文件,当然还可以同时上传多个文件,上传多个文件可以参考npm中multer的解析
地址:https://www.npmjs.com/package/multer
身份认证
身份认证(Authentication)又称“身份验证”,“鉴权”,是指通过一定的手段,完成对用户身份的确认
日常生活中的身份认证随处可见,例如:高铁的验票乘车,手机密码或者指纹解锁,支付宝或微信的支付密码等
在web开发中,也涉及到用户身份的认证,例如:各大网站的手机验证码登陆,邮箱密码登陆,二维码登陆等
session
登陆功能其实就是身份的认证
之前使用本地存储的问题有那些?
不同开发模式下的身份认证
- 前后端分离:ajax请求接口(html,css等静态资源是不请求服务器的,只有数据是请求接口返回的)推荐JWT认证
- 服务器段渲染(将整个页面以字符串的方式返回给浏览器)推荐使用session
什么是http无状态
http协议是无状态,指的是客户端的每次http请求都是独立的,连续多个请求之间是没有直接的关系的,服务器不会主动保留每次http请求的状态
让服务器有记忆功能 cookie和session
cookie虽然是本地存储,但是每一次请求都会将cookie发送给服务器
cookie相当于每一次客户端颁发一个通行证
cookie的问题
cookie是存储在本地的
并且js是可以直接读写cookie的,所以cookie是不安全的
不建议服务器将重要的数据保存在cookie中
Session
session是一种记录客户状态的机制,cookie是保存在客户端中的,而session保存在服务端上

express中使用session
步骤:
- 安装express-session
- 引入模块
- 对session进行配置
- 使用 - 添加session
- 使用 - 获取session
安装
npm install express-session
引入
let session = require('express-session');
对session进行配置
// 配置session
app.use(session({
// 密钥,本质上就是字符串,相当于密码本
secret: 'ryh',
// 强制保存 session 即使它并没有变化,。默认为 true。建议设置成 false。 don't save session if unmodified
resave: true,
// 强制将未初始化的 session 存储
saveUninitialized: true,
}))
设置session
// 设置session
app.get('/set',(req,res)=>{
req.session.name = '天王盖地虎'; // 设置session
// req.session.cookie.maxAge=0; //重新设置 cookie 的过期时间
res.send('设置session');
})
获取session
// 获取session
app.get('/get',(req,res)=>{
console.log(req.session.name); // 获取session
res.send(req.session.name);
})
销毁session
// 销毁session
app.get('/del',(req,res)=>{
req.session.destroy(function(err) { /*销毁 session*/ })
res.send('销毁session');
})
session参考文档:https://www.cnblogs.com/loaderman/p/11506682.html
session案例
使用session模拟 登陆 和 退出功能
- 使用express-generator搭建项目结构
express -e myapp项目名称 // 创建项目结构 cd myapp npm install // 安装包依赖
- 分析路由,配置路由
// 在 / 配置根目录路由,访问127.0.0.1:3000的时候显示首页
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
- 修改首页登陆注册的地址
<li><a href='/user/login'>请登陆</a></li>
user.js
login.ejs页面
处理登录请求
- 修改首页登录字样
<% if(name){ %>
<li><a><%=name%>登陆成功</a></li>
<li><a href="/users/logout">退出</a></li>
<%} else { %>
<li><a href="/users/login">请登录</a></li>
<% } %>
为了判断是登录之后的跳转还是第一次访问跳转,需要给index页面传递session - index.js
- 对应的index.ejs页面需要处理登录的状态
登录成功显示:欢迎XXX登录成功,并且添加退出按钮
登录失败显示:请登录
<% if(name){ %>
<li><a><%=name%>登陆成功</a></li>
<li><a href="/users/logout">退出</a></li>
<%} else { %>
<li><a href="/users/login">请登录</a></li>
<% } %>
- 退出操作
router.get('/logout', function(req, res, next) {
// 清除session
req.session.destroy();
res.redirect('/');
});
项目:产品大牛
Token【JWT认证】
1.为什么使用JWT认证?
session认证机制需要配置cookie才能实现,由于cookie默认不支持跨域访问,所以,当涉及到前端跨域请求后端接口的时候,需要做很多额外的配置,才能实现跨域session认证
注意:
1. 当前端请求后端接口不存在跨域问题的时候,推荐使用session身份认证机制
2. 当前端需要跨域请求后端接口的时候,不推荐使用session身份认证机制,推荐使用JWT认证机制
2. 什么是JWT
JWT(全称:json web token)是目前最流行的跨域认证解决方案
如果前后端进行数据交互的时候,需要进行跨域,那么就可以使用jwt认证机制
3. jwt的工作原理

核心原理:用户的信息通过token字符串的形式,保存在客户端浏览器中,服务器通过还原token字符串的形式来认证用户的身份
4.JWT组成部分
WT通常由3部分组成,分别是header(头部),payload(有效荷载),signature(签名)【签名类似于谍战片中破解摩斯密码的密码本】
三者之间使用英文的‘.’分割,格式如下:header.payload.signature
标准返回的格式:

其中:
payload部分是真正的用户信息,他是用户信息经过加密之后生成的字符串
header和signature是安全性相关的部分,只是为了保证token的安全性【防止别人破解这个信息】
5.JWT的使用方式
客户端收到服务器返回的JWT之后,通常会将他存储在localStroage或sessionStroage中
此后,客户端每次与服务器通信,都要带上这个JWT的字符串,从而进行身份认证。推荐的做法是 把JWT 放在HTTP请求头的Authorization字段中
格式:Authorization:Bearer <token>
6.在express中使用JWT
1)安装包jsonwebtoken 这个包
npm i jsonwebtoken
jsonwebtoken里面有两个方法
jwt.sign:设置token
jwt.verify:解析token
2)导入包
// 1. 倒入用于生成jwt字符串的包
const jwt = require('jsonwebtoken');
3)定义secret密钥
了保证jwt字符串的安全性,防止jwt字符串在网络传输过程中被别人破解,我们需要专门定义一个用于加密和解密的secret密钥
作用:
当生成jwt字符串的时候,需要使用secret密钥对用户的信息进行加密,最终得到加密好的jwt字符串
当把jwt字符串解析还原成json对象的时候,需要使用secret密钥进行解码
secret本质上就是一个普通的字符串,就相当于是密码本,但是你用的是哪个密码本别人不知道,所以没办法被破解,越复杂越好
// secret密钥:密码本 const secretKey = 'dianshanhu123';
4)生成jwt字符串
在登陆成功后,调用jsonwebtoken包中提供的sign()方法,将用户的信息加密成jwt字符串,响应给客户端
语法:
jwt.sign({uname:name},secretKey,{expiresIn:'1h'}) 对信息进行加密
{uname:name}:需要加密的信息
secretKey:密码本
expiresIn:token字符串的有效期,1h小时,1s秒,1m分钟【生成token之后,30秒之内是有效的】
app.js
app.get('/send', (req, res) => {
let { name, pwd } = req.query;
if (name == 'admin' && pwd == 'admin') {
res.send({
status: 200,
msg: '登陆成功',
token: jwt.sign({ uname: name }, secretKey, { expiresIn: '1h' })
})
} else {
res.send({
status: 102,
msg: '失败'
})
}
})

5)客户端保存token字符串
之后就可以在请求头中携带token字符串,然后对token的值进行身份认证
在前端页面,给localstroage设置token值
show.html
<h1>首页</h1>
<div id="msg"></div>
<button>退出账号</button>
<script>
$(() => {
$.ajax({
url: 'http://127.0.0.1:3000/show',
type: 'get',
beforeSend:function (request) {
request.setRequestHeader("authorization",window.localStorage.getItem("msg"));
},
success: function (res) {
if(res.msg == 'ok'){
$('#msg').html(`欢迎${res.data.uname}登陆成功`);
}
console.log(res);
}
})
})
$('button').click(()=>{
alert('账号已退出,跳转到登陆页面');
window.localStorage.removeItem("msg");
window.location.href = 'http://127.0.0.1:3000';
})
</script>

6)将jwt字符串还原为json对象
客户端每次在访问哪些有权限接口的时候,都需要主动通过请求头中的Authorization字段,将token字符串发送到服务器进行身份验证
此时,服务器可以通过jwt.verify方法,自动将客户端发送过来的token解析还原成json对象
app.get('/show', (req, res) => {
console.log(req.headers);
let { authorization } = req.headers;
console.log(authorization);
try {
// const data = jwt.verify(authorization.split(' ')[1], secretKey); // 带有Bearer
const data = jwt.verify(authorization, secretKey);
console.log(data);
res.send({
status: 200,
msg: 'ok',
data: data
})
} catch (err) {
res.send({
status: 401,
msg: 'error'
})
}
})
注意:
A.token添加成功之后,在获取token的时候,必须在请求头中添加 authorization,然后就可以在req.headers中直接获取 token值
B.不要把一些重要信息放在token中,比如密码
7)捕获解析jwt失败后产生的错误
当使用 verify 解析token字符串时,如果客户端发送过来的token字符串过期或者不合法,会产生一个解析失败的错误,影响项目的正常运行,我们可以通过express的错误中间价,捕获这个错误并进行相关的处理,代码如下
try {
// const data = jwt.verify(authorization.split(' ')[1], secretKey); // 带有Bearer
const data = jwt.verify(authorization, secretKey);
console.log(data);
res.send({
status: 200,
msg: 'ok',
data: data
})
} catch (err) {
res.send({
status: 401,
msg: 'error'
})
}
data的返回格式

其中iat和exp表示token的有效期:
iat:发布时间
exp:截止时间

浙公网安备 33010602011771号