精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

SpringBoot 后端接口規范(下)

jf_78858299 ? 來源:架構師 ? 作者:架構師 ? 2023-05-05 17:02 ? 次閱讀

七、接口版本控制

1、簡介

SpringBoot項目中,如果要進行restful接口的版本控制一般有以下幾個方向:

  • 基于path的版本控制
  • 基于header的版本控制

在spring MVC下,url映射到哪個method是由RequestMappingHandlerMapping來控制的,那么我們也是通過RequestMappingHandlerMapping來做版本控制的。

2、Path控制實現

首先定義一個注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ApiVersion {
    // 默認接口版本號1.0開始,這里我只做了兩級,多級可在正則進行控制
    String value() default "1.0";
}

ApiVersionCondition用來控制當前request 指向哪個method

public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {
    private static final Pattern VERSION_PREFIX_PATTERN = Pattern.compile("v(\\\\d+\\\\.\\\\d+)");

    private final String version;

    public ApiVersionCondition(String version) {
        this.version = version;
    }

    @Override
    public ApiVersionCondition combine(ApiVersionCondition other) {
        // 采用最后定義優先原則,則方法上的定義覆蓋類上面的定義
        return new ApiVersionCondition(other.getApiVersion());
    }

    @Override
    public ApiVersionCondition getMatchingCondition(HttpServletRequest httpServletRequest) {
        Matcher m = VERSION_PREFIX_PATTERN.matcher(httpServletRequest.getRequestURI());
        if (m.find()) {
            String pathVersion = m.group(1);
            // 這個方法是精確匹配
            if (Objects.equals(pathVersion, version)) {
                return this;
            }
            // 該方法是只要大于等于最低接口version即匹配成功,需要和compareTo()配合
            // 舉例:定義有1.0/1.1接口,訪問1.2,則實際訪問的是1.1,如果從小開始那么排序反轉即可
//            if(Float.parseFloat(pathVersion)>=Float.parseFloat(version)){
//                return this;
//            }

        }
        return null;
    }

    @Override
    public int compareTo(ApiVersionCondition other, HttpServletRequest request) {
        return 0;
        // 優先匹配最新的版本號,和getMatchingCondition注釋掉的代碼同步使用
//        return other.getApiVersion().compareTo(this.version);
    }

    public String getApiVersion() {
        return version;
    }

}

PathVersionHandlerMapping用于注入spring用來管理

public class PathVersionHandlerMapping extends RequestMappingHandlerMapping {

    @Override
    protected boolean isHandler(Class? beanType) {
        return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class);
    }

    @Override
    protected RequestCondition? getCustomTypeCondition(Class? handlerType) {
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(handlerType,ApiVersion.class);
        return createCondition(apiVersion);
    }

    @Override
    protected RequestCondition? getCustomMethodCondition(Method method) {
        ApiVersion apiVersion = AnnotationUtils.findAnnotation(method,ApiVersion.class);
        return createCondition(apiVersion);
    }

    private RequestCondition

WebMvcConfiguration配置類讓spring來接管

@Configuration
public class WebMvcConfiguration implements WebMvcRegistrations {

    @Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new PathVersionHandlerMapping();
    }
}

最后controller進行測試,默認是v1.0,如果方法上有注解,以方法上的為準(該方法vx.x在路徑任意位置出現都可解析)

@RestController
@ApiVersion
@RequestMapping(value = "/{version}/test")
public class TestController {

    @GetMapping(value = "one")
    public String query(){
        return "test api default";
    }

    @GetMapping(value = "one")
    @ApiVersion("1.1")
    public String query2(){
        return "test api v1.1";
    }


    @GetMapping(value = "one")
    @ApiVersion("3.1")
    public String query3(){
        return "test api v3.1";
    }
}

3、header控制實現

總體原理與Path類似,修改ApiVersionCondition即可,之后訪問時在header帶上X-VERSION參數即可

public class ApiVersionCondition implements RequestCondition<ApiVersionCondition> {
    private static final String X_VERSION = "X-VERSION";
    private final String version ;
    
