Node_文件上传&令牌

信息获取来源Eno Yao

创建脚手架
express katsuki-project(express 名称)

在katsuki-project目录下安装依赖包
npm install

上传单文件项目

在katsuki-project安装multer模块

npm install multer --save

目录中创建一个uploads文件夹,不创建运行也会自动创建
项目结构

项目结构
	public
		javascripts
			jquery.js
			upload.js
		upload.html
	routes
		uploads.js
	app.js
upload.html
<script src="javascripts/jquery.js"></script>
<script src="javascripts/upload.js"></script>

<img id="img" src="" alt="上传图片" />
<input type="file" id="file" name="headImg" />
upload.js
$(()=>{
    function doUpload() {
        var formData = new FormData();
        //记得append("xxx")和对应标签name属性值一致 要跟后端一致
        formData.append('headImg', $('#file')[0].files[0]);
        $.ajax({
            url: 'http://localhost:3000/uploads/upload',
            type: 'POST',
            cache: false,
            data: formData,
            processData: false,
            contentType: false
        }).done(function(res) {
            $('#img').attr('src', `http://localhost:3000/${res.file.filename}`);
        }).fail(function(res) {
            console.log(res);
        });
    }
    $('#file').on('change',()=>{
        doUpload();
    })
})
路由文件uploads.js
var express = require('express');
var router = express.Router();

var multer = require("multer");
var storage = multer.diskStorage({
  //设置上传后文件路径,uploads文件夹会自动创建。
  destination: function (req, file, cb) {
    //路径要对,不然会500错误
    cb(null, './uploads')
  },
  //给上传文件重命名,获取添加后缀名
  filename: function (req, file, cb) {
    var fileFormat = (file.originalname).split(".");
    //给图片加上时间戳格式防止重名名
    //比如把 katsuki.jpg图片切割为数组[katsuki,jpg],然后用数组长度-1来获取后缀名
    cb(null, file.fieldname + '-' + Date.now() + "." + fileFormat[fileFormat.length - 1]);
  }
});
var upload = multer({
  storage: storage
});

router.post('/upload', upload.single('logo'), function (req, res, next) {
  console.log(req);
  res.json({
    status: "success",
    file: req.file
  });
});

module.exports = router;
app.js语句添加

添加路由路径语句
var uploadsRouter = require('./routes/uploads');
app.use('/uploads',uploadsRouter);

添加上传图片存储位置语句
app.use(express.static(path.join(__dirname, 'uploads')));

文件配置完成后

npm start
网页打开路径 localhost:3000/upload.html 上传文件,这里写的html针对上传图片显示
上传后在uploads文件夹里会有该文件

令牌登录

在描述令牌登录前,补充token、localStorage&sessionStorage

token

token进行加密解密操作,配合node的crypto内置模块使用
token.js来源 Eno Yao

token.js
var crypto = require("crypto");
// 把加密的内容一段乱码
var token = {
    // 加密
	createToken: function(obj, timeout) {
		//后来加的时效性  token在30内都是有效的
		var obj2 = {
			data: obj, //payload
			created: parseInt(Date.now() / 1000), //token生成的时间的,单位秒
			exp: parseInt(timeout) || 10 //token有效期
		};
		//payload信息
		var base64Str = Buffer.from(JSON.stringify(obj2), "utf8").toString("base64");
		//添加签名,防篡改
		var secret = "piggyyao.com";
		var hash = crypto.createHmac('sha256', secret);
		hash.update(base64Str);
		var signature = hash.digest('base64');
		return base64Str + "." + signature;
    },
    // 解码
	decodeToken: function(token) {
		var decArr = token.split(".");
		if(decArr.length < 2) {
			//token不合法
			return false;
		}
		var payload = {};
		//将payload json字符串 解析为对象
		try {
			payload = JSON.parse(Buffer.from(decArr[0], "base64").toString("utf8"));
		} catch(e) {
			return false;
		}
		//检验签名
		var secret = "piggyyao.com";
		var hash = crypto.createHmac('sha256', secret);
		hash.update(decArr[0]);
		var checkSignature = hash.digest('base64');
		return {
			payload: payload,
			signature: decArr[1],
			checkSignature: checkSignature
		}
    },
    // 校验
	checkToken: function(token) {
		var resDecode = this.decodeToken(token);
		if(!resDecode) {

			return false;
		}
		//是否过期
		var expState = (parseInt(Date.now() / 1000) - parseInt(resDecode.payload.created)) > parseInt(resDecode.payload.exp) ? false : true;
		if(resDecode.signature === resDecode.checkSignature && expState) {
			return true;
		}
		return false;
	}
}
module.exports = exports = token;

token的基本使用,一般都在路由文件中进行加密操作

run.js
var token = require("./token.js");
console.log(token); //得到引入的token对象,内有三个函数
// 加密
let crypto = token.createToken({
    name: 'katsuki',
    age: 18
}, 30) //30为令牌有效时间,单位秒

