Express-generator和文件上传和身份认证

Express-generator

express生成器

之前做项目非常麻烦,需要创建,静态资源文件夹,路由文件夹,views视图文件夹,还有各种各样的配置信息,我们在做一个项目的时候,主要关注的是项目后台的逻辑;

我们需要有这样一个工具(express-generator),能够帮助我们快速生成对应的目录结构

 

使用步骤

  1. 安装
npm i express-generator -g

 

  1. 创建项目
    express -e 项目的名字

 

  1. 尝试分析代码
  2. 进入项目,安装相关的包依赖
  npm i

 

  1. 运行程序
npm run start

  1. 修改运行命令
"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

步骤:

  1. 安装express-session
  2. 引入模块
  3. 对session进行配置
  4. 使用 - 添加session
  5. 使用 - 获取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模拟 登陆 和 退出功能

  1. 使用express-generator搭建项目结构
express -e myapp项目名称 // 创建项目结构
cd myapp
npm install // 安装包依赖

 

  1. 分析路由,配置路由
// 在 / 配置根目录路由,访问127.0.0.1:3000的时候显示首页
router.get('/', function(req, res, next) {
  	res.render('index', { title: 'Express' });
});

 

  1. 修改首页登陆注册的地址
<li><a href='/user/login'>请登陆</a></li>


user.js
login.ejs页面
处理登录请求

  1. 修改首页登录字样
<% 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

  1. 对应的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>
<% } %>

 

  1. 退出操作
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之后通常会将他存储在localStroagesessionStroage

此后客户端每次与服务器通信都要带上这个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:截止时间

posted @ 2022-10-26 09:25  好阿  阅读(179)  评论(0)    收藏  举报