    public ApiVersionCondition(String version) {
        this.version = version;
    }

    @Override
    public ApiVersionCondition combine(ApiVersionCondition other) {
        // 采用最后定義優先原則,則方法上的定義覆蓋類上面的定義
        return new ApiVersionCondition(other.getApiVersion());
    }

    @Override
    public ApiVersionCondition getMatchingCondition(HttpServletRequest httpServletRequest) {
        String headerVersion = httpServletRequest.getHeader(X_VERSION);
        if(Objects.equals(version,headerVersion)){
            return this;
        }
        return null;
    }

    @Override
    public int compareTo(ApiVersionCondition apiVersionCondition, HttpServletRequest httpServletRequest) {
        return 0;
    }
    public String getApiVersion() {
        return version;
    }

}

八、API接口安全

1、簡介

APP、前后端分離項目都采用[API]接口形式與服務器進行數據通信,傳輸的數據被偷窺、被抓包、被偽造時有發生,那么如何設計一套比較安全的API接口方案至關重要,一般的解決方案有以下幾點:

  • Token授權認證,防止未授權用戶獲取數據;
  • 時間戳超時機制;
  • URL簽名,防止請求參數被篡改;
  • 防重放,防止接口被第二次請求,防采集;
  • 采用HTTPS通信協議,防止數據明文傳輸;

2、Token授權認證

因為HTTP協議是無狀態的,Token的設計方案是用戶在客戶端使用用戶名和密碼登錄后,服務器會給客戶端返回一個Token,并將Token以鍵值對的形式存放在緩存(一般是Redis)中,后續客戶端對需要授權模塊的所有操作都要帶上這個Token,服務器端接收到請求后進行Token驗證,如果Token存在,說明是授權的請求。

Token生成的設計要求

  • 應用內一定要唯一,否則會出現授權混亂,A用戶看到了B用戶的數據;
  • 每次生成的[Token]一定要不一樣,防止被記錄,授權永久有效;
  • 一般Token對應的是Redis的key,value存放的是這個用戶相關緩存信息,比如:用戶的id;
  • 要設置Token的過期時間,過期后需要客戶端重新登錄,獲取新的Token,如果[Token]有效期設置較短,會反復需要用戶登錄,體驗比較差,我們一般采用Token過期后,客戶端靜默登錄的方式,當客戶端收到[Token]過期后,客戶端用本地保存的用戶名和密碼在后臺靜默登錄來獲取新的[Token],還有一種是單獨出一個刷新Token的接口,但是一定要注意刷新機制和安全問題;

根據上面的設計方案要求,我們很容易得到Token=md5(用戶ID+登錄的時間戳+服務器端秘鑰)這種方式來獲得Token,因為用戶ID是應用內唯一的,登錄的時間戳保證每次登錄的時候都不一樣,服務器端秘鑰是配置在服務器端參與加密的字符串(即:鹽),目的是提高Token加密的破解難度,注意一定不要泄漏

3、時間戳超時機制

客戶端每次請求接口都帶上當前時間的時間戳timestamp,服務端接收到timestamp后跟當前時間進行比對,如果時間差大于一定時間(比如:1分鐘),則認為該請求失效。 時間戳超時機制是防御DOS攻擊的有效手段。 例如http://url/getInfo?id=1&timetamp=1661061696

4、URL簽名

寫過支付寶或微信支付對接的同學肯定對URL簽名不陌生,我們只需要將原本發送給server端的明文參數做一下簽名,然后在server端用相同的算法再做一次簽名,對比兩次簽名就可以確保對應明文的參數有沒有被中間人篡改過。例如http://url/getInfo?id=1&timetamp=1559396263&sign=e10adc3949ba59abbe56e057f20f883e

