文章來源于各種:Java旅途 作者:周明堯
在平時工作中,總會接觸到多種接口。前后端數(shù)據(jù)傳輸接口,第三方業(yè)務平臺接口。一個平臺的前后端數(shù)據(jù)傳輸接口一般都會在內(nèi)網(wǎng)環(huán)境下通信,而且會使用安全框架,所以安全性可以得到很好的保護。這篇文章重點討論一下提供給第三方平臺的業(yè)務接口應當如何設(shè)計?我們應該考慮哪些問題?
主要從以上三個方面來設(shè)計一個安全的API接口。
一 安全性問題
安全性問題是一個接口必須要保證的規(guī)范。如果接口保證不了安全性,那么你的接口相當于直接暴露在公網(wǎng)環(huán)境中任人蹂躪。
1.1 調(diào)用接口的先決條件-token
獲取 token 一般會涉及到幾個參數(shù)appid
,appkey
,timestamp
,nonce
,sign
。我們通過以上幾個參數(shù)來獲取調(diào)用系統(tǒng)的憑證。
appid
和appkey
可以直接通過平臺線上申請,也可以線下直接頒發(fā)。appid
是全局唯一的,每個appid
將對應一個客戶,appkey
需要高度保密。
timestamp
是時間戳,使用系統(tǒng)當前的 unix 時間戳。時間戳的目的就是為了減輕 DOS 攻擊。防止請求被攔截后一直嘗試請求接口。服務器端設(shè)置時間戳閥值,如果請求時間戳和服務器時間超過閥值,則響應失敗。
nonce
是隨機值。隨機值主要是為了增加sign
的多變性,也可以保護接口的冪等性,相鄰的兩次請求nonce
不允許重復,如果重復則認為是重復提交,響應失敗。
sign
是參數(shù)簽名,將appkey
,timestamp
,nonce
拼接起來進行md5加密(當然使用其他方式進行不可逆加密也沒問題)。
token
,使用參數(shù)appid
,timestamp
,nonce
,sign
來獲取token,作為系統(tǒng)調(diào)用的唯一憑證。token
可以設(shè)置一次有效(這樣安全性更高),也可以設(shè)置時效性,這里推薦設(shè)置時效性。如果一次有效的話這個接口的請求頻率可能會很高。token
推薦加到請求頭上,這樣可以跟業(yè)務參數(shù)完全區(qū)分開來。
1.2 使用POST作為接口請求方式
一般調(diào)用接口最常用的兩種方式就是 GET 和 POST 。兩者的區(qū)別也很明顯,GET 請求會將參數(shù)暴露在瀏覽器 URL 中,而且對長度也有限制。為了更高的安全性,所有接口都采用 POST 方式請求。
1.3 客戶端IP白名單
ip 白名單是指將接口的訪問權(quán)限對部分 ip 進行開放。這樣就能避免其他 ip 進行訪問攻擊,設(shè)置 ip 白名單比較麻煩的一點就是當你的客戶端進行遷移后,就需要重新聯(lián)系服務提供者添加新的 ip 白名單。設(shè)置 ip 白名單的方式很多,除了傳統(tǒng)的防火墻之外,spring cloud alibaba 提供的組件 sentinel 也支持白名單設(shè)置。為了降低 api 的復雜度,推薦使用防火墻規(guī)則進行白名單設(shè)置。
1.4 單個接口針對ip限流
限流是為了更好的維護系統(tǒng)穩(wěn)定性。使用 redis 進行接口調(diào)用次數(shù)統(tǒng)計,ip+接口地址作為 key,訪問次數(shù)作為 value ,每次請求 value+1,設(shè)置過期時長來限制接口的調(diào)用頻率。
1.5 記錄接口請求日志
使用 aop 全局記錄請求日志,快速定位異常請求位置,排查問題原因。
1.6 敏感數(shù)據(jù)脫敏
在接口調(diào)用過程中,可能會涉及到訂單號等敏感數(shù)據(jù),這類數(shù)據(jù)通常需要脫敏處理,最常用的方式就是加密。加密方式使用安全性比較高的RSA
非對稱加密。非對稱加密算法有兩個密鑰,這兩個密鑰完全不同但又完全匹配。只有使用匹配的一對公鑰和私鑰,才能完成對明文的加密和解密過程。
二 冪等性問題
冪等性是指任意多次請求的執(zhí)行結(jié)果和一次請求的執(zhí)行結(jié)果所產(chǎn)生的影響相同。說的直白一點就是查詢操作無論查詢多少次都不會影響數(shù)據(jù)本身,因此查詢操作本身就是冪等的。但是新增操作,每執(zhí)行一次數(shù)據(jù)庫就會發(fā)生變化,所以它是非冪等的。
冪等問題的解決有很多思路,這里講一種比較嚴謹?shù)?。提供一個生成隨機數(shù)的接口,隨機數(shù)全局唯一。調(diào)用接口的時候帶入隨機數(shù)。第一次調(diào)用,業(yè)務處理成功后,將隨機數(shù)作為key,操作結(jié)果作為 value,存入 redis,同時設(shè)置過期時長。第二次調(diào)用,查詢 redis,如果 key 存在,則證明是重復提交,直接返回錯誤。
三 數(shù)據(jù)規(guī)范問題
3.1 版本控制
一套成熟的 API 文檔,一旦發(fā)布是不允許隨意修改接口的。這時候如果想新增或者修改接口,就需要加入版本控制,版本號可以是整數(shù)類型,也可以是浮點數(shù)類型。一般接口地址都會帶上版本號,http://ip:port//v1/list
。
3.2 響應狀態(tài)碼規(guī)范
一個牛逼的 API,還需要提供簡單明了的響應值,根據(jù)狀態(tài)碼就可以大概知道問題所在。我們采用 http 的狀態(tài)碼進行數(shù)據(jù)封裝,例如200表示請求成功,4xx表示客戶端錯誤,5xx表示服務器內(nèi)部發(fā)生錯誤。狀態(tài)碼設(shè)計參考如下:
分類 | 描述 |
---|---|
1xx | 信息,服務器收到請求,需要請求者繼續(xù)執(zhí)行操作 |
2xx | 成功 |
3xx | 重定向,需要進一步的操作以完成請求 |
4xx | 客戶端錯誤,請求包含語法錯誤或無法完成請求 |
5xx | 服務端錯誤 |
狀態(tài)碼枚舉類:
public enum CodeEnum {
// 根據(jù)業(yè)務需求進行添加
SUCCESS(200,"處理成功"),
ERROR_PATH(404,"請求地址錯誤"),
ERROR_SERVER(505,"服務器內(nèi)部發(fā)生錯誤");
private int code;
private String message;
CodeEnum(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
3.3 統(tǒng)一響應數(shù)據(jù)格式
為了方便給客戶端響應,響應數(shù)據(jù)會包含三個屬性,狀態(tài)碼(code),信息描述(message),響應數(shù)據(jù)(data)??蛻舳烁鶕?jù)狀態(tài)碼及信息描述可快速知道接口,如果狀態(tài)碼返回成功,再開始處理數(shù)據(jù)。
響應結(jié)果定義及常用方法:
public class R implements Serializable {
private static final long serialVersionUID = 793034041048451317L;
private int code;
private String message;
private Object data = null;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
/**
* 放入響應枚舉
*/
public R fillCode(CodeEnum codeEnum){
this.setCode(codeEnum.getCode());
this.setMessage(codeEnum.getMessage());
return this;
}
/**
* 放入響應碼及信息
*/
public R fillCode(int code, String message){
this.setCode(code);
this.setMessage(message);
return this;
}
/**
* 處理成功,放入自定義業(yè)務數(shù)據(jù)集合
*/
public R fillData(Object data) {
this.setCode(CodeEnum.SUCCESS.getCode());
this.setMessage(CodeEnum.SUCCESS.getMessage());
this.data = data;
return this;
}
}
總結(jié)
本篇文章從安全性、冪等性、數(shù)據(jù)規(guī)范等方面討論了 API 設(shè)計規(guī)范。除此之外,一個好的 API 還少不了一個優(yōu)秀的接口文檔。接口文檔的可讀性非常重要,雖然很多程序員都不喜歡寫文檔,而且不喜歡別人不寫文檔。為了不增加程序員的壓力,推薦使用 swagger 或其他接口管理工具,通過簡單配置,就可以在開發(fā)中測試接口的連通性,上線后也可以生成離線文檔用于管理API。
以上就是W3Cschool編程獅
關(guān)于如何設(shè)計一個看起來很牛逼的API接口的相關(guān)介紹了,希望對大家有所幫助。