nodeJS入门(四)之身份验证

一、bcrypt模块

bcrypt模块用于对用户密码进行加密。

1.1、简单介绍一下

bcrypt 算法相对来说是运算比较慢的算法,在密码学界有句常话:越慢的算法越安全。算法越慢,黑客破解成本越高。
通过salt 和 cost这两个值来减缓加密过程。bcrypt是单向的,而且经过salt 和 cost的处理,使其受rainbow攻击破解的概率大大降低,同时破解的难度也提升不少,相对于MD5等加密方式更加安全,而且使用也比较简单。
​ ​
bcrypt算法将salt随机并混入最终加密后的密码,验证时也无需单独提供之前的salt,从而无需单独处理salt问题。

其实,说这么多还是得学会怎么用!

1.2、安装

 npm  i  bcrypt --save

1.3、加密

我们使用bcrypt模块是为了给用户密码等隐秘信息加密,这样就能防止密码泄露等问题。

密码加密实例代码:

//1、引入模块
let  bcrypt= require("bcrypt");

//2、 产生salt
let salt = bcrypt.genSaltSync(11); // 11 是迭代次数

//3、加密
// 格式:bcrypt.hashSync(用户注册时输入的密码,salt); 
let pass = bcrypt.hashSync("123456",salt); 

console.log("pass",pass);//pass就是加密后的结果,把这个可以存储到数据库中

//加密后的密码格式如下:
// $2b$10$1MtFAztjfpDTm8z.PjQTwOo6k4FrRiXwbZKq0oAKWqWI94mhzJfTG

这时,我们存入数据库的密码就变成加密过后的内容了,那在登录时怎么对比用户输入的密码是否正确呢?

接着往下看:

// 验证密码是否正确
//1、引入模块
let  bcrypt= require("bcrypt");

//格式:bcrypt.compareSync(用户登录时输入的密码,数据库中拿到的密码);
let isMatch = bcrypt.compareSync("123456","$2b$11$jMC6xi32MVFDApY.valjJ.f7W5gGXQoLj3VZlrPQ8Fik.pVQ/szTK");

//true:表示密码一致;false:密码不一致
console.log(isMatch);

这样就ok了!

二、身份验证

HTTP 是一种无状态的协议,也就是它并不知道是谁访问(每次的访问和以前哪次的访问来自同一个客户端)。客户端用户名密码通过了身份验证,但是下次这个客户端再发送请求时候,还得再验证。

有问题肯定就有解决方案:(以下2种)

2.1、session(会话)

2.1.1、session实现身份验证的思路

1)、当用户打开浏览器,首次访问某个网站(服务器),服务器会产生一个唯一的编号(sessionId),在响应时,把该编号发给客户端,客户端把该编号存储在cookie里。

2)、当用户二次访问(如:点击超链)服务器,那么,请求时,会携带保存在cookie里的编号,服务器端拿到该编号后,会跟session中的编号进行对比,就可以判断本次访问和哪次访问是同一个客户端。

2.1.2、session的业务流程

1、客户端发送用户名和密码,请求登录

​ 2、服务端收到请求,验证用户名与密码

​ 3、验证成功后,服务端种一个cookie或发一个字符到客户端,同时服务器保留一份session

​ 4、客户端收到 响应 以后可以把收到的字符存到cookie

​ 5、客户端每次向服务端请求资源的cookie会自动携带

​ 6、服务端收到请求,然后去验证cookie和session,如果验证成功,就向客户端返回请求的库数据

Session存储位置: 服务器内存,磁盘,或者数据库里

Session存储内容: id,存储时间,用户名等

客户端携带 : cookie自动带

2.1.3、express-session

1、安装

npm i express-session -S

2、引入session模块:

var session = require('express-session');

3、创建session中间件:

app.use(session(options)); 

实例代码:

app.use(session({
	secret: 'recommend 128 bytes random string',
	cookie: { maxAge: 20 * 60 * 1000 },//session的过期时间(没有错,cookie和session息息相关,所以,是用cookie.maxAge来设置session的过期时间)
 	resave: true,
  	saveUninitialized: true
	})
);

​ 4、保存变量:

req.session.变量名= 值;

​ 5、获取变量:

req.session.变量名

2.2、token

用的较多。

