最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Boot實現(xiàn)接口簽名驗證的過程

 更新時間:2024年04月26日 09:48:05   作者:濤哥是個大帥比  
在Spring Boot中實現(xiàn)接口校驗簽名通常是為了保證接口請求的安全性和數(shù)據的完整性,這篇文章主要介紹了Spring Boot實現(xiàn)接口簽名驗證,需要的朋友可以參考下

項目場景:

開放接口是指不需要登錄憑證就允許被第三方系統(tǒng)調用的接口。為了防止開放接口被惡意調用,開放接口一般都需要驗簽才能被調用。

在Spring Boot中實現(xiàn)接口校驗簽名通常是為了保證接口請求的安全性和數(shù)據的完整性。簽名校驗通常涉及對請求參數(shù)的簽名計算和驗證,以確保請求是由可信的發(fā)送方發(fā)送,并且在傳輸過程中沒有被篡改。下面,我將詳細介紹如何在Spring Boot應用中實現(xiàn)接口校驗簽名的過程。

解決方案:

1.配置簽名密鑰

簽名密鑰是用于生成和驗證簽名的秘密信息,生成規(guī)則自己定義,需要把生成的密鑰提供給第三方。

比如:

appId:360aa3a3ba074da6a7bb17ae55e72d26
appSecret:81343DC5-6E80-483A-A427-E3DF5FA4E5F3

/**
 * 生成應用id和密鑰
 */
@RequestMapping(value = "/getSecret", method = RequestMethod.GET)
public Map<String, String> getSecret() {
	//生成應用id和密鑰提供給第三方使用,具體生成規(guī)則自己定
	String appId = UUID.randomUUID().toString().replace("-", "").toLowerCase();
	String appSecret = UUID.randomUUID().toString().toUpperCase();
	System.out.println("appId:"+appId);
	System.out.println("appSecret:"+appSecret);
	Map<String, String> map = new HashMap<>();
	map.put("appId", appId);
	map.put("appSecret", appSecret);
	return map;
}

2.定義簽名算法

一個用于生成簽名,另一個用于驗證簽名。生成簽名的方法通常將請求參數(shù)按照特定規(guī)則計算出一個簽名值。常見的簽名算法有HMAC-SHA1、HMAC-SHA256等。

驗證簽名的方法則是對接收到的請求參數(shù)進行同樣的處理,并計算出一個簽名值,然后與請求中攜帶的簽名值進行比對。

package com.test.utils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Signature {
    /**
     * 獲取簽名
     * @param secretKey 密鑰
     * @param data  需要簽名的數(shù)據
     * @return  簽名
     */
    public static String signWithHmacSha1(String secretKey, String data) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA1");
            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(signingKey);
            return Base64.getEncoder().encodeToString(mac.doFinal(data.getBytes("UTF-8")));
        } catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
    /**
     * 驗證簽名
     * @param secretKey 密鑰
     * @param data  需要簽名的數(shù)據
     * @param hmac  已經簽名的數(shù)據
     * @return  true:簽名一致
     */
    public static boolean verify(String secretKey, String data, String hmac) {
        String calculatedHmac = signWithHmacSha1(secretKey, data);
        return calculatedHmac.equals(hmac);
    }
}

3.攔截器或過濾器實現(xiàn)

使用Spring的攔截器(Interceptor)或過濾器(Filter)來實現(xiàn)對接口請求的簽名校驗。在攔截器或過濾器中,你可以獲取到請求的參數(shù),并調用簽名驗證方法來校驗簽名的有效性。

package com.test.aop;
import com.test.utils.Signature;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
 * 簽名攔截器
 */
@Component
@Slf4j
public class SignInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");
        //分配的應用id
        String appId = request.getHeader("appId");
        //時間戳
        String timestampStr = request.getHeader("timestamp");
        //簽名
        String signature = request.getHeader("signature");
        if(StringUtils.isBlank(appId) || StringUtils.isBlank(timestampStr) || StringUtils.isBlank(signature)){
            response.setStatus(500);
            response.getWriter().println("參數(shù)錯誤!");
            return false;
        }
        //這個密鑰實際應該根據appId到數(shù)據庫里查出來
        String appSecret = "81343DC5-6E80-483A-A427-E3DF5FA4E5F3";
        //如果密鑰沒查到
