今天小編給大家分享一下Node中express的身份認(rèn)證怎么使用的相關(guān)知識點,內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
十載的利通網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。全網(wǎng)整合營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整利通建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。創(chuàng)新互聯(lián)從事“利通網(wǎng)站設(shè)計”,“利通網(wǎng)站推廣”以來,每個客戶項目都認(rèn)真落實執(zhí)行。
目前主流的Web開發(fā)模式有兩種:
基于服務(wù)端渲染的傳統(tǒng)Web開發(fā)模式
服務(wù)端渲染的概念:服務(wù)器發(fā)送給客戶端的HTML頁面,是在服務(wù)器通過字符串的拼接,動態(tài)生成的。因此,客戶端不需要使用Ajax這樣的技術(shù)額外請求頁面的數(shù)據(jù)。
代碼如下:
app.get('/index.html',(req,res)=>{
// 1.要渲染的數(shù)據(jù)
const user = {name:'zs',age:20}
// 2.服務(wù)器通過字符串的拼接,動態(tài)生成 HTML 內(nèi)容
const html = `
姓名:${user.name},年齡:${user.age}
`
// 3.把生成好的頁面內(nèi)容響應(yīng)給客戶端。因此客戶端拿到的是帶有真實數(shù)據(jù)的 HTML 頁面
res.send(html)
})
服務(wù)端渲染的優(yōu)缺點
優(yōu)點:
1)前端耗時少:因為服務(wù)器端負(fù)責(zé)動態(tài)生成 HTML內(nèi)容,瀏覽器只需要直接渲染頁面即可。尤其是移動端,更省電。
2)有利于SEO:因為服務(wù)器端響應(yīng)的是完整的 HTML頁面內(nèi)容,所以爬蟲更容易爬取獲得信息,更有利于SEO。
缺點:
1)占用服務(wù)器端資源:即服務(wù)器端完成HTML頁面內(nèi)容的拼接,如果請求較多,會對服務(wù)器造成一定的訪問壓力。
2)不利于前后端分離,開發(fā)效率低:使用服務(wù)器端渲染,則無法進(jìn)行分工合作,尤其對于前端復(fù)雜度高的項目,不利于項目高效開發(fā)。
基于前后端分離的新型Web開發(fā)模式
前后端分離的概念:前后端分離的開發(fā)模式,依賴于Ajax技術(shù)的廣泛應(yīng)用。簡而言之,前后端分離的Web開發(fā)模式,就是后端只負(fù)責(zé)提供API接口,前端使用Ajax調(diào)用接口的開發(fā)模式。
前后端分離的優(yōu)缺點
優(yōu)點:
1)開發(fā)體驗好。前端專注于UI頁面的開發(fā),后端專注于api的開發(fā),且前端有更多的選擇性
2)用戶體驗好。Ajax技術(shù)的廣泛應(yīng)用,極大的提高了用戶的體驗,可以輕松實現(xiàn)頁面的局部刷新
3)減輕了服務(wù)器端的渲染壓力。因為頁面最終是在每個用戶的瀏覽器中生成的。
缺點:
1)不利于SE0。因為完整的HTML頁面需要在客戶端動態(tài)拼接完成,所以爬蟲對無法爬取頁面的有效信息。(解決方案:利用Vue、React等前端框架的SSR (server side render)技術(shù)能夠很好的解決SEO問題!)
如何選擇Web開發(fā)模式
比如企業(yè)級網(wǎng)站,主要功能是展示而沒有復(fù)雜的交互,并且需要良好的SEO,則這時我們就需要使用服務(wù)器端渲染;而類似后臺管理項目,交互性比較強,不需要考慮SEO,那么就可以使用前后端分離的開發(fā)模式。
因此,具體使用何種開發(fā)模式并不是絕對的,為了同時兼顧了首頁的渲染速度和前后端分離的開發(fā)效率,一些網(wǎng)站采用了首屏服務(wù)器端渲染+其他頁面前后端分離的開發(fā)模式。
身份認(rèn)證(Authentication)又稱“身份驗證”、“鑒權(quán)”,是指通過一定的手段,完成對用戶身份的確認(rèn)。在Web開發(fā)中,也涉及到用戶身份的認(rèn)證,例如:各大網(wǎng)站的手機(jī)驗證碼登錄、郵箱密碼登錄、二維碼登錄等。
身份認(rèn)證的目的:為了確認(rèn)當(dāng)前所聲稱為某種身份的用戶,確實是所聲稱的用戶。
不同開發(fā)模式下的身份認(rèn)證
對于服務(wù)端渲染和前后端分離這兩種開發(fā)模式來說,分別有著不同的身份認(rèn)證方案:
1)服務(wù)端渲染推薦使用 Session認(rèn)證機(jī)制
2)前后端分離推薦使用 JWT認(rèn)證機(jī)制
HTTP協(xié)議的無狀態(tài)性:指的是客戶端的每次HTTP請求都是獨立的,連續(xù)多個請求之間沒有直接的關(guān)系,服務(wù)器不會主動保留每次HTTP請求的狀態(tài)。而要想突破HTTP的無狀態(tài)的限制,就需要借助Cookie。
Cookie是存儲在用戶瀏覽器中的一段不超過4KB的字符串。它由一個名稱(Name)、一個值(Value)和其它幾個用于控制Cookie有效期、安全性、使用范圍的可選屬性組成。不同域名下的Cookie 各自獨立,每當(dāng)客戶端發(fā)起請求時,會自動把當(dāng)前域名下所有未過期的Cookie一同發(fā)送到服務(wù)器。
Cookie的特性:自動發(fā)送、域名獨立、過期時限、4KB限制。
Cookie在身份認(rèn)證中的作用
客戶端第一次請求服務(wù)器的時候,服務(wù)器通過響應(yīng)頭的形式,向客戶端發(fā)送一個身份認(rèn)證的Cookie,客戶端會自動將Cookie保存在瀏覽器中。隨后,當(dāng)客戶端瀏覽器每次請求服務(wù)器的時候,瀏覽器會自動將身份認(rèn)證相關(guān)的Cookie,通過請求頭的形式發(fā)送給服務(wù)器,服務(wù)器即可驗明客戶端的身份。
Cookie的安全性問題
由于Cookie是存儲在瀏覽器中的,而且瀏覽器提供了讀寫Cookie的API,因此Cookie很容易被偽造,不具有安全性。因此不建議服務(wù)器將重要的隱私數(shù)據(jù),通過Cookie的形式發(fā)送給瀏覽器,所以千萬不要使用Cookie存儲重要且隱私的數(shù)據(jù),比如用戶的身份信息、密碼等。
而Session的認(rèn)證機(jī)制就是為了提高cookie安全性的一種認(rèn)證機(jī)制。
在Express項目中,只需安裝 express-session 中間件,即可在項目中使用Session認(rèn)證:
npm install express-session
express-session中間件安裝完成后,需要通過app.use()來注冊session中間件,代碼如下:
// 配置 Session 中間件
const session = require('express-session')
app.use(session({
secret:'Session_test', // secret 屬性值可以是任意字符串
resave:false, // 固定寫法
saveUninitialized:true // 固定寫法
}))
當(dāng)express-session中間件配置成功后,即可通過 req.session來訪問和使用 session 對象,從而存儲用戶的關(guān)鍵信息:
// 登錄的API接口
app.post('/api/login',(req,res)=>{
// 判斷用戶提交的信息是否正確
if(req.body.username !=='admin' || req.body.password !=='123456'){
return res.send({status:1,msg:'登錄失敗'})
}
// 登錄成功后,將成功的用戶信息保存到session中
// 注意:只有成功配置了 express-session 這個中間件后,才能通過 req 點出來 session 這個屬性
req.session.user = req.body // 用戶的信息
req.session.islogin = true // 用戶的登錄狀態(tài)
res.send({status:0,msg:'登錄成功'})
})
當(dāng)然也可以直接從 req.session 對象上獲取之前存儲的數(shù)據(jù)。代碼如下:
app.post('/api/logout',(req,res)=>{
// 清空session信息
req.session.destroy()
res.send({
status:0,
msg:'退出登錄成功'
})
})
Session認(rèn)證的局限性:Session認(rèn)證機(jī)制需要配合Cookie 才能實現(xiàn)。由于Cookie默認(rèn)不支持跨域訪問,所以,當(dāng)涉及到前端跨域請求后端接口的時候,需要做很多額外的配置,才能實現(xiàn)跨域Session認(rèn)證。
當(dāng)前端請求后端接口不存在跨域問題的時候,推薦使用Session身份認(rèn)證機(jī)制。
JWT(英文全稱:JSON Web Token)是目前最流行的跨域認(rèn)證解決方案。當(dāng)前端需要跨域請求后端接口的時候,不推薦使用Session身份認(rèn)證機(jī)制,推薦使用JWT認(rèn)證機(jī)制。
JWT工作原理:用戶的信息通過Token字符串的形式,保存在客戶端瀏覽器中。服務(wù)器通過還原Token字符串的形式來認(rèn)證用戶的身份。
JWT的組成部分:
Header(頭部)、Payload(有效荷載)、Signature(簽名)。
Payload部分才是真正的用戶信息,它是用戶信息經(jīng)過加密之后生成的字符串。
Header和Signature是安全性相關(guān)的部分,只是為了保證Token的安全性。
三者之間使用英文的“.”分隔,格式如下:
Header.Payload.Signature
JWT的使用方式: 客戶端收到服務(wù)器返回的WT之后,通常會將它儲存在localStorage或sessionStorage中。此后,客戶端每次與服務(wù)器通信,都要帶上這個WT的字符串,從而進(jìn)行身份認(rèn)證。推薦的做法是把JWT放在HTTP請求頭的Authorization字段中,格式如下:
Authorization: Bearer
運行如下命令安裝兩個JWT相關(guān)的包:
# jsonwebtoken用于生成JWT字符串
# express-jwt用于將JWT字符串解析還原成JSON對象
npm install jsonwebtoken express-jwt@5.3.3
定義secret密鑰:為了保證JWT字符串的安全性,防止JWT字符串在網(wǎng)絡(luò)傳輸過程中被別人破解,我們需要專門定義一個用于加密和解密的secret密鑰。
當(dāng)生成JWT字符串的時候,需要使用 secret 密鑰對用戶的信息進(jìn)行加密,最終得到加密好的JWT字符串;當(dāng)把JWT字符串解析還原成JSON對象的時候,需要使用secret密鑰進(jìn)行解密。
// 定義 secret 密鑰,建議將密鑰命名為 secretKey
const secretKey = 'Hello Node.js'
生成JWT字符串:調(diào)用jsonwebtoken包提供的sign()方法,將用戶的信息加密成JWT字符串,響應(yīng)給客戶端。
// 登錄接口
app.post('/api/login',(req,res)=>{
// 將 req.body 請求體中的數(shù)據(jù),轉(zhuǎn)存為 userinfo 常量
const userinfo = req.body
// 登錄失敗
if(userinfo.username !=='admin' || userinfo.password !=='123456'){
return res.send({
status:400,
message:'登錄失??!'
})
}
// 三個參數(shù)分別是:用戶信息對象,加密密鑰,配置對象
const tokenStr = jwt.sign({username: userinfo.username},secretKey,{expiresIn:'20s'})
// 用戶登錄成功后,生成 JWT 字符串,通過 token 屬性響應(yīng)給客戶端
res.send({
status:200,
message:'登錄成功',
token: tokenStr, // 要發(fā)送給客戶端的 token 字符串
})
})
JWT字符串還原為JSON對象:客戶端每次在訪問那些有權(quán)限接口的時候,都需要主動通過請求頭中的Authorization字段將Token字符串發(fā)送到服務(wù)器進(jìn)行身份認(rèn)證。此時,服務(wù)器可以通過express-jwt這個中間件,自動將客戶端發(fā)送過來的Token解析還原成JSON對象。
// 注冊將 JWT 字符串解析還原成 JSON 對象的中間件
// expiresJWT({secret:secretKey}) 用來解析 Token 的中間件
// .unless({path:[/^\/api\//]}) 用來指定哪些接口不需要訪問權(quán)限
app.use(expressJWT({secret:secretKey}).unless({path:[/^\/api\//]}))
使用req.user獲取用戶信息:當(dāng)express-jwt這個中間件配置成功之后,即可在那些有權(quán)限的接口中,使用req.user對象,來訪問從WT字符串中解析出來的用戶信息了,示例代碼如下:
app.get('/admin/getinfo',function(req,res){
// 使用 req.user 獲取用戶信息,并使用data屬性將用戶信息發(fā)送給客戶端
console.log(req.user);
res.send({
status:200,
message:'獲取用戶信息成功',
data:req.user, // 要發(fā)送給客戶端的用戶信息
})
})
捕獲解析JWT失敗后產(chǎn)生的錯誤:當(dāng)使用express-jwt解析Token字符串時,如果客戶端發(fā)送過來的Token字符串過期或不合法,會產(chǎn)生一個解析失敗的錯誤,影響項目的正常運行。我們可以通過 Express的錯誤中間件,捕獲這個錯誤并進(jìn)行相關(guān)的處理,示例代碼如下:
// 使用全局錯誤處理中間件,捕獲解析 JWT 失敗后產(chǎn)生的錯誤
app.use((err, req, res, next) => {
// 這次錯誤是由 token 解析失敗導(dǎo)致的
if (err.name === 'UnauthorizedError') {
return res.send({
status: 401,
message: '無效的token',
})
}
res.send({
status: 500,
message: '未知的錯誤',
})
})
具體詳細(xì)代碼如下:
// 導(dǎo)入 express 模塊
const express = require('express')
// 創(chuàng)建服務(wù)器
const app = express()
// 導(dǎo)入JWT相關(guān)的兩個包
const jwt = require('jsonwebtoken')
const expressJWT = require('express-jwt')
// 允許跨域資源共享
const cors = require('cors')
app.use(cors())
// 解析 post 表單數(shù)據(jù)的中間件
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }))
// 定義 secret 密鑰,建議將密鑰命名為 secretKey
const secretKey = 'Hello Node.js'
// 注冊將 JWT 字符串解析還原成 JSON 對象的中間件
// expiresJWT({secret:secretKey}) 用來解析 Token 的中間件
// .unless({path:[/^\/api\//]}) 用來指定哪些接口不需要訪問權(quán)限
app.use(expressJWT({secret:secretKey}).unless({path:[/^\/api\//]}))
// 登錄接口
app.post('/api/login',(req,res)=>{
// 將 req.body 請求體中的數(shù)據(jù),轉(zhuǎn)存為 userinfo 常量
const userinfo = req.body
// 登錄失敗
if(userinfo.username !=='admin' || userinfo.password !=='123456'){
return res.send({
status:400,
message:'登錄失?。?#39;
})
}
// 三個參數(shù)分別是:用戶信息對象,加密密鑰,配置對象
const tokenStr = jwt.sign({username: userinfo.username},secretKey,{expiresIn:'50s'})
// 用戶登錄成功后,生成 JWT 字符串,通過 token 屬性響應(yīng)給客戶端
res.send({
status:200,
message:'登錄成功',
token: tokenStr, // 要發(fā)送給客戶端的 token 字符串
})
})
// 這是一個有權(quán)限的API接口
app.get('/admin/getinfo',function(req,res){
// 使用 req.user 獲取用戶信息,并使用data屬性將用戶信息發(fā)送給客戶端
console.log(req.user);
res.send({
status:200,
message:'獲取用戶信息成功',
data:req.user, // 要發(fā)送給客戶端的用戶信息
})
})
// 使用全局錯誤處理中間件,捕獲解析 JWT 失敗后產(chǎn)生的錯誤
app.use((err, req, res, next) => {
// 這次錯誤是由 token 解析失敗導(dǎo)致的
if (err.name === 'UnauthorizedError') {
return res.send({
status: 401,
message: '無效的token',
})
}
res.send({
status: 500,
message: '未知的錯誤',
})
})
// 調(diào)用app.listen 方法,指定端口號并啟動web服務(wù)器
app.listen(80,function(){
console.log('Express server running at http://127.0.0.1:80');
})
以上就是“Node中express的身份認(rèn)證怎么使用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。