2.2.1、实现思路

在服务端不需要存储用户的登录记录,全部发给客户端由客户端自己存(cookie,localStorage)

​ 1、客户端使用用户名跟密码请求登录
​ 2、服务端收到请求,去验证用户名与密码
​ 3、验证成功后,服务端会签发一个 Token(加了密的字符串),再把这个 Token 发送给客户端
​ 4、客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
​ 5、客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
​ 6、服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

2.2.2、实现步骤

  • jsonwebtoken的安装引入
npm i jsonwebtoken -S
let jwt = require('jsonwebtoken')
  • 生成签名(token)
let token = jwt.sign(payload, secretOrPrivateKey, [options, callback])
  • 校验token
jwt.verify(token, secretOrPublicKey, [options, callback])
token: 制作后的token
secretOrPublicKey] 解密规则,字符串,或者公钥
callback: 回调 err 错误信息 decode 成功后的信息
options] expiresIn 过期时间
  • token删除
    由客户端,负责删除,服务器端没有任何保存,

2.3、session vs token

sessiontoken
服务端保存用户信息×
避免CSRF攻击×
多服务器粘性问题存在不存在

解释一下多服务器粘性问题:

当在应用中进行 session的读,写或者删除操作时,会有一个文件操作发生在操作系统的temp文件夹下,至少在第一次时。假设有多台服务器并且 session在第一台服务上创建。
当你再次发送请求并且这个请求落在另一台服务器上,session
信息并不存在并且会获得一个“未认证”的响应。这时候,就需要把在第一台服务器上保存的session给其它服务器上也保存。然而,在基于token 的认证中,这个问题很自然就被解决了。没有粘性 session 的问题,因为在每个发送到服务器的请求中这个请求的 token都会被拦截。

2.4、保存信息给浏览器(cookie)

  • 前端保存
cookie/localstorage
  • 后端操作cookie

服务器给浏览器种cookie: cookie-parser

Cookie的创建(express会将其填入Response Header中的Set-Cookie):

格式:

1、添加cookie

res.cookie(name, value [, options]);
//参数:
   name: cookie名
   value: 类型为String和Object。
   Option: 类型为对象,可使用的属性如下:
   domain:cookie在什么域名下有效,类型为String,。默认为网站域名
   expires: cookie过期时间,类型为Date。如果没有设置或者设置为0,那么该cookie只在这个session有效
   maxAge: 实现expires的功能,设置cookie过期的时间,类型为String,指明从现在开始,多少毫秒以后,cookie到期。
   path: cookie在什么路径下有效,默认为'/',类型为String
   secure:只能被HTTPS使用,类型Boolean,默认为false
   

 

2、删除cookie

res.clearCookie(name [, options]);

3、获取cookie

req.cookies.键名  //cookie是在客户端保存,每次请求时会携带,所以,用req对象获取cookie

示例:

//设置键为name,值为:baobao,可访问的域名为:.example.com,可访问的路径:/admin',只可以用https访问
res.cookie('name', 'baobao', { 
		domain: '.example.com', 
			maxAge:10000*1000,
		path: '/admin', 
		secure: true 
		});

//cookie的value为对象
res.cookie('cart', { items: [1,2,3] });

三、文件上传

3.1、基本思路

前端表单->后端接收到文件本身->保存到服务器上->给数据库记录文件一些信息(如:文件路径)->库返回给nodejs相关信息->nodejs返回给前端

前端:

<form enctype="multipart/form-data" action="" method="post">
      <input type=file  name="fieldname"  />
</form>

实现

multer->文件名会随机->fs模块改名->path系统模块解析磁盘路径

后端:multer 接受 form-data编码数据

3.2、multer中间件

multer 接受 form-data编码数据,所以,要求前端携带时注意一下,如:

<form enctype="multipart/form-data" />

使用

//1 引入(在app.js里)
let multer  = require('multer');
//2 实例化  
let objMulter = multer({ dest: './upload' }); //dest: 指定 保存位置(存到服务器)
//安装中间件, 
app.use(objMulter.any());  //允许上传什么类型文件,any 代表任何类型  

中间件扩展了req请求体 req.files

app.post('/reg',(req,res)=>{
    req.files//为一个数组,取值时注意
})