//        if(flag){
//            response.setStatus(500);
//            response.getWriter().println("密鑰不存在!");
//        }
        //拼接數(shù)據
        String origin = appId + "\n" + appSecret + "\n" + timestampStr;
        if(!Signature.verify(appSecret, origin, signature)){
            response.setStatus(500);
            response.getWriter().println("簽名錯誤!");
            return false;
        }
        //業(yè)務的時間戳
        long timestamp = Long.parseLong(timestampStr);
        //當前時間戳
        long currentTimestamp = System.currentTimeMillis() / 1000;
        //10分鐘內有效
        long timeDifference = 10 * 60;
        if(Math.abs(timestamp - currentTimestamp) > timeDifference){
            response.setStatus(500);
            response.getWriter().println("簽名過期!");
            return false;
        }
        //放行
        return true;
    }
}

配置攔截器

package com.test.config;
import com.test.aop.SignInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
 * WebMvc配置
 */
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
	@Resource
	private SignInterceptor signInterceptor;
	@Override
	public void addInterceptors(InterceptorRegistry registry) {
		//不攔截的地址
		List<String> excludedList = new ArrayList<>();
		//swagger地址
		excludedList.add("/swagger-ui.html");
		excludedList.add("/swagger-ui.html/**");
		excludedList.add("/webjars/**");
		excludedList.add("/swagger/**");
		excludedList.add("/doc.html");
		excludedList.add("/doc.html/**");
		excludedList.add("/swagger-resources/**");
		excludedList.add("/v2/**");
		excludedList.add("/favicon.ico");
		//生成應用id和密鑰接口不攔截
		excludedList.add("/getSecret");
		registry.addInterceptor(signInterceptor)
				.addPathPatterns("/**")//攔截所有請求
				.excludePathPatterns(excludedList);//排除的請求
		super.addInterceptors(registry);
	}
}

4.測試接口

controller定義一個測試接口

/**
 * 測試簽名
 */
@RequestMapping(value = "/sign", method = RequestMethod.GET)
public String sign() {
	return "success";
}

模擬第三方調用:

我們需要把接口請求頭所需參數(shù)和簽名的方法告知第三方。

接口請求頭參數(shù)如下:

參數(shù)名稱中文參數(shù)值
appId應用id360aa3a3ba074da6a7bb17ae55e72d26
timestamp當前時間戳,精確到秒

1713838208

signature簽名bjvXebFiHi2+I93BNs+8+Tl2I7k=

簽名方法:

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
public class Signature {
    /**
     * 獲取簽名
     * @param secretKey 密鑰
     * @param data  需要簽名的數(shù)據
     * @return  簽名
     */
    public static String signWithHmacSha1(String secretKey, String data) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(secretKey.getBytes("UTF-8"), "HmacSHA1");
            Mac mac = Mac.getInstance("HmacSHA1");
            mac.init(signingKey);
            return Base64.getEncoder().encodeToString(mac.doFinal(data.getBytes("UTF-8")));
        } catch (NoSuchAlgorithmException | InvalidKeyException | UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

生成簽名示例:

public static void main(String[] args) {
   //這里的應用id和密鑰已實際分配的為準
   String appId = "360aa3a3ba074da6a7bb17ae55e72d26";
   String appSecret = "81343DC5-6E80-483A-A427-E3DF5FA4E5F3";
   //當前時間戳,精確到秒,示例:1713838208
   long timestamp = System.currentTimeMillis() / 1000;
   //拼接數(shù)據:appId、appSecret、timestamp
   String origin = appId + "\n" + appSecret + "\n" + timestamp;
   String signature = Signature.signWithHmacSha1(appSecret, origin);
   //需要加到請求頭的參數(shù)
   System.out.println("appId:"+appId);
   System.out.println("timestamp:"+timestamp);
   System.out.println("signature:"+signature);
}

當?shù)谌街澜涌谡埱箢^所需參數(shù)和簽名的方法后,就可以調用接口了

curl調用:

curl -X GET \
  http://localhost:8080/testservice/test/sign \
  -H 'appId: 360aa3a3ba074da6a7bb17ae55e72d26' \
  -H 'signature: bjvXebFiHi2+I93BNs+8+Tl2I7k=' \
  -H 'timestamp: 1713843128'

