使用Node在服務端呼叫HTTP-Basic認證的API

RAY發表於2018-02-02

前言

Node作為前後端分離的”利器“由於它使用JS語法的特殊性,可以使得前端更好的利用Node來作為中間層十分方便得分發請求或者呼叫後臺提供的“黑盒”API。即便是使用Node為主作為服務端開發在專案中也會經常用到要去其他的系統呼叫服務的場景。

請求的認證一直是一個web系統很重要的一環,直接關係到了系統的安全。對於Node在服務端方面,稍微複雜的認證機制使用的最多的就是passport模組,通過它強大而又靈活的Strategy機制,官方同時也提供了很多策略滿足很多常見的場景。當然今天的主題是最簡單的基礎認證 HTTP Basic Authentication,提供了對http最為基礎的認證策略,即使用者名稱和密碼。對於服務端呼叫API的場景加上這個基本認證也會比在前端直接使用這種比較“空”的認證方式更加合適。

本文將介紹使用Node在服務端呼叫API時面對最基本的HTTP認證 -- HTTP Basic Authentication認證的處理方式。即不同的服務端http client諸如Axios, Request, Restler的使用。

HTTP Basic Authentication

首先對HTTP Basic Authentication這個最簡單的http認證形式進行簡單介紹

http-basic.jpg

上圖所示,在客戶端進行資源請求的時候由於該介面API設定了http基本認證對資源的訪問進行了限制,則客戶端必須提供使用者名稱和密碼並且服務端驗證通過時才會得到資源。

實現

下面將使用使用express搭建一個簡單的需要基本認證的介面,需要說明的是在express3中express還整合了很豐富的中介軟體系統,比如你可以直接通過app.use(express.basicAuth('username', 'password'));來設定一個基本認證。在express4開始由於分離了中介軟體系統,你需要多出一步手動安裝basic-auth中介軟體的過程。

//app.js
const express = require('express')
const basicAuth = require('basic-auth')
const bodyParser = require('body-parser')
const app = express();
app.use(bodyParser.json())
app.use(bodyParser.urlencoded({
    extended:true
   }))
app.all('/api', function (req, res) {
    const credentials = basicAuth(req)
    if (!credentials || credentials.name !== 'ray' || credentials.pass !== '123') {
        res.statusCode = 401
        res.setHeader('WWW-Authenticate', 'Basic realm="example"')
        res.end('go away')
    } else {
        console.log(req.body)
        if(req.body.need && req.body.need === 'money'){
            res.json({
                key: 'show me the money'
            });
        }else{
            res.json({
                key: 'show me the gold'
            })  
        }            
    }
});

app.listen(3000, function () {
    console.log('Example app listening on port 3000!');
});
複製程式碼

先簡單的搭建起一個提供api的伺服器,當你執行node app.js之後訪問localhost:3000/api的時候就會看到瀏覽器彈出讓你輸入使用者名稱和密碼的對話方塊,你如果點選了取消,即不提供使用者名稱和密碼,或者錯誤密碼,就會驗證失敗,你將看到‘go away’。當你提供了正確的密碼則將得到'show me the gold'。

值得一提的是,express的搭建中,我使用了body-parser這個中介軟體,原因是接下來我們使用node在服務端請求api的時候會使用POST方法傳遞引數,即我想得到的是'show me the money'這句話。而**http的post請求預設的資料格式是www-form-urlencoded**解析的時候需要bodyParser.urlencoded支援。

在服務端呼叫API

其實在Node端可以用的http client模組有很多,比如可以使用pipe進行流式操作的request,以及我現在在做的專案中使用的restler,當然還有現在很火爆的前後端都可以使用,並且基於現代非同步基礎--Promiseaxios,接下來就介紹對於這三個模組在服務端去請求一個設了HTTP Basic Authentication認證的API介面,就是從我們上面用express搭起來的簡單的伺服器得到'show me the money'這句話。

request模組

npm install --save request安裝request模組到我們專案目錄,然後新建req.js檔案。

//req.js
const request = require('request')

request.post('http://localhost:3000/api', {
    'auth': {
        'user': 'ray',
        'pass': '123',
        'sendImmediately': false
    },
    'form': {
        need: 'money'
    }
}, function (err, httpResponse, data) {
    if (err) {
        console.log(err);
    } else {
        console.log(`data:${data}`)
    }
})
複製程式碼

request模組本身體積確實有點大,上面使用它的post方法,通過在第二個引數物件中寫上auth屬性提供對http基礎認證所需要的使用者名稱和密碼,第二個屬性form就是放在請求的body中的型別為application/x-www-form-urlencoded引數,將會被我們的express伺服器通過req.body解析到,當然,需要bodyParser.urlencoded()提供支援。

接下來,先node app.js開啟我們的伺服器,之後你再去node req.js執行這個檔案你就會看到data:{"key":"you get the money"}

axios模組

npm install --save axios,新建axi.js

//axi.js
const axios = require('axios')

axios({
        url: 'http://localhost:3000/api',
        method: 'post',
        auth: {
            username: 'ray',
            password: '123'
        },
        data: {
            need: 'money'
        }
    })
    .then((response) => {
        console.log(response.data)
    })
    .catch(function (error) {
        console.log(error);
      });
複製程式碼

axios最大的特點就是可以十分愉快的使用Promise,並且它的體積足夠的小,它對基礎認證的資訊同樣也是在配置中的auth屬性,而他所需要隨請求放在body中的引數是放在data欄位中,而且需要注意的是他返回的資料是在返回結果的data欄位中,同樣,此時你node axi.js也能得到{ key: 'you get the money' }.

restler模組

npm install --save restler,新建rest.js

const rest = require('restler')

rest.post('http://localhost:3000/api',{
    username:'ray',
    password:'123',
    data: {
        need:'money'
    }
}).on('complete',function(data){
    console.log(data)
})
複製程式碼

最後是restler模組,需要的認證資訊直接是其第二個引數options中的兩個欄位usernamepassword,攜帶在body中的資訊依舊是放在data欄位中,用監聽事件的方式監聽complete事件發生觸發回撥函式你就得到了通過驗證的訊息{ key: 'you get the money' }

當然上述三個模組以及瀏覽器傳送請求不帶認證資訊都將得到帶著401的"go away",三個模組不在請求的body中帶上引數need都會”show you the gold”。

後續

最後,如果有錯誤與不足還希望您能指出:)

個人部落格地址

相關文章