​ fieldname: 表单name名
​ originalname: 上传的文件名(浏览器端选择的文件的名字)
​ encoding: 编码方式
​ mimetype: 文件类型
​ buffer: 文件本身
​ size:尺寸
​ destination: 上传后,文件保存的路径 (服务器端的路径)
​ filename: 上传后,保存后的文件名 不含后缀
​ path: 上传后,保存磁盘路径+保存后的文件名 不含后缀

前端使用form发送请求代码

<form action="/upload" enctype="multipart/form-data" method="post" >
    <input type="text" name="username" >
    <input type="file" name="files" >
    <input type="submit" value="上传">
</form>    

前端使用ajax发送请求:

<body>
    <form action="regSave" method="post" >
        用户名<input type="text" name="username" ><br/>
        头像:
        <img style="width:50px;height:50px" id="logoImg" />
        
            <input type="file" id="photoFile" style="display: none;" onchange="upload()">
        
        <a href="javascript:void(0)" onclick="uploadPhoto()">选择图片</a>
        
        <input name="logo" type="hidden" id="logoInput" >     <br/>   
        
        <input type="submit" value="注册" >
    </form>    
</body>
</html>

<script src="js/jquery-3.2.1.min.js"></script>
<script>
    function uploadPhoto() {
        $("#photoFile").click();//选择文件的按钮
    }
    //上传
   function upload(){
        if ($("#photoFile").val() == '') {
            return;
        }
        console.log($("#photoFile").val());
       
        var formData = new FormData();
       
        formData.append('photo', document.getElementById('photoFile').files[0]);
       
        $.ajax({
            url:"/upload",
            type:"post",
            data:formData,  
            contentType:false,
            processData:false,        
            success:function(str){
                console.log(str);//图片文件路径
                $("#logoImg").attr("src",str);
                $("#logoInput").val(str);
            }
        });
    };
</script>

四、BSR&&SSR&&SEO

4.1、BSR

客户端渲染(BSR:Browser Side Render)

客户端渲染:就是客户端在操作DOM.

渲染过程:在服务端放了一个html页面,客户端发起请求,服务端把页面发送过去,客户端从上到下依次解析,如果在解析的过程中,发现ajax请求,再次向服务器发送新的请求,客户端拿到ajax
响应的结果,渲染在页面上,这个过程中至少和服务端交互了两次

  • 优缺点

缺点:请求次数会增加,如果渲染逻辑复杂,数量大的话,尽量不要使用客户端渲染。
优点:网络上传输的数据量小,局部刷新

4.2、SSR

服务端渲染(SSR)

渲染过程:前端发送请求,服务器端从数据库中拿出数据,通过render()函数,把数据渲染在模板(ejs)里,产生了HTML代码,把渲染结果发给了前端,整个过程只有一次交互。
优点:提高渲染速度
缺点:网络上传输的数据量大了,页面全部刷新。

4.3、SSR与BSR的区别

大多数网站里,既有服务端渲染又有客户端渲染 。

  • 服务端渲染(SSR)和客户端渲染(BSR)的区别

1)、客户端渲染不利于 SEO 搜索引擎优化,服务器端渲染有利于SEO搜索引擎优化
2)、服务端渲染是可以被爬虫抓取到的,客户端异步渲染是很难被爬虫抓取到的

4.4、SEO

SEO(Search Engine Optimization):搜索引擎优化

作用:提升网站关键词排名,提高访问量

  • 搜索引擎不友好的网站有哪些特征:

1、网页中大量采用图片或者Flash等富媒体(Rich
Media)形式,没有可以检索的文本信息,而SEO最基本的就是文章SEO和图片SEO;
2、网页没有标题,或者标题中没有包含有效的关键词;
3、网页正文中有效关键词比较少(最好自然而重点分布,不需要特别的堆砌关键词);
4、网站导航系统让搜索引擎“看不懂”;
5、大量动态网页影响搜索引擎检索; 6、没有被其他已经被搜索引擎收录的网站提供的链接;
7、网站中充斥大量欺骗搜索引擎的垃圾信息,如“过渡页”、“桥页”、颜色与背景色相同的文字;
8、网站中缺少原创的内容,完全照搬硬抄别人的内容等。 9、网站地图,网站日记提取蜘蛛爬行轨迹。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值