總結 這里簽名由appId + "\n" + appSecret + "\n" + timestamp,生成簽名字串時間戳用于保證簽名的有效性,即使簽名被盜用,也只能在有效時間內使用appId、appSecret自己定義生成規(guī)則,保存到數(shù)據庫中

源碼百度網盤下載地址:

鏈接: https://pan.baidu.com/s/1dhtbspb3AC3M_sWBG2D-Xg?pwd=k57m

提取碼: k57m

到此這篇關于Spring Boot實現(xiàn)接口簽名驗證的文章就介紹到這了,更多相關Spring Boot接口簽名驗證內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot進行模塊化開發(fā)的5種組織方式小結

    SpringBoot進行模塊化開發(fā)的5種組織方式小結

    模塊化開發(fā)作為解決復雜性的關鍵策略,能夠有效提升代碼的可維護性、可擴展性和團隊協(xié)作效率,本文將介紹SpringBoot模塊化開發(fā)的5種組織方式,需要的小伙伴可以參考一下
    2025-06-06
  • Hibernate的一對一,一對多/多對一關聯(lián)保存的實現(xiàn)

    Hibernate的一對一,一對多/多對一關聯(lián)保存的實現(xiàn)

    本文主要介紹了Hibernate的一對一,一對多/多對一關聯(lián)保存的實現(xiàn),文中通過示例代碼介紹的很詳細,感興趣的可以了解一下
    2021-09-09
  • Java反射機制,反射相關API,反射API使用方式(反射獲取實體類字段名和注解值)

    Java反射機制,反射相關API,反射API使用方式(反射獲取實體類字段名和注解值)

    這篇文章主要介紹了Java反射機制,反射相關API,反射API使用方式(反射獲取實體類字段名和注解值),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Java工作環(huán)境的配置與Eclipse的安裝過程

    Java工作環(huán)境的配置與Eclipse的安裝過程

    這篇文章主要介紹了Java工作環(huán)境的配置與Eclipse的安裝過程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • maven下載依賴失敗問題及解決

    maven下載依賴失敗問題及解決

    這篇文章主要介紹了maven下載依賴失敗問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • servlet實現(xiàn)文件下載的步驟及說明詳解

    servlet實現(xiàn)文件下載的步驟及說明詳解

    這篇文章主要為大家詳細介紹了servlet實現(xiàn)文件下載的步驟及說明,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • IDEA 2020 2全家桶安裝激活超詳細圖文教程

    IDEA 2020 2全家桶安裝激活超詳細圖文教程

    這篇文章主要介紹了IDEA-2020-2 全家桶安裝激活超詳細教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-08-08
  • JSONObject如何轉為實體類對象

    JSONObject如何轉為實體類對象

    介紹了JSONObject轉為實體類對象的三種方法:JSONObject中的toJavaObject方法和getObject方法支持深轉換,而JSON中的parseObject方法只能轉換一層對象,此外,還補充說明了在對JSON轉為實體類對象時,無論JSON中的數(shù)據字段是否多于或少于實體類中字段,轉化都不會報錯
    2024-11-11
  • Java中StringBuilder類的用法解析

    Java中StringBuilder類的用法解析

    StringBuilder是一個可變的字符序列,這個類提供了一個與StringBuffer兼容的API。本文主要為大家介紹了StringBuilder類的常用用法,需要的可以參考一下
    2023-05-05
  • springboot文件虛擬路徑映射方式

    springboot文件虛擬路徑映射方式

    這篇文章主要介紹了springboot文件虛擬路徑映射方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08

最新評論

周至县| 寿阳县| 济宁市| 迭部县| 南部县| 祁阳县| 蓬溪县| 临安市| 西华县| 株洲县| 怀远县| 南岸区| 璧山县| 平湖市| 宁河县| 河西区| 观塘区| 汤阴县| 瓮安县| 河源市| SHOW| 青岛市| 嵩明县| 林州市| 咸阳市| 凤城市| 东山县| 碌曲县| 原平市| 清流县| 白山市| 纳雍县| 雷山县| 乐山市| 额济纳旗| 平乐县| 独山县| 志丹县| 策勒县| 武夷山市| 武义县|