西安 美院 網(wǎng)站建設(shè)百度關(guān)鍵詞的費用是多少
Session-Cookie 鑒權(quán)
cookie介紹
- Cookie 存儲在客戶端,可隨意篡改,不安全
- 有大小限制,最大為 4kb
- 有數(shù)量限制,一般一個瀏覽器對于一個網(wǎng)站只能存不超過 20 個 Cookie,瀏覽器一般只允許存放 300個 Cookie
- Cookie 是不可跨域的,但是一級域名和二級域名是允許共享使用的(靠的是 domain)
session介紹
當(dāng)瀏覽器訪問服務(wù)器并發(fā)送第一次請求時,服務(wù)器端會創(chuàng)建一個session對象,生成一個類似于 key,value的鍵值對,然后將key(cookie)返回到瀏覽器(客戶)端,瀏覽器下次再訪問時,攜帶key(cookie), 找到對應(yīng)的session(value)。 客戶的信息都保存在session中
流程圖解
代碼實踐
技術(shù)棧
- 前端:React
- 后端:Express + MongoDB
后端部分
1.安裝express-session
npm install express-session --save
2.在路由前配置中間件
//配置中間件
app.use(session({secret: "this is Chris Wu", // 可以隨便寫。 一個 String 類型的字符串,作為服務(wù)器端生成 session 的簽名name: "session_id" /*保存在本地cookie的一個名字 默認(rèn)connect.sid可以不設(shè)置*/,resave: false /*強制保存 session 即使它并沒有變化,。默認(rèn)為 true。建議設(shè)置成 false。*/,saveUninitialized: true, //強制將未初始化的 session 存儲。默認(rèn)值是true建議設(shè)置成truecookie: {maxAge: 1000 * 30 * 60/*過期時間*/,secure: false} /*secure https這樣的情況才可以訪問cookie*/,//設(shè)置過期時間比如是30分鐘,只要游覽頁面,30分鐘沒有操作的話在過期rolling: true, //在每次請求時強行設(shè)置 cookie,這將重置 cookie 過期時間(默認(rèn):false)})
);
3.在用戶登錄接口中設(shè)置session req.session.user = username
// 用戶登錄
const signin = async (req, res, next) => {// 前端傳過來的用戶名和密碼const { username, password } = req.body// 從數(shù)據(jù)庫中查詢用戶let result = await usersModel.findUser(username) // 驗證用戶是否是合法用戶if (result) {// 設(shè)置 sessionreq.session.user = username;res.send({code:1,data:'登陸成功!'});} else {res.send({code:0,data:'用戶名或密碼錯誤!'});}
}
登錄成功后,我們可以打開瀏覽器F12的Application中的Cookies查看,已經(jīng)生成了一個key為session_id的cookie
4.在需要登錄狀態(tài)下的請求,我們可以通過req.session.user
判斷,例如一個檢查登錄的接口
app.get("/check", function (req, res) {//獲取sesssionif (req.session.user) {/*獲取*/res.send("你好" + req.session.user + "歡迎回來");} else {// 獲取不到就返回未登錄信息給前端,前端跳到登錄頁面res.send({errCode: 10001,msg:"未登錄"});}
});
5.如果想銷毀session
app.get("/logout",function(req,res){//銷毀req.session.destroy(function(err){console.log(err);})res.send('退出登錄成功');});
到這一步后端的鑒權(quán)已初步完成
但是設(shè)想一下cookie中的maxAge只設(shè)置了10秒,用戶每一次操作的間隔會很長,再想操作頁面時cookie已過期,那又需要重新登錄,這樣體驗感會很差😅😅
6.所以我們可以設(shè)置一個全局的中間件,在每次請求時更新session
這個中間件需要放在路由前和session中間件后
app.use((req,res,next)=>{if(req.url.includes('signin')){next();return;}console.log(req.session)if(req.session.user){// 通過new Date()更新sessionreq.session.mydate = new Date();next();}else {res.status(401).send({code:0})}
})
7.session可以結(jié)合數(shù)據(jù)庫做持久化操作,當(dāng)服務(wù)器掛掉時也不會導(dǎo)致某些客戶信息丟失。 我使用的是MongoDB
安裝connect-mongo
,引入并直接在session中間件中間件中添加如下配置
注意cookie的過期時間和數(shù)據(jù)庫中的過期時間要一致
const MongStore = require('connect-mongo')
//配置中間件
app.use(session({secret: "this is string key", name: "session_id" resave: false saveUninitialized: true, cookie: {maxAge: 1000 * 30 * 60secure: false} rolling: true, store: MongStore.create({mongoUrl:'mongodb://localhost:27017/react_login_session',ttl:1000 * 60 *30})})
);
到這里后端的工作已全部完成啦
前端部分
1.登錄部分
2.axios的封裝 由于sessionID保存在cookie中,每次請求會直接帶上cookie,使用請求攔截中無需操作
但是如果cookie失效,后端會返回401錯誤碼,所以在請求攔截中需要判斷,返回登錄頁
這里由于不太熟悉React的路由哈哈哈😅😅,所以直接用 window.location.href
跳轉(zhuǎn)登錄頁了
到這一步前端的工作也完成了
坑!!!
這期間遇到的坑竟然是跨域問題!!
問題
一開始我為了方便就用了npm i cors
,直接調(diào)用這個中間件解決跨域
請求時session中保存的字段消失了!!
然后我通過打印req.session
發(fā)現(xiàn)復(fù)雜請求會先發(fā)一次option預(yù)檢,再發(fā)送真實的請求,這期間session中的字段就會消失
解決
需要在請求頭中加上這兩行
res.header("Access-Control-Allow-Origin”,"http://locallhost:3000") 不能為*了,必須指定
response.setHeader("Access-Control-Allow-Credentials",true");//是否支持cookie跨域
當(dāng)然也可以前端利用webpack中的代理解決跨域,就避免了這個坑
END
- session-cookie鑒權(quán)的操作并不難,可是Session 存儲在服務(wù)端,增大了服務(wù)端的開銷,用戶量大的時候會大大降低服務(wù)器性能,并且非常不安全,Cookie 將數(shù)據(jù)暴露在瀏覽器中,增加了數(shù)據(jù)被盜的風(fēng)險(容易被 CSRF 等攻擊)所以下一篇文章將介紹JWT的操作給大家
- 希望這篇文章可以幫助到有需要的小伙伴,有問題可以在評論區(qū)留言或私信我
最后
最近還整理一份JavaScript與ES的筆記,一共25個重要的知識點,對每個知識點都進(jìn)行了講解和分析。能幫你快速掌握J(rèn)avaScript與ES的相關(guān)知識,提升工作效率。
有需要的小伙伴,可以點擊下方卡片領(lǐng)取,無償分享