安全的關(guān)鍵.png)
node.js + express + docker + mysql + jwt 實(shí)現(xiàn)用戶管理restful api
注意,這里只是對(duì)REST API 的簡(jiǎn)單介紹,起到拋磚引玉作用,更加深入內(nèi)容不在本次學(xué)習(xí)范圍內(nèi),感興趣的小伙伴可以查看相關(guān)資料深入學(xué)習(xí)。此外本號(hào)接受該領(lǐng)域的投稿,歡迎聯(lián)系云朵君!
API,全名Application Programming Interface (應(yīng)用程式介面),簡(jiǎn)單來(lái)說(shuō),是品牌開(kāi)發(fā)出的一種接口,讓第三方可以額外開(kāi)發(fā)、應(yīng)用在自身的產(chǎn)品上的系統(tǒng)溝通介面。
REST 是一種通過(guò) HTTP 協(xié)議設(shè)計(jì) API 的架構(gòu)風(fēng)格。它的主要優(yōu)點(diǎn)是其極大的靈活性。只要需要直接從服務(wù)器向 Web 應(yīng)用程序或站點(diǎn)的用戶提供數(shù)據(jù),開(kāi)發(fā)人員就會(huì)使用 REST API。
REST API 的主要組件:
REST API 通過(guò) HTTP 請(qǐng)求進(jìn)行通信,完成以下功能——?jiǎng)?chuàng)建、讀取、更新和刪除數(shù)據(jù)。它們也稱為 CRUD 操作。REST 提供有關(guān)請(qǐng)求資源的信息,并使用四種方法來(lái)描述如何處理資源:
REST,全名Representational State Transfer( 表現(xiàn)層狀態(tài)轉(zhuǎn)移),他是一種設(shè)計(jì)風(fēng)格,RESTful 只是轉(zhuǎn)為形容詞,像是 peace 和平這名詞,轉(zhuǎn)成形容詞是peaceful,RESTful 則形容以此規(guī)范設(shè)計(jì)的API,稱為RESTful API。
RESTful API 主要由三種元件組成:
所以使用 RESTful 風(fēng)格設(shè)計(jì)的API,就有了以下幾種優(yōu)點(diǎn)及限制:
Restful API 它允許集成應(yīng)用程序 app ?或與 Restful Web 服務(wù)交互。它現(xiàn)在正在成長(zhǎng)為連接微服務(wù)架構(gòu)中組件的最常用方法。我們借助 API,能夠獲取或發(fā)送數(shù)據(jù)到網(wǎng)站并執(zhí)行一些操作,目的是通過(guò) Web 服務(wù)完成我們的任務(wù)。每個(gè)網(wǎng)站都使用不同類型的 API,例如股票市場(chǎng)交易網(wǎng)站,借助 API 獲取當(dāng)前價(jià)格和上下波動(dòng)。
同樣,我們創(chuàng)建 Hello world API,它表示如果你對(duì)其發(fā)出 get 請(qǐng)求,?將獲得 JSON 響應(yīng),一般情況下, API 給出 JSON 類型的響應(yīng)。接下來(lái),使用 pip 包管理器安裝 Flask:
pip install flask
pip install flask-restful
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
class Helloworld(Resource):
def __init__(self):
pass
def get(self):
return {
"Hello": "World"
}
api.add_resource(Helloworld, '/')
if __name__ == '__main__':
app.run(debug=True)
ok,到現(xiàn)在已經(jīng)創(chuàng)建了第一個(gè)Rest api,看起來(lái)挺簡(jiǎn)單的,那么,什么是Flask-Restful呢?
Flask restful 定義了資源Resource類,其中包含每個(gè) HTTP 方法的方法。方法名稱應(yīng)與其對(duì)應(yīng)的 HTTP 方法相同,并以小寫(xiě)形式書(shū)寫(xiě),如上代碼中所示。我們發(fā)現(xiàn)這些方法沒(méi)有路由裝飾器,這是它們是基于資源路由的。無(wú)論定義什么類,我們都可以使用添加資源add_resource方法定義到它的路由以及在對(duì)應(yīng)路由上調(diào)用該類?。
說(shuō)明: 在上面的代碼中,我們首先加載需要的父類,然后初始化我們的app和API。之后,我們創(chuàng)建了一個(gè)程序,并且我們正在發(fā)出一個(gè) GET 請(qǐng)求,說(shuō)明如果有人點(diǎn)擊了這個(gè)程序,那么他將得到 Hello world 作為 JSON 格式的響應(yīng)。要打開(kāi)特定 URL,我們使用 add resource 方法并將其路由到默認(rèn)斜杠。要運(yùn)行此文件,可以使用 POSTMAN 工具(一種 API 維護(hù)工具)來(lái)創(chuàng)建、測(cè)試和管理 API。還可以使用requests請(qǐng)求模塊使用以下代碼測(cè)試此 API。首先,運(yùn)行上面的文件,它會(huì)給你 localhost URL,然后在另一個(gè)命令提示符下,運(yùn)行下面的代碼文件:
import requests
url = "http://127.0.0.1:5000/"
response = requests.get(url=url)
print(response.text)
{
"Hello": "World"
}
通過(guò)以上內(nèi)容的學(xué)習(xí),相比大家已經(jīng)對(duì) REST API 有個(gè)初步印象。接下來(lái)我們將繼續(xù)探索使用 REST API 的不同 HTTP 方法,其中我們定義一個(gè)列表,該列表將以字典(JSON 對(duì)象)的形式存儲(chǔ)從服務(wù)器獲取的所有數(shù)據(jù)。這是很重要的,因?yàn)槲覀冊(cè)陧?xiàng)目中有不同的api來(lái)獲取數(shù)據(jù),而不是其他地方的數(shù)據(jù)。
首先創(chuàng)建一個(gè) API,在其中創(chuàng)建 3 個(gè)名為 GET、POST 和 DELETE 的 HTTP 方法,并且在其中創(chuàng)建一個(gè)自定義 URL,當(dāng)請(qǐng)求 POST 方法時(shí),它將以 Name 作為輸入;在請(qǐng)求 GET 方法時(shí),將名稱返回;在DELETE時(shí),如果該名稱存在,我們將刪除該名稱,再次訪問(wèn)它會(huì)給我們 NULL。
創(chuàng)建一個(gè)文件并編寫(xiě)以下代碼:
from flask import Flask
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
data = []
class People(Resource):
def get(self):
for x in data:
if x['Data'] == name:
return x
return {'Data': None}
def post(self, name):
temp = {'Data': name}
data.append(temp)
return temp
def delete(self):
for ind, x in enumerate(data):
if x['Data'] == name:
temp = data.pop(ind)
return {'Note': 'Deleted'}
api.add_resource(People, '/Name/')
if __name__ == '__main__':
app.run(debug=True)
打開(kāi) POSTMAN API 工具并點(diǎn)擊每個(gè) HTTP 方法請(qǐng)求。首先,當(dāng)我們使用 post 請(qǐng)求Name時(shí),它給了我們一個(gè)name
。在獲取請(qǐng)求時(shí),我們將返回name
。它在刪除時(shí)被刪除,當(dāng)再次將其取回時(shí),它會(huì)給你返回 NULL。
結(jié)果如下
我們使用帶有 API 的裝飾器來(lái)監(jiān)控 IP 地址、cookie 等。我們將繼續(xù)學(xué)習(xí)如何使用帶有裝飾器的Flask API。裝飾器是一個(gè)將另一個(gè)函數(shù)作為參數(shù)并返回另一個(gè)函數(shù)的函數(shù)。也可以將其理解為在不改變或修改當(dāng)前功能的情況下,為現(xiàn)有功能提供一些附加功能的功能。
這里我們創(chuàng)建一個(gè)新文件,我將通過(guò)創(chuàng)建兩個(gè)裝飾器來(lái)展示。在第一個(gè)文件中,編寫(xiě)返回代碼執(zhí)行時(shí)間的外部時(shí)間函數(shù)。我們從 functools
模塊(用于高階 python 函數(shù)的標(biāo)準(zhǔn)模塊)導(dǎo)入應(yīng)用于 wrapper 函數(shù)的 wrap 裝飾器 。它通過(guò)復(fù)制所有參數(shù)來(lái)更新包裝函數(shù)。
from flask import Flask
from flask_restful import Resource, Api
import datetime
from flask import request
from functools import wraps
app = Flask(__name__)
api = Api(app)
def time(function=None):
@wraps(function)
def wrapper(*args, **kwargs):
s = datetime.datetime.now()
_ = function(*args, **kwargs)
e = datetime.datetime.now()
print("Execution Time : {} ".format(e-s))
return _
return wrapper
class HelloWorld(Resource):
@monitor
def get(self):
return {"hello": "world"}
api.add_resource(HelloWorld, "/")
if __name__ == "__main__":
app.run(debug=True)
我們創(chuàng)建第二個(gè)裝飾器來(lái)監(jiān)視cookie和IP地址,因此創(chuàng)建下面的函數(shù)。不是向hello world函數(shù)添加時(shí)間裝飾器,而是添加監(jiān)視器裝飾器并運(yùn)行代碼。
def monitor(function=None):
@wraps(function)
def wrapper(*args, **kwargs):
_ = function(*args, **kwargs)
print("Ip Address : {} ".format(request.remote_user))
print("Cookies : {} ".format(request.cookies))
print(request.user_agent)
return _
return wrapper
當(dāng)我們?cè)O(shè)計(jì)API時(shí),我們也應(yīng)該注意安全性,因?yàn)楹芏嗳藭?huì)訪問(wèn)它。因?yàn)锳PI可能包含一些雙方之間的機(jī)密數(shù)據(jù),因此我們可以指定只有授權(quán)的人可以訪問(wèn)API,那該怎么辦?此時(shí)可以使用Flask基本身份驗(yàn)證。當(dāng)然,此時(shí)需要使用pip命令安裝這個(gè)flask模塊。
pip install flask-httpauth
我們正在構(gòu)建一個(gè)API并定義User數(shù)據(jù)字典,其中包含用戶名和密碼。當(dāng)在實(shí)時(shí)用例中工作時(shí),可以通過(guò)配置文件或從數(shù)據(jù)庫(kù)中接受用戶名和密碼。首先,我們創(chuàng)建一個(gè)主要函數(shù)來(lái)匹配用戶名和密碼,并創(chuàng)建一個(gè)GET方法,該方法表示任何點(diǎn)擊此API的人,如果沒(méi)有登錄,我們就無(wú)法訪問(wèn)數(shù)據(jù)。
from flask import Flask
from flask_restful import Resource, Api
from flask_httpauth import HTTPBasicAuth
app = Flask(__name__)
api = Api(app, prefix="/api/v1")
auth = HTTPBasicAuth()
USER_DATA = {
"admin": "SuperSecretPwd"
}
#route to verify the password
@auth.verify_password
def verify(username, password):
if not(username and password):
return False
return USER_DATA.get(username) == password
class PrivateResource(Resource):
@auth.login_required
def get(self):
return {"How's the Josh": "High"}
api.add_resource(PrivateResource, '/private')
if __name__ == '__main__':
app.run(debug=True)
當(dāng)我們使用POSTMAN運(yùn)行上述文件時(shí),我們會(huì)嘗試在沒(méi)有登錄的情況下獲取數(shù)據(jù),以便給你演示未經(jīng)授權(quán)的訪問(wèn)權(quán)限。
現(xiàn)在轉(zhuǎn)到授權(quán),并單擊Basic authorization。輸入用戶名和密碼,然后點(diǎn)擊GET請(qǐng)求以獲得所需的結(jié)果。
這是保護(hù) Flask API 的方法,也是最基本的方法,當(dāng)然還有更多更高級(jí)的方法,這里不做過(guò)多的介紹。
至此我們已經(jīng)了解了如何保護(hù)我們的 API,在未經(jīng)授權(quán)的登錄禁止訪問(wèn),但是如果我們還想知道訪問(wèn)者的位置(緯度和經(jīng)度點(diǎn))、IP 地址、服務(wù)器名稱(例如訪問(wèn)API 的人的詳細(xì)信息),我們還可以繼續(xù)配置,使用 REST API 的基本flask跟蹤應(yīng)用程序。首先,使用 PIP 命令安裝flask跟蹤包。
pip install flask-track-usage
接下來(lái)看下該程序:
from flask import Flask, g
app = Flask(__name__)
app.config['TRACK_USAGE_USE_FREEGEOIP'] = False
app.config['TRACK_USAGE_INCLUDE_OR_EXCLUDE_VIEWS'] = 'include'
from flask_track_usage import TrackUsage
from flask_track_usage.storage.printer import PrintWriter
from flask_track_usage.storage.output import OutputWriter
t = TrackUsage(app, [
PrintWriter(),
OutputWriter(transform=lambda s: "OUTPUT: " + str(s))
])
@t.include
@app.route('/')
def index():
g.track_var["optional"] = "Write_Something"
return "Hello"
#Run the application
if __name__ == "__main__":
app.run(debug=True)
該程序通過(guò)導(dǎo)入 Track Usage、Input writer 和 output writer
來(lái)創(chuàng)建一個(gè)跟蹤應(yīng)用程序。將flask app傳遞給 Track 包并使用輸出編寫(xiě)器,并使用 lambda 函數(shù)以字符串格式寫(xiě)入輸出。之后在 slash 上創(chuàng)建一個(gè)基本路由,并將跟蹤應(yīng)用程序作為裝飾器包含在內(nèi)。g
代表全局,表示數(shù)據(jù)在上下文中是全局的。因此,創(chuàng)建一個(gè)基本 API,它在瀏覽器返回"Hello"
,同時(shí)在后端獲得所有人員的信息。
現(xiàn)在已經(jīng)為案例創(chuàng)建了一個(gè)不錯(cuò)的REST API。盡管如此,我們還需要為REST API編寫(xiě)單元測(cè)試代碼,因?yàn)閺腁PI中識(shí)別常見(jiàn)錯(cuò)誤,并確保生產(chǎn)安全是至關(guān)重要的。
如下是創(chuàng)建一個(gè)名為run的新文件并開(kāi)發(fā)以下簡(jiǎn)單API。
from flask import Flask
from flask_restful import Resource, Api
import json
app = Flask(__name__)
api = Api(app)
class Helloworld(Resource):
def __init__(self):
pass
def get(self):
return json.dumps({"Message": "Fine"})
api.add_resource(Helloworld, '/')
if __name__ == '__main__':
app.run(debug=True)
現(xiàn)在創(chuàng)建另一個(gè)名為test的文件,在其中編寫(xiě)用于對(duì)API進(jìn)行單元測(cè)試的代碼。最常見(jiàn)的情況是執(zhí)行以下三個(gè)基本單元測(cè)試。
from run import app
import unittest
class FlaskTest(unittest.TestCase):
#Check for response 200
def test_inde(self):
tester = app.test_client(self) #tester object
response = tester.get("/")
statuscode = response.status_code
self.assertEqual(statuscode, 200)
#check if the content return is application JSON
def test_index_content(self):
tester = app.test_client(self)
response = tester.get("/")
self.assertEqual(response.content_type, "application/json")
#check the Data returned
def test_index_data(self):
tester = app.test_client(self)
response = tester.get("/")
self.assertTrue(b'Message' in response.data)
if __name__ == '__main__':
unittest.main()
如果你已經(jīng)學(xué)習(xí)過(guò)網(wǎng)絡(luò)爬蟲(chóng),你應(yīng)該知道 200
響應(yīng)意味著對(duì)特定 URL 的請(qǐng)求已成功發(fā)出,并返回響應(yīng)。
好了,這就是本文的全部?jī)?nèi)容。到這里我們已經(jīng)學(xué)會(huì)了從頭開(kāi)始創(chuàng)建 Flask REST API ,并輕松安全地對(duì)其進(jìn)行維護(hù)。
文章轉(zhuǎn)自微信公眾號(hào)@數(shù)據(jù)STUDIO
node.js + express + docker + mysql + jwt 實(shí)現(xiàn)用戶管理restful api
nodejs + mongodb 編寫(xiě) restful 風(fēng)格博客 api
表格插件wpDataTables-將 WordPress 表與 Google Sheets API 連接
使用 Django 和 Django REST 框架構(gòu)建 RESTful API:實(shí)現(xiàn) CRUD 操作
ASP.NET Web API快速入門(mén)介紹
2024年在線市場(chǎng)平臺(tái)的11大最佳支付解決方案
完整指南:如何在應(yīng)用程序中集成和使用ChatGPT API
選擇AI API的指南:ChatGPT、Gemini或Claude,哪一個(gè)最適合你?
用ASP.NET Core 2.1 建立規(guī)范的 REST API — 緩存和并發(fā)
對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力
一鍵對(duì)比試用API 限時(shí)免費(fèi)