内容回顾
node是一个服务端的js,他的底层内核是V8引擎。
相关的指令及工具
nvm node的版本管理工具(需要安装)
nrm node的镜像管理工具(需要安装)
npx 快速执行脚本的命令
npm 包管理器
node 运行js文件的
包管理工具
npm
npm i 第三方模块 #npm安装
yarn (Facebook出品)
yarn add 第三方模块 #yarn安装
基础npm指令
- npm install 安装 简写为 npm i
- npm uninstall 卸载
- npm update 更新
- npm publish 发布
- npm set 设置
- npm config 配置
- ...
命令修饰关键词
- -S 保存到本地 --save
- -D 保存到工作环境 --develop
- -g 全局保存 --global
内置模块及第三方模块
内置模块(不需要安装)
http(处理http请求),url模块处理url,path模块路径处理,querystring(qs)读取对应的内容 fs模块filesystem...
第三方模块(需要安装)
md5 加密模块 uuid形成id模块 mysql模块 mongodb模块 body-parse模块 cookie-parse模块 express模块...
模块化(require.js的模块化)
require 导入
const http = require("http")
module.exports 导出
module.exports = { }
内置加密模块 crypto
导入模块
const {createHmac} = require('node:crypto');
接口书写
//用户登录操作
router.post("/login", async function (req, res, next) {
//获取用户名及密码
let {
username,
password
} = req.body
//对应的密码要进行加密操作再进行验证 密钥
let checks = await queryUserByUser({
username
})
//如果用户名存在
if (checks.length) {
//验证当前是否正确 获取当前用户
let user = checks[0]
//密码要进行加密操作 user.slat
password = createHmac("sha256", user.slat).update(password).digest("hex")
//判断当前user密码是否和对应的加密密码一致
if (user.password == password) {
res.send(new Response({
id: user.id
}, 200, "登录成功"))
} else {
res.send(new Response({}, 200, "用户名或密码错误"))
}
}else {
res.send(new Response({}, 200, "用户名或密码错误"))
}
})
//用户注册操作
router.post("/register", async function (req, res, next) {
//获取用户信息
let {
username,
password
} = req.body
//查询当前用户是否存在
let users = await queryUserByUser({
username
})
//查不到注册
if (!users.length) {
//对密码进行加密操作
//随机生成对应的盐值
req.body.slat = Math.ceil(Math.random() * 1000) + Date.now().toString()
req.body.password = createHmac("sha256",
req.body.slat).update(password).digest("hex")
//指定默认值
await saveUser(req.body)
//注册成功
res.send(new Response(req.body, 200, "注册成功"))
} else {
res.send(new Response({}, 200, "当前用户已存在"))
}
})
第三方模块 jwt
jwt概述
json web token主要是用于安全传输,里面主要有授权和加密等操作。JSON WEB Token(JWT,读作 [/dʒɒt/] ),是一种基于JSON的,用于在网络上声明某种主张的令牌(token)。JWT通常由三部分组成:头信息(header),消息体(payload)和签名(signature)。
jwt的简单构成
密钥 (加密方式 hash加密 对称加密 非对称加密(rsa))
信息 (关键信息 用户id等标识信息)
过期时间 (为毫秒值)
jsonwebtoken || express-jwt (导入了jwt模块)
流程
- 先拦截对应的需要权限进入的接口 放行不需要拦截的接口(登录、注册)
//中间件拦截 参数1为密钥 参数2为加密方式
app.use(jwt({secret:privateKey,algorithms:["RS256"]}).unless({
path:["/users/login","/users/register"]
}))
- 登录成功生成对应的token发送到浏览器上
//用户登录操作
router.post("/login", async function (req, res, next) {
//获取用户名及密码
let {
username,
password
} = req.body
//对应的密码要进行加密操作再进行验证 密钥
let checks = await queryUserByUser({
username
})
//如果用户名存在
if (checks.length) {
//验证当前是否正确 获取当前用户
let user = checks[0]
//密码要进行加密操作 user.slat
password = createHmac("sha256",
user.slat).update(password).digest("hex")
//判断当前user密码是否和对应的加密密码一致
if (user.password == password) {
//生成token
//sign方法 第一个为数据 第二个为私钥 第三为配置
let token = sign({id:user.id},privateKey,{
algorithm:"RS256",
//过期时间为s
expiresIn: 120
})
//生成对应的token
res.send(new Response({
id: user.id,
token
}, 200, "登录成功"))
} else {
res.send(new Response({}, 200, "用户名或密码错误"))
}
}else {
res.send(new Response({}, 200, "用户名或密码错误"))
}
})
- 再次请求需要拦截的接口 需要带上对应的token
存对应的登录返回的token(localstroage || sessionstroage)
localstroage.setItem("token",token) //存入token到本地
从本地获取token存入对应的请求头
//请求头中添加对应的token
req.headers["Authorization"] = "Bearer"+从本地拿的token
后台解析
// 获取所有的用户
router.get('/', async function (req, res, next) {
let users = await getUsers()
//得到token字符串 Bearer token
let tokenStr = req.headers["authorization"].split(" ")[1]
//解析token 取出里面的数据
let payload = verify(tokenStr,publicKey,{
algorithms:["RS256"]
})
//根据id得到相关数据 (得到当前用户的权限)
res.send(new Response(users)).status(200)
});
密钥生成
- 对称加密 (加密和解密是一个)
- 非对称加密 (非对称加密 公钥 及 私钥)
借助openSSL 来完成密钥的生成
安装openSSL(部分电脑内置)
openSSL version -a
生成私钥
openssl genrsa -out private.key
根据私钥生成公钥
openssl rsa -in private.key -pubout -out public.key
读取key的工具
const fs = require("fs")
const {join} = require("path")
let privateKey = fs.readFileSync(join(__dirname,"../key/private.key"))
let publicKey =fs.readFileSync(join(__dirname,"../key/public.key"))
module.exports = {
privateKey,
publicKey
}
axios
概述
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
axios的特点
- 从浏览器中创建 XMLHttpRequests(XMLHttpRequest - Web APIs | MDN)
- 从 node.js 创建 http(https://nodejs.org/api/http.html) 请求
- 支持 Promise (Promise - JavaScript | MDN)API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF(https://en.wikipedia.org/wiki/Cross-site_request_forgery)
axios的简单使用
直接使用axios里面的方法 (返回的是promise对象)
- axios.get
- axios.post
- axios.delete
- axios.put
- axios.patch
- ....
<button>登录</button>
<!-- cdn引入 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
async function login(){
//发送get请求 请求地址 参数
let info = await axios.post("http://localhost:3000/users/login",{
username:'jack',
password:'123'
})
console.log(info)
}
document.querySelector("button").onclick = ()=>{
login()
}
</script>
二次封装
将对应的axiso封装成一个文件 返回一个对应的axios的请求方法
<button class="login">登录封装版</button>
<button class="getUsers">获取users数据</button>
<!-- cdn引入 -->
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var request = axios.create({
baseURL: 'http://localhost:3000',
timeout: 3000,
})
//封装对应的axios
//请求拦截
request.interceptors.request.use(config => {
//获取本地的token加入到对应的headers中
config.headers["Authorization"] = "Bearer"+localStorage.getItem("token")
return config;
}, error => {
console.log("请求出错")
return Promise.reject(error);
});
//响应拦截
request.interceptors.response.use(response => {
//使用localstroage存入 获取的token
let token = response.data.data.token
//存入对应的localstroage中
localStorage.setItem("token",token)
return response;
}, error => {
//如果响应过期了 那么应该去登录页面
if(error.response.status == 401){
console.log("去登陆页面")
}
return Promise.reject(error);
});
async function loginAxios() {
//发送get请求 请求地址 参数
let info = await request({
method: "post",
url: '/users/login',
data: {
username:'jack',
password: '123'
}
})
console.log(info)
}
document.querySelector(".login").onclick = () => {
loginAxios()
}
document.querySelector(".getUsers").onclick = async () => {
console.log("触发了")
let info = await request({
method: "get",
url: '/users',
data:{}
})
console.log(info)
}
</script>
请求拦截
//获取localstroage中的token 将token加入到对应的请求头
//获取本地的token加入到对应的headers中
config.headers["Authorization"] = "Bearer "+localStorage.getItem("token")
响应拦截
//获取响应的token 将token存入本地 (localstroage)
//使用localstroage存入 获取的token
let token = response.data.data.token
//存入对应的localstroage中
localStorage.setItem("token",token)
上传功能实现
第三方模块 multer
npm i multer -S
上传工具类封装
var multer = require("multer")
var path = require("path")
var {mkdirSync,existsSync} = require("fs")
//帮助类完成对应的上传
//自定义上传的相关信息
const storage = multer.diskStorage({
destination: function (req, file, cb) {
let uploadPath = "../public/upload"
//判断路径是否存在
if(!existsSync(path.join(__dirname,uploadPath))){
// 如果不存在就创建
mkdirSync(path.join(__dirname,uploadPath))
}
cb(null, path.join(__dirname,uploadPath))
},
filename: function (req, file, cb) {
//随机生成的名字
const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1000)
cb(null, file.fieldname + '-' + uniqueSuffix +
path.extname(file.originalname) )
}
})
//产生对应的上传的方法
const upload = multer({
storage: storage
})
module.exports = upload
基础使用
页面
<!DOCTYPE html>
<html>
<head>
<title>上传页面</title>
<link rel='stylesheet' href='/stylesheets/style.css' />
</head>
<body>
<form action="http://localhost:3000/upload" method="post"
enctype="multipart/form-data">
<input type="file" name="file">
<button type="submit">上传</button>
</form>
</body>
</html>
接口
//上传页面接口
router.get('/upload.html', function (req, res, next) {
res.render('upload');
});
//upload.single('属性名') 表示上传一个文件
//upload.array([]) 表示上传多个文件
//上传接口
router.post('/upload', upload.single('file'),function (req, res, next) {
console.log('进来了')
//完成上传操作
console.log(req.file, req.body)
res.send({
fileName:req.file.filename,
path:"http://localhost:3000/upload/"+req.file.filename
})
});
中间件拦截
//中间件拦截 参数1为密钥 参数2为加密方式
app.use(jwt({secret:publicKey,algorithms:["RS256"]}).unless({
path:["/users/login","/users/register","/",/upload/] //其中带upload的内容不需要拦
截
}))