Angular.js與node.js項(xiàng)目里用cookie校驗(yàn)賬戶登錄詳解
前言
最近的新項(xiàng)目中,用戶登錄需要采用cookie來(lái)記住用戶,校驗(yàn)身份。所以本文就把實(shí)現(xiàn)的過(guò)程總結(jié)出來(lái)分享給大家,需要的朋友們可以參考學(xué)習(xí)。
在header中攜帶authId登錄
在之前老的項(xiàng)目里,沒(méi)有采用cookie來(lái)記錄用戶登錄狀態(tài),而是在請(qǐng)求的header中攜帶一個(gè)身份標(biāo)識(shí)來(lái)校驗(yàn),大致方案如下:
- 客戶端使用post請(qǐng)求提交user、password給服務(wù)端進(jìn)行登錄操作;
- 服務(wù)端校驗(yàn)用戶是否合法,如果合法將產(chǎn)生一個(gè)唯一的身份標(biāo)識(shí)authId,返回給客戶端,客戶端將此authId存放本地(如localStorage);
- 客戶端在每次需要校驗(yàn)身份的請(qǐng)求中,往header中加入這個(gè)authId;
- 服務(wù)端檢測(cè)當(dāng)前的authId是否有效,有效則表示當(dāng)前用戶合法,允許操作;
- 客戶端用戶登出的時(shí)候,發(fā)送一個(gè)delete請(qǐng)求,告訴服務(wù)端用戶注銷,同時(shí)刪除本地的authId信息;
- 服務(wù)端收到注銷請(qǐng)求后,刪除當(dāng)前的authId數(shù)據(jù)。
上面的方案,如果其他客戶端知道了這個(gè)authId后,可以在其他客戶端模擬身份,不安全,因此棄用。
用cookie記住用戶
新項(xiàng)目中,將采用此文即將介紹的方案–利用cookie來(lái)記住用戶。主要流程是:
- 客戶端使用post請(qǐng)求提交user、password給服務(wù)端進(jìn)行登錄操作;
- 服務(wù)端校驗(yàn)用戶是否合法,如果合法將產(chǎn)生一個(gè)唯一的身份標(biāo)識(shí)authId,以cookie的形式返回給客戶端;
- 客戶端再次請(qǐng)求服務(wù)端時(shí),會(huì)攜帶此前已經(jīng)拿到的cookie給服務(wù)端,服務(wù)端校驗(yàn)是否合法,合法則可以繼續(xù)操作;
- 客戶端用戶登出的時(shí)候,發(fā)送一個(gè)delete請(qǐng)求,告訴服務(wù)端用戶注銷,服務(wù)端刪除登錄標(biāo)識(shí)。
整個(gè)過(guò)程可以用下面這張圖簡(jiǎn)單表示:
前臺(tái)用angular搭建單頁(yè)客戶端應(yīng)用,后臺(tái)用node搭建服務(wù)器,數(shù)據(jù)存放在mongodb中,這三個(gè)技術(shù)及cookie基礎(chǔ)知識(shí)本文不做介紹,感興趣的同學(xué)可以自行了解。
以下的代碼都是最簡(jiǎn)單的get/post請(qǐng)求,但也是最核心的部分,其他有關(guān)登錄的繁瑣操作,感興趣的同學(xué)可以自行補(bǔ)充。
從開(kāi)始–>結(jié)束,遇到的問(wèn)題
首先,我用的是最基礎(chǔ)的post請(qǐng)求,服務(wù)端也只是簡(jiǎn)單的返回?cái)?shù)據(jù),部分簡(jiǎn)單但比較核心的代碼如下:
// client $http({ method : 'POST', url : 'http://127.0.0.1:8888/rest/user', data : {name: 'xxx',password:'***'} }).success(function (data) { console.log('login success,data is:'+data); }).error(function (data) { console.log('login error'); }).then(function () { console.log(arguments); }); // server var cookie = "authId=" + authId; res.setHeader('Content-Type', 'application/json;charset=utf-8'); res.setHeader('Set-Cookie', cookie + ';Max-Age=3600;HttpOnly=false;Path=/;'); res.writeHead(200, {'Content-Type': 'text/plain'}); res.end();
查看chrome調(diào)試,發(fā)現(xiàn)雖然服務(wù)端的cookie推過(guò)來(lái)了,但整體出了問(wèn)題,提示如下:
XMLHttpRequest cannot load http://127.0.0.1:8888/rest/user. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:62427' is therefore not allowed access.
分析問(wèn)題后,發(fā)現(xiàn)原因是來(lái)自客戶端的請(qǐng)求不能跨域訪問(wèn)服務(wù)端的請(qǐng)求,請(qǐng)求的資源header中沒(méi)有攜帶允許跨越請(qǐng)求的信息。根據(jù)這個(gè)提示,我們把服務(wù)端的代碼稍加改進(jìn)后,如下:
// server var cookie = "authId=" + authId; res.setHeader('Content-Type', 'application/json;charset=utf-8'); res.setHeader('Set-Cookie', cookie + ';Max-Age=3600;HttpOnly=false;Path=/;'); // 添加允許跨越的頭信息 res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); res.writeHead(200, {'Content-Type': 'text/plain'}); res.end();
解釋下上面代碼什么意思,第一句主要是允許來(lái)自任何域的請(qǐng)求訪問(wèn),第二句是允許哪些類型的請(qǐng)求訪問(wèn)。加上后再次運(yùn)行,提示如下:
XMLHttpRequest
cannot load http://127.0.0.1:8888/rest/user. Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
原因是來(lái)自客戶端的請(qǐng)求中,Content-Type頭字段,在服務(wù)端的響應(yīng)信息的頭中,沒(méi)有攜帶,再次修改代碼如下:
// server var cookie = "authId=" + authId; res.setHeader('Content-Type', 'application/json;charset=utf-8'); res.setHeader('Set-Cookie', cookie + ';Max-Age=3600;HttpOnly=false;Path=/;'); // 添加允許跨越的頭信息 res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); // 添加支持Content-Type允許的頭信息 res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); res.writeHead(200, {'Content-Type': 'text/plain'}); res.end();
再次運(yùn)行代碼,發(fā)現(xiàn)沒(méi)有錯(cuò)誤提示,但是當(dāng)我們?cè)俅握?qǐng)求服務(wù)器時(shí),發(fā)現(xiàn)客戶端的請(qǐng)求并沒(méi)有攜帶cookie信息,這顯然不是我們想要的效果:
在查閱了一段時(shí)間后了解到,客戶端是會(huì)默認(rèn)攜帶cookie給服務(wù)端的,但是當(dāng)客戶端的請(qǐng)求是跨域請(qǐng)求時(shí),由于跨域請(qǐng)求本身就有風(fēng)險(xiǎn),而攜帶給cookie同樣有風(fēng)險(xiǎn)。
因此在進(jìn)行跨域訪問(wèn)時(shí),客戶端不會(huì)將服務(wù)端返回的cookie攜帶。此時(shí),我們需要同時(shí)在客戶端和服務(wù)端都設(shè)置“withCredentials”為true,代碼如下:
// client $http({ method : 'POST', url : 'http://127.0.0.1:8888/rest/user', withCredentials: true data : {name: 'xxx',password:'***'} }).success(function (data) { console.log('login success,data is:'+data); }).error(function (data) { console.log('login error'); }).then(function () { console.log(arguments); }); // server var cookie = "authId=" + authId; res.setHeader('Content-Type', 'application/json;charset=utf-8'); res.setHeader('Set-Cookie', cookie + ';Max-Age=3600;HttpOnly=false;Path=/;'); // 添加允許跨越的頭信息 res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); // 添加支持Content-Type允許的頭信息 res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // 設(shè)置已攜帶憑證為true //res.setHeader('Access-Control-Allow-Credentials', true); res.writeHead(200, {'Content-Type': 'text/plain'}); res.end();
運(yùn)行后,發(fā)現(xiàn)又有錯(cuò)誤提示,如下:
XMLHttpRequest cannot load http://127.0.0.1:8888/rest/user. Response to preflight request doesn't pass access control check: A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin 'http://localhost:62427' is therefore not allowed access.
分析錯(cuò)誤后發(fā)現(xiàn),原因是當(dāng)設(shè)置了已攜帶憑證參數(shù)為true時(shí),允許跨域請(qǐng)求的源不能設(shè)置為泛型的“*”,因此我們?cè)俅涡薷拇a如下:(最終代碼)
// client $http({ method : 'POST', url : 'http://127.0.0.1:8888/rest/user', withCredentials: true data : {name: 'xxx',password:'***'} }).success(function (data) { console.log('login success,data is:'+data); }).error(function (data) { console.log('login error'); }).then(function () { console.log(arguments); }); // server var cookie = "authId=" + authId; res.setHeader('Content-Type', 'application/json;charset=utf-8'); res.setHeader('Set-Cookie', cookie + ';Max-Age=3600;HttpOnly=false;Path=/;'); // 添加允許跨越的頭信息 // res.setHeader('Access-Control-Allow-Origin', '*'); // 用當(dāng)前的客戶端origin來(lái)取代泛型的“*” res.setHeader('Access-Control-Allow-Origin', 'http://localhost:62427'); res.setHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS'); // 添加支持Content-Type允許的頭信息 res.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // 設(shè)置已攜帶憑證為true res.setHeader('Access-Control-Allow-Credentials', true); res.writeHead(200, {'Content-Type': 'text/plain'}); res.end();
此時(shí),第一次請(qǐng)求服務(wù)端時(shí),服務(wù)端返回cookie信息,以后每次客戶端請(qǐng)求服務(wù)端,客戶端的header中都會(huì)攜帶cookie信息,效果如下圖:
最后
以上就是在使用cookie記住用戶身份時(shí)遇到的一些問(wèn)題及簡(jiǎn)單解決方法,一般在angular應(yīng)用中,可能使用較多的是resoure進(jìn)行http通信,此時(shí)只要在GET/POST/PUT/DELETE等請(qǐng)求的參數(shù)中,將“withCredentials”設(shè)置為true即可。希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流。
- js實(shí)現(xiàn)登錄注冊(cè)框手機(jī)號(hào)和驗(yàn)證碼校驗(yàn)(前端部分)
- JavaScript 完成注冊(cè)頁(yè)面表單校驗(yàn)的實(shí)例
- JavaScript注冊(cè)時(shí)密碼強(qiáng)度校驗(yàn)代碼
- js簡(jiǎn)單實(shí)現(xiàn)用戶注冊(cè)信息的校驗(yàn)代碼
- JS校驗(yàn)與最終登陸界面功能完整示例
- 詳解AngularJs HTTP響應(yīng)攔截器實(shí)現(xiàn)登陸、權(quán)限校驗(yàn)
- jsp登陸校驗(yàn)演示 servlet、login、success
- 攔截JSP頁(yè)面,校驗(yàn)是否已登錄詳解及實(shí)現(xiàn)代碼
- ASP.NET MVC結(jié)合JavaScript登錄、校驗(yàn)和加密
- javascript使用正則表達(dá)式實(shí)現(xiàn)注冊(cè)登入校驗(yàn)
相關(guān)文章
angular強(qiáng)制更新ui視圖的實(shí)現(xiàn)方法
這篇文章主要介紹了angular強(qiáng)制更新ui視圖的實(shí)現(xiàn)方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03angularjs 處理多個(gè)異步請(qǐng)求方法匯總
這篇文章主要介紹了angularjs 處理多個(gè)異步請(qǐng)求方法匯總,需要的朋友可以參考下2015-01-01Angularjs渲染的 using 指令的星級(jí)評(píng)分系統(tǒng)示例
本篇文章主要介紹了Angularjs渲染的 using 指令的星級(jí)評(píng)分系統(tǒng)示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11詳解為Angular.js內(nèi)置$http服務(wù)添加攔截器的方法
所謂攔截器就是在目標(biāo)達(dá)到目的地之前對(duì)其進(jìn)行處理以便處理結(jié)果更加符合我們的預(yù)期。Angular的$http攔截器是通過(guò)$httpProvider.interceptors數(shù)組定義的一組攔截器,每個(gè)攔截器都是實(shí)現(xiàn)了某些特定方法的Factory。本文就介紹了為Angular.js內(nèi)置$http服務(wù)添加攔截器的方法。2016-12-12angularjs實(shí)現(xiàn)上拉加載和下拉刷新數(shù)據(jù)功能
本篇文章主要介紹了angularjs實(shí)現(xiàn)上拉加載和下拉刷新數(shù)據(jù)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06AngularJS通過(guò)$location獲取及改變當(dāng)前頁(yè)面的URL
本篇將介紹AngularJS中的$location服務(wù)的基本用法,$location服務(wù)的主要作用是用于獲取當(dāng)前url以及改變當(dāng)前的url,并且存入歷史記錄。本文通過(guò)示例代碼介紹的很詳細(xì),有需要的朋友們可以參考借鑒,下面來(lái)一起看看吧。2016-09-09AngularJS 單選框及多選框的雙向動(dòng)態(tài)綁定
本篇文章主要介紹了AngularJS 單選框及多選框的雙向動(dòng)態(tài)綁定的相關(guān)知識(shí)。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧2017-04-04angular基于ng-alain定義自己的select組件示例
這篇文章主要介紹了angular基于ng-alain定義自己的select組件示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02