細談Node.js項目實戰

     使用node.js開發的token用戶驗證的網站不少,典型的網站,如豬八戒威客網站,使用了node.js技術。 node

在網站應用中,會爲不一樣的用戶賦予不一樣的權限(好比爲管理員帳戶賦予較高的權限),因此咱們須要在auto()函數中添加用戶認證的流程。 算法

通常來說,最多見的方案是基於cookie 或session 受權管理,但某些場景下這種方案並不適用,好比對要求使用REST 架構的應用,或客戶端對cookie\session 支持不佳(如移動端)等。更有效的方案是在每次請求中都攜帶token(比較常見的OAuth2.0 協議3),並在服務端經過token 進行獨立的認證。這裏既能夠把token 字段加載到請求參數中,也能夠添加到HTTP 請求頭中。固然這裏也能夠是其餘認證信息,好比E-mail 和密碼、API 密鑰、API 密碼等。 數據庫

在咱們的示例中,每一個請求都會提交token 字段,並在接收時把token(經過req.query.token 獲取)和應用中儲存的token(一般使用數據庫儲存,或如本例中簡單地保存在SECRET_TOKEN 常量中)進行比對。若是比對經過則調用next()方法繼續後續處理,若是不經過則調用next(error)觸發Express.js 的錯誤響應:
  express

 
  1. var auth = function(req, res, next) {  
  2. if (req.query.token && token === SECRET_TOKEN) {  
  3. // 校驗經過,進行下一階段處理  
  4. return next();  
  5. } else {  
  6. return next(new Error('Not authorized'));  
  7. // 也能夠 res.send(401);  
  8. }  
  9. }; 

在實踐中,通常使用API 的key 和secret 生成HMAC-SHA1(一種基於散列的信息加密算法)字符串,並把它和接收到的token(req.query.token)進行比對。 後端

注意 在調用next()方法時傳入一個error 對象做爲參數,表示放棄請求處理,這時會觸發Express.js 的錯誤模式,並進入錯誤處理流程。 api

咱們剛纔介紹了REST API 中經常使用的基於token 的認證模式。另一種常見模式是使用cookie 進行用戶認證,這種模式在含有用戶界面的應用中常用。咱們使用cookie 儲存session ID,並在請求時自動提交。從某種意義上講,cookie 有些相似於token,可是cookie使用較爲方便,並不須要開發者作太多的工做。基於session 的認證就是使用這種模式。基於session 的認證在Web 應用中十分常見,也更受推崇,由於瀏覽器能夠自動處理帶有session 的請求頭,並且大多數的後端平臺或框架也能原生支持session。接下來,就讓咱們一塊兒進入在Node.js 中實現基於session 的用戶認證這一小節吧。 瀏覽器

   

基於session 的用戶認證 安全

基於session 的用戶認證藉助於請求體對象req 中的session 對象完成。簡單地說,session 能夠鑑別客戶端,並對應地儲存信息,供同一客戶端全部的後續請求讀取。 服務器

在Express.js 4.x 版(4.1.2 版以及寫本書時使用的4.2.0 版)中,咱們須要手動引入(require())操做session 所依賴的模塊,由於Express.js 4.x 把它們從核心包中剔除了。例如,引入並使用cookie-parser 和express-session 模塊:
  cookie

 
  1. var session = require('express-session');  
  2. ...  
  3. app.use(cookieParser());  
  4. app.use(session()); 

固然,在進行這些操做以前,cookie-parser 模塊和express-session 模塊須要經過NPM 安裝到項目的node_modules 文件夾中。

若是是在經典的Express.js 3.x 版本中,則須要在配置文件中加入下面兩個中間件。

1. express.cookieParser():解析發送的和接收的cookie。

2. express.session():在每一個請求體中暴露res.session 對象,而且在內存或持久化存儲中(如MongoDB、Redis 等)儲存session 數據。

在後文的例子中,若是沒有特別說起Express.js 的版本,就表示代碼能兼容3.x 和4.x
版本。

囉唆一句,咱們能夠在req.session 中儲存任何數據,它們會自動出如今來自同一個客戶端的全部後續請求中(在客戶端支持cookie 的前提下)。在這個例子中,認證信息用session 儲存的一個標記(布爾值),咱們在受權函數中去檢查這個標記,爲真放行,爲假則退出。像這樣敲擊代碼:

 
  1. app.post('/login', function(req, res, next) {  
  2. // 檢查憑證  
  3. // 在請求的有效負載中進行傳遞  
  4. if (checkForCredentials(req)) {  
  5. req.session.auth = true;  
  6. res.redirect('/dashboard'); // 非公開內容  
  7. } else {  
  8. res.send(401); // 認證不經過  
  9. }  
  10. }); 

警告 避免在cookie 中儲存任何敏感信息。由於cookie 十分不安全,並且儲存長度存在限制(不一樣的瀏覽器限制不一樣,IE 最小)。因此推薦的方法是:不去手動操做cookie,cookie 中只保留session ID 字段,這個字段由Express.js 中間件自動控制。

Express.js 默認使用內存來儲存session 數據,這就表示每次應用崩潰或手動重啓時session 數據都會丟失。咱們可使用Redis 或者MongoDB 儲存session 數據,這樣既能夠保證session 數據可以持久化存儲也能夠實現session 數據可跨服務器讀取

爲你的博客增長郵箱和密碼登陸功能

你的博客中實現基於session 的用戶認證,咱們須要完成如下步驟:

1. 在app.js 的配置部分中增長引入和使用session 中間件的代碼。

2. 實現一個基於session 的用戶認證中間件,以便咱們在多個路由規則之間複用這些代碼。

3. 在app.js 文件中添加上一步驟中的中間件,以控制非公開頁面的訪問。像這樣:

app.get('/api/', authorize, api.index)

4. 在user.js 中實現包含認證過程的登陸路由POST /login 和登出路由GET/logout。  

相關文章
相關標籤/搜索