-
鉴权
- 鉴权: 判断某用户是否有权访问服务器上的资源
- 例如;
- 用户需要登录之后才可以访问一些特定的界面
- 某些页面需要token才可以访问
- HTTP是无状态的
- 早期的web只需要提供信息给访问者就行了,不需要记录状态,浏览器和服务器不能凭借HTTP协议来辨别请求的上下文
- 服务器是不能识别浏览器发出的请求是否之前发过
- 鉴权思路
- 一种: 将身份信息保存在服务器.
- 例如: 取快递的时候,报出快递号就可以查看是否有这个快递
- 快递点就是服务器,自己是客户端
- 二:种 将身份信息保存在客户端.
- 例如: 游乐园门票,使用门票后,在门票上面打孔,但门票在自己手上
- 自己是客户端,服务器是游乐园
- 一种: 将身份信息保存在服务器.
- 鉴权实现步骤
- 怎么让服务器认识你,明白你是谁
- 用户登录之后,得到能表明身份的凭证,下次请求或请求其他页面,带上这个凭证我就可以访问,不带凭证就不能访问,因为服务器不认识你
-
鉴权的方式有三种(cookie,session,token)
-
cookie(甜饼)
- 是存在于浏览器上的一种浏览器本地存储的方式, 存储一些不重要的信息,大小为4K
- 同域名下的 cookie 不同标签页可以共享, 默认过期时间是浏览器关闭时
- 进行 HTTP 请求时, 会自动带上浏览器全部的 cookie 发给后台, 后台也可以获取 cookie, 设置可以在响应时, 向浏览器中设置 cookie。
- 可以通过浏览器查看某个网站的cookie
- 因为cookie可以人为的设置和修改查看,所以一些重要信息无法在cookie上储存,因为是不安全的
-
cookie的修改和查看
- cookie在检查元素中可以进行查看,双击中间的name和value可以进行修改和增加,一般cookie保存一些无关紧要的信息和请求
-
cookie鉴权方案
- 分析思路
- 用户登录成功,服务器设置cookie
- 用户下次请求会自动加上cookie,服务器解析cookie,判断是否登录
- 用户退出,服务器删除cookie
-
案例准备(结构,代码,安装包)
-
用到的npm包
-
npm install cookie-parser
npm install express
下面cookie代码演示默认:已安装这两个包
- index.html代码
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> </head> <body> <input type="text" id="username" name="name" value="admin" /> <input type="text" id="password" name="password" value="123456" /> <button id="btn_keyvalue">登录</button> <a href="./testcookie" target="_blank">页面跳转携带cookie</a> <button id="btn_testCookie">ajax页面跳转携带cookie</button> <button id="btn_delCookie">退出,删除cookie</button> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script> // 用户退出,验证删除cookie的功能 $('#btn_delCookie').click(function () { $.ajax({ type: 'get', url: 'http://localhost:3000/quit', success(res) { console.log(res) }, }) }) // 测试cookie的效果 $('#btn_testCookie').click(function () { $.ajax({ type: 'get', url: 'http://localhost:3000/testcookie', success(res) { console.log(res) }, }) }) // 用户登录 $('#btn_keyvalue').click(function () { $.ajax({ type: 'post', url: 'http://localhost:3000/login', data: { name: $('#username').val(), password: $('#password').val(), }, success(res) { console.log(res) }, }) }) </script> </body> </html>
- server.js代码
-
// 引入模块 express cookie-parser const express = require('express') const cookieParser = require('cookie-parser') const app = express() // 中间件 静态托管 app.use(express.static('public')) // 中间件 接收简单键值对 接受的数据在req.body中 app.use(express.urlencoded()) // const cors = require('cors') // app.use(cors()) // 中间件 引入cookieparser语法 app.use(cookieParser()) // 发送POST请求 点击登录 app.post('/login', (req, res) => { // 解构赋值 ES6语法 console.log('接收到的简单键值对', req.body) const { name, password } = req.body // console.log('获取的值', name, password) // 1.判断,只能是这个账号密码,正常是链接的数据库 // 2.判断输入的值是否在数据中存在 // 3.简单测试cookie,默认这俩值 if (name === 'admin' && password === '123456') { // 设置响应头来设置cookie // res.setHeader('set-cookie', 'name=' + name) // express框架给我们提供了一个res.cookie方法,用来设置cookie res.cookie('islogin', true) res.send('登陆成功') } else { res.send('登陆失败') } }) // 跨页面传cookie app.get('/testcookie', (req, res) => { // 能获取到cookie是引入的cookie-parser console.log('本次请求带的cookie是', req.headers.cookie) console.log('请求携带的cookie是', req.cookies) if (req.cookies.islogin === 'true') { res.send('cookie跨页面成功') } else { res.send('cookie已被移除') } }) // 退出登录 app.get('/quit', (req, res) => { // 移除islogin的cookie res.clearCookie('islogin') res.send('删除cookie') }) app.listen(3000, () => { console.log(3000) })
-
-
- 效果展示
- 我们设置的cookie在浏览器页面也可以被访问的到的
-
同理,操作各种跨页面,携带cookie进行请求,移除都是可以完成的
- 分析思路
-
session
-
session从字面上就是会画
-
session 是区别于数据库存在的一种服务器临时存储技术, 它主要存储一些无需持久化的数据, 比如临时的登录状态信息等.
-
session原理
-
用户登录成功时,服务器端会生成一个sessionid,并通过set-cookie将生成的sessionid返回给客户端
-
客户端收到sessionid会将它保存在cookie中,当客户端再次访问服务端时会带上这个sessionid
-
当服务端再次接收到来自客户端的请求时,会先去检查是否存在sessionid,不存在就新建一个sessionid重复1,2的流程,如果存在就去遍历服务端的session文件,找到与这个sessionid相对应的文件,文件中的键值便是sessionid,值为当前用户的一些信息
-
通过cookie回传给浏览器的是session编号;真正的数据在服务器端
-
-
有案例(不想写,写了三次,自动删除三次)
-
-
cookie和session的比较
-
cookie原理:
-
从服务器端向客户端浏览器留下信息
设置响应头:set-cookie
; -
浏览器每次访问服务器时都带上这些信息(自动携带cookie是浏览器的特点);
-
-
session原理:
-
服务器端会为每个用户(浏览器)各自保存一个session(文件)。当服务器保存session之后,会以cookie的形式告诉浏览器,你的session编号是哪一个。它把session号返回给了浏览器,而把真实的数据保存在服务器。
-
下次再来访问服务器的时候,浏览器就会带着它自己的session号去访问,服务器根据session号就可以找到对应的session了。
-
-
cookie:优点是节省服务器空间,缺点不安全。不要保存敏感信息。
-
session:优点是安全,缺点需要服务器空间(服务器重启,则数据丢失), 是一种最常见的解决方案。
-
-
JWT
-
JWT(json web token),token的意思是"令牌",是服务端生成的一串字符串,作为客服端进行请求的一个标识
-
原理:
-
服务器认证之后,生成一个JSON对象,返回给用户,就像下面这样
{
"姓名": "张三",
"角色": "管理员",
"到期时间": "2022年7月11日0点0分"
} - 以后,用户与服务端通信的时候,都要返回这个JSON对象.服务器完全只靠这个对象认定用户的身份
- 并且为了防止用户篡改数据,服务器在生成这个对象的时候,会给他加密一下,就是我们看到的长长的字符串
- 当因为跳转页面携带token,会出现跨域问题(本文中解决跨越问题引用cors包,具体解决跨域问题的方法,后面会对跨域解释(//此处省略地址))
-
-
案例准备
-
安装npm包
-
npm i jsonwebtoken
npm i express
npm i cors
npm i express-jwt 1
-
- 案例目录
- idnex.html代码
-
-
-
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Document</title> </head> <body> <h1>token</h1> <input type="text" id="username" name="name" value="admin" /> <input type="text" id="password" name="password" value="123456" /> <button id="btn_login">登录,获取token</button> <button id="btn_testToken">没有token,不能访问</button> <button id="btn_delToken">删除token</button> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script> $('#btn_delToken').click(function () { // 删除localstorage localStorage.removeItem('token') }) // 在请求头中携带token $('#btn_testToken').click(function () { $.ajax({ type: 'get', url: 'http://localhost:3000/test', headers: { Authorization: localStorage.getItem('token'), }, success(res) { console.log(res) }, }) }) $('#btn_login').click(function () { $.ajax({ type: 'post', url: 'http://localhost:3000/login', data: { name: $('#username').val(), password: $('#password').val(), }, success(res) { console.log('登录成功,token', res.token) // 保存token localStorage.setItem('token', res.token) }, }) }) </script> </body> </html>
-
- server.js代码
-
// 引用模块 express cors jsonwebtoken express-jwt const express = require('express') const cors = require('cors') const app = express() const jwt = require('jsonwebtoken') const expressJwt = require('express-jwt') // 中间件 跨域 app.use(cors({ origin: true, credentials: true })) // 中间件 静态托管 app.use(express.static('public')) // 中间件 接受简单键值对 app.use(express.urlencoded()) // app.use(jwt().unless()) // jwt() 用于解析token,并将 token 中保存的数据 赋值给 req.user // unless() 约定某个接口不需要身份认证 app.use( expressJwt({ secret: 'node1', // 生成token时的 钥匙,必须和jwt.sign({ name: name }, //'node1', { expiresIn: 15 })第二个参数名字一致统一 algorithms: ['HS256'], // 必填,加密算法 }).unless({ path: ['/login'], // 除了个接口,其他都需要认证 }) ) app.post('/login', (req, res) => { console.log('接收到的数据是', req.body) const { name, password } = req.body if (password === '123456') { // 创建token // expiresIn:过期时间,单位是秒 // - 参数1:必填,对象形式;希望在token中保存的数据 // - 参数2:必填,字符串形式;加密的钥匙;后续验证token的时候,还需要使用 // - 参数3:可选,对象形式;配置项,比如可以配置token的有效期 // - 参数4:可选,函数形式;生成token之后的回调 // - 生成的token前面,必须拼接 `Bearer ` 这个字符串。 const tokenStr = jwt.sign({ name: name }, 'node1', { expiresIn: 15 }) const token = 'Bearer ' + tokenStr res.json({ msg: '登录成功', token: token }) } else { res.json({ msg: '登录失败' }) } }) app.get('/test', (req, res) => { res.json({ msg: '测试tokenOk' }) }) // 在所有的路由最后,加入错误处理中间件,来提示token方面的错误。 app.use((err, req, res, next) => { if (err.name === 'UnauthorizedError') { // res.status(401).send('invalid token...'); res.status(401).send({ status: 1, message: '身份认证失败!' }) } }) app.listen(3000, () => { console.log(3000) })
- cookie不能存储重要的信息
- session储存的信息在服务器上
- 当访问用户过多的时候,一个服务器储存有限,特点时间大批用户涌入,服务器可能会瘫痪
- 当在*登陆的信息后,去到其他地区之后,服务器没有你的信息,就还需要登录验证
- 只能用于特定的服务器,服务器关闭的开启都会影响用户的体验
- 对于一个域名多个服务器来说不太试用
- 目前现在的主流公司,一般都是以token来储存用户的信息的