簽名算法過程

  • 首先對通信的參數按key進行字母排序放入數組中(一般請求的接口地址也要參與排序和簽名,那么需要額外添加url=http://url/getInfo這個參數)
  • 對排序完的數組鍵值對用&進行連接,形成用于加密的參數字符串
  • 在加密的參數字符串前面或者后面加上私鑰,然后用md5進行加密,得到sign,然后隨著請求接口一起傳給服務器。服務器端接收到請求后,用同樣的算法獲得服務器的sign,對比客戶端的sign是否一致,如果一致請求有效

5、防重放

客戶端第一次訪問時,將簽名sign存放到服務器的Redis中,超時時間設定為跟時間戳的超時時間一致,二者時間一致可以保證無論在timestamp限定時間內還是外 URL都只能訪問一次,如果被非法者截獲,使用同一個URL再次訪問,如果發現緩存服務器中已經存在了本次簽名,則拒絕服務。

如果在緩存中的簽名失效的情況下,有人使用同一個URL再次訪問,則會被時間戳超時機制攔截,這就是為什么要求sign的超時時間要設定為跟時間戳的超時時間一致。拒絕重復調用機制確保URL被別人截獲了也無法使用(如抓取數據)

方案流程

  • 客戶端通過用戶名密碼登錄服務器并獲取Token;
  • 客戶端生成時間戳timestamp,并將timestamp作為其中一個參數;
  • 客戶端將所有的參數,包括Token和timestamp按照自己的簽名算法進行排序加密得到簽名sign
  • 將token、timestamp和sign作為請求時必須攜帶的參數加在每個請求的URL后邊,例:http://url/request?token=h40adc3949bafjhbbe56e027f20f583a&timetamp=1559396263&sign=e10adc3949ba59abbe56e057f20f883e
  • 服務端對token、timestamp和sign進行驗證,只有在token有效、timestamp未超時、緩存服務器中不存在sign三種情況同時滿足,本次請求才有效;

6、采用HTTPS通信協議

安全套接字層超文本傳輸協議HTTPS,為了數據傳輸的安全,HTTPS在HTTP的基礎上加入了SSL協議,SSL依靠證書來驗證服務器的身份,并為客戶端和服務器之間的通信加密。

HTTPS也不是絕對安全的,比如中間人劫持攻擊,中間人可以獲取到客戶端與服務器之間所有的通信內容

九、總結

自此整個后端接口基本體系就構建完畢了

  • 通過Validator + 自動拋出異常來完成了方便的參數校驗
  • 通過全局異常處理 + 自定義異常完成了異常操作的規范
  • 通過數據統一響應完成了響應數據的規范
  • 多個方面組裝非常優雅的完成了后端接口的協調,讓開發人員有更多的經歷注重業務邏輯代碼,輕松構建后端接口

這里再說幾點

  • controller做好try-catch工作,及時捕獲異常,可以再次拋出到全局,統一格式返回前端
  • 做好日志系統,關鍵位置一定要有日志
  • 做好全局統一返回類,整個項目規范好定義好
  • controller入參字段可以抽象出一個公共基類,在此基礎上進行繼承擴充
  • controller層做好入參參數校驗
  • 接口安全驗證
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 接口
    +關注

    關注

    33

    文章

    8497

    瀏覽量

    150834
  • URL
    URL
    +關注

    關注

    0

    文章

    139

    瀏覽量

    15311
  • 后端
    +關注

    關注

    0

    文章

    31

    瀏覽量

    2217
  • SpringBoot
    +關注

    關注

    0

    文章

    173

    瀏覽量

    167
收藏 人收藏

    評論

    相關推薦

    請問可變增益放大器AD8369后端接模數轉換器AD9268怎么匹配?

    如題,想請教一可變增益放大器AD8369后端接模數轉換器AD9268怎么匹配?AD9268前接50歐阻抗的手冊里面有(下圖),可AD8369輸出為200歐阻抗,不知道該怎么接?不知道差分阻抗匹配怎么計算?@
    發表于 12-25 11:40

    SpringBoot知識總結

    SpringBoot干貨學習總結
    發表于 08-01 10:40

    怎么學習SpringBoot

    SpringBoot學習之路(X5)- 整合JPA
    發表于 06-10 14:52

    怎樣去使用springboot

    怎樣去使用springboot呢?學習springboot需要懂得哪些?
    發表于 10-25 07:13

    SpringBoot應用啟動運行run方法

    什么時候創建嵌入式的Servlet容器工廠?什么時候獲取嵌入式的Servlet容器并啟動Tomcat;獲取嵌入式的Servlet容器工廠:1)、SpringBoot應用啟動運行run方法2
    發表于 12-20 06:16

    基于DSP控制的電力線通信模擬前端接口設計

    基于DSP控制的電力線通信模擬前端接口設計
    發表于 10-20 15:51 ?5次下載
    基于DSP控制的電力線通信模擬前<b class='flag-5'>端接口</b>設計

    數字接口—單端接口與差動接口的對比

    數字接口—單端接口與差動接口的對比
    發表于 11-07 08:07 ?0次下載
    數字<b class='flag-5'>接口</b>—單<b class='flag-5'>端接口</b>與差動<b class='flag-5'>接口</b>的對比

    什么是 SpringBoot

    本文從為什么要有 `SpringBoot`,以及 `SpringBoot` 到底方便在哪里開始入手,逐步分析了 `SpringBoot` 自動裝配的原理,最后手寫了一個簡單的 `start` 組件,通過實戰來體會了 `
    的頭像 發表于 04-07 11:28 ?1264次閱讀
    什么是 <b class='flag-5'>SpringBoot</b>?

    SpringBoot的核心注解1

    今天跟大家來探討SpringBoot的核心注解@SpringBootApplication以及run方法,理解下springBoot為什么不需要XML,達到零配置
    的頭像 發表于 04-07 14:34 ?673次閱讀
    <b class='flag-5'>SpringBoot</b>的核心注解1

    SpringBoot的核心注解2

    今天跟大家來探討SpringBoot的核心注解@SpringBootApplication以及run方法,理解下springBoot為什么不需要XML,達到零配置
    的頭像 發表于 04-07 14:34 ?1925次閱讀
    <b class='flag-5'>SpringBoot</b>的核心注解2

    SpringBoot 后端接口規范(上)

    一個后端接口大致分為四個部分組成: 接口地址(url)、接口請求方式(get、post等)、請求數據(request)、響應數據(response) 。雖然說后端接口的編寫并沒有統一
    的頭像 發表于 05-05 17:00 ?746次閱讀
    <b class='flag-5'>SpringBoot</b> <b class='flag-5'>后端接口</b><b class='flag-5'>規范</b>(上)

    SpringBoot 后端接口規范(中)

    一個后端接口大致分為四個部分組成: 接口地址(url)、接口請求方式(get、post等)、請求數據(request)、響應數據(response) 。雖然說后端接口的編寫并沒有統一
    的頭像 發表于 05-05 17:01 ?629次閱讀
    <b class='flag-5'>SpringBoot</b> <b class='flag-5'>后端接口</b><b class='flag-5'>規范</b>(中)

    后端分離必備的接口規范

    隨著互聯網的高速發展,前端頁面的展示、交互體驗越來越靈活、炫麗,響應體驗也要求越來越高,后端服務的高并發、高可用、高性能、高擴展等特性的要求也愈加苛刻,從而導致前后端研發各自專注于自己擅長的領域深耕細作。
    的頭像 發表于 05-15 17:16 ?818次閱讀
    前<b class='flag-5'>后端</b>分離必備的<b class='flag-5'>接口</b><b class='flag-5'>規范</b>

    springboot后端交互流程

    Boot 進行開發時,前后端交互是一個非常重要的部分,本文將詳細介紹 Spring Boot 前后端交互的流程。 前后端交互的基本原理 在前后端交互的過程中,前端負責向
    的頭像 發表于 11-22 16:00 ?2024次閱讀

    一個注解搞定SpringBoot接口防刷

    技術要點:springboot的基本知識,redis基本操作,
    的頭像 發表于 11-28 10:46 ?386次閱讀