//令牌
console.log(crypto);

console.log(token.decodeToken(crypto));
// 解密
console.log(token.decodeToken(crypto).payload.data);
//检测是否有令牌
console.log(token.checkToken(crypto));

打印结果
结果

localStorage&sessionStorage

localStorage一直保存,主题颜色,白天模式或者夜间模式,token

// 增加 更新
localStorage.setItem(key,value);
// 查
let value = localStorage.getItem(key);
localStorage.removeItem(key);
// 全部清除
localStorage.clear();

sessionStorage网页如果关闭的话,就清除,页面缓存的数据

// 增加 更新
sessionStorage.setItem(key,value);
// 查
let value = sessionStorage.getItem(key);
sessionStorage.removeItem(key);
// 全部清除
sessionStorage.clear();

localStorage和sessionStorage空间大但是没有时效性

cookie具备最多功能(键值对,时效性等等),但是缺点空间小

令牌登录实现

假设已经在脚手架创建的文件目录中,完成了登录和登录跳转页

这里只对js文件对应部分进行描述

项目结构
	public
		javascripts
			jquery.js
			login.js
			katsuki.js
		login.html
		katsuki.html (登录跳转页)
	routes
		user.js (脚手架创建自带路由文件)
user.js
var express = require('express');
var router = express.Router();
//这里调用之前 Node_数据库 博文写的mongodb封装
let {
  find
} = require("../libs/mongod.js");
var token = require("../libs/token.js");

/* GET users listing. */
router.get('/', function (req, res, next) {
  res.send('respond with a resource');
});

//登录路由
router.post('/login', async (req, res, next) => {
  let {
    inputName,
    inputPassword
  } = req.body;

  let data = await find('user', {
    username: inputName
  });
  if (data[0].password == inputPassword) {
    res.send({
      status: "success",
      token: token.createToken({
        inputName,
        inputPassword
      }, 60) //令牌有效时间为60秒
    });
  } else {
    res.send({
      status: "fail",
    });
  }
});

//后台首页判断自动登录路由
router.post('/autoLogin', async (req,res,next)=>{
  res.send({
    status: token.checkToken(req.headers.token)
  })
})

module.exports = router;
login.js
$(() => {
    //登录按钮获取
    let signIn = $('#signin');
    //登录ajax请求
    let loginIn = (inputName, inputPassword) => {
        return new Promise((resolve, reject) => {
            $.ajax({
                type: 'post',
                url: 'http://localhost:3000/users/login',
                data: {
                    inputName,
                    inputPassword
                },
                success(data) {
                    resolve(data);
                }
            })
        })
    }
    
	//登录点击事件
    signIn.click(async () => {
    	//用户名获取
        let inputName = $('#inputName').val();
        //密码获取
        let inputPassword = $('#inputPassword').val();
        let data = await loginIn(inputName, inputPassword);
        
        //data拿到经过登录路由判断返回的res.send内容,进行下面操作
        let fn = {
            success() {
                console.log('登录成功');
                localStorage.setItem("token", data.token);
                location.href = 'katsuki.html';
            },
            fail() {
                console.log('登录失败');
            }
        }
        fn[data.status]()
    })
})
katsuki.js 未封装fn写法
$(() => {
	//自动登录判断函数
	let autoLogin = () => {
	   return new Promise((resolve, reject) => {
	       $.ajax({
	           type: 'post',
	           headers: {
	               token: localStorage.getItem("token")
	           },
	           url: "http://localhost:3000/users/autoLogin",
	           success(data) {
	               resolve(data);
	           }
	       })
	   })
	}
	(async () => {
        let isLogin = await autoLogin();
        if(isLogin.status){
			//为true,有令牌,进行相应操作
        }else{
			//为false,无令牌,跳回登录页
			location.href = "login.html";
        }
    })()
}
katsuki.js 封装fn写法
$(() => {
	//封装的函数都放入fn,使用时用fn.函数名调用
	(async () => {
        let fn = {
            true: async () => {
                //为true,有令牌,进行相应操作
            },
            false() {
            	//为false,无令牌,跳回登录页
                location.href = "login.html";
            },
            //自动登录判断
            autoLogin() {
                return new Promise((resolve, reject) => {
                    $.ajax({
                        type: 'post',
                        headers: {
                            token: localStorage.getItem("token")
                        },
                        url: "http://localhost:3000/users/autoLogin",
                        success(data) {
                            resolve(data);
                        }
                    })
                })
            },
            kasami() {
            	console.log('kasami');
            	//this返回fn对象,能够继续点调用对象方法
            	return this; 
            },
            katsuki() {
				console.log('katsuki');
				return this;
			}
    	}
	}    
	let isLogin = await fn.autoLogin();
	// 异步 awiat和async
	fn[isLogin.status]();
	// 链式调用
	fn.kasami().katsuki();
    })()
})    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值