如何使用Spring Boot實現(xiàn)接口時間戳鑒權(quán)
Spring Boot實現(xiàn)接口時間戳鑒權(quán),簽名(sign
)和時間戳(ts
)放入請求頭(Header)。
一、請求頭參數(shù)設(shè)計
參數(shù)名 | 類型 | 說明 |
---|---|---|
ts | Long | 13位時間戳(Unix毫秒值),必填,標識請求有效期 |
sign | String | 簽名值,必填,用于校驗請求合法性 |
二、簽名算法調(diào)整(Header版)
1. 構(gòu)造原始字符串
str = key + url_encode(path) + ts
path:請求的URL路徑部分(不含查詢參數(shù)和域名),例如:/api/v1/user。
url_encode(path):需對路徑中的特殊字符進行URL編碼(如中文、/等無需編碼,但空格需轉(zhuǎn)義為%20)。
2. 生成簽名 SIGN
sgin = md5(S).toLowerCase()
結(jié)果轉(zhuǎn)換為小寫字符串,與請求頭中的sign對比校驗。
三、Spring Boot實現(xiàn)流程
1. 創(chuàng)建攔截器(Interceptor)
用于攔截請求,校驗ts和sign的合法性。
import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.util.Objects; public class AuthInterceptor implements HandlerInterceptor { private final String secretKey; // 從配置文件獲取密鑰,例如application.properties private final long maxClockSkew = 60 * 1000; // 時間窗口:60秒(允許客戶端與服務(wù)端的時間誤差) public AuthInterceptor(String secretKey) { this.secretKey = secretKey; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { // 1. 校驗時間戳是否存在 String ts = request.getHeader("ts"); if (StringUtils.isEmpty(ts)) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); response.setContentType("application/json"); // 返回錯誤信息:缺少時間戳 return false; } // 2. 校驗時間戳格式及有效性 long ts; try { ts = Long.parseLong(ts ); } catch (NumberFormatException e) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); // 返回錯誤信息:時間戳格式錯誤 return false; } long currentTime = System.currentTimeMillis(); if (currentTime - ts > maxClockSkew|| ts - currentTime > maxClockSkew) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 返回錯誤信息:請求已過期 return false; } // 3. 校驗簽名是否存在 String sign= request.getHeader("sign"); if (StringUtils.isEmpty(sign)) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); // 返回錯誤信息:缺少簽名 return false; } // 4. 構(gòu)造原始簽名字符串并生成簽名 String path = request.getRequestURI(); // 獲取路徑,例如"/api/v1/user" String encodedPath = URLEncoder.encode(path, StandardCharsets.UTF_8.toString()) .replace("+", "%20") // 處理空格編碼差異(URLEncoder默認用+,此處統(tǒng)一為%20) .replace("%7E", "~"); // 保留波浪線~的原始格式 String rawString = secretKey + encodedPath + tsHeader; try { MessageDigest md = MessageDigest.getInstance("MD5"); byte[] digest = md.digest(rawString.getBytes(StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(); for (byte b : digest) { sb.append(String.format("%02x", b)); // 轉(zhuǎn)換為小寫16進制字符串 } String generatedSign = sb.toString(); // 5. 對比簽名 if (!generatedSign.equals(sign)) { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // 返回錯誤信息:簽名校驗失敗 return false; } } catch (Exception e) { response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return false; } return true; // 校驗通過,允許請求繼續(xù) } }
2. 配置攔截器(WebMvcConfigurer)
將攔截器注冊到Spring Boot的攔截器鏈中,指定需要鑒權(quán)的接口路徑。
import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { private final String secretKey; // 從配置文件獲取密鑰,例如通過@Value注入 public WebConfig(String secretKey) { this.secretKey = secretKey; } @Override public void addInterceptors(InterceptorRegistry registry) { AuthInterceptor authInterceptor = new AuthInterceptor(secretKey); registry.addInterceptor(authInterceptor) .addPathPatterns("/api/v1/**") // 需要鑒權(quán)的接口路徑(如/api/v1下所有接口) .excludePathPatterns("/api/v1/public/**"); // 無需鑒權(quán)的公共接口(可選) } }
3. 配置文件(application.properties)
# 密鑰(建議從環(huán)境變量或配置中心獲取,而非硬編碼) auth.secret-key=your_secret_key_here
四、客戶端請求示例(以Postman為例)
1. 請求頭參數(shù)
名稱 | 值 |
---|---|
ts | 1686048000000(當前時間戳,13位Long) |
sign | 計算得到的簽名值(如e10adc3949ba59abbe56e057f20f883e) |
2. 簽名計算步驟(JavaScript示例)
function generateSignature(key, path, ts) { const encodedPath = encodeURIComponent(path).replace(/[!'()*]/g, encodeURIComponent); // 嚴格編碼特殊字符 const rawString = key + encodedPath + ts; const md5 = require('crypto-js/md5'); // 需要安裝crypto-js庫 return md5(rawString).toString().toLowerCase(); } // 示例調(diào)用 const key = 'your_secret_key'; const path = '/api/v1/user'; // 接口路徑 const ts = Date.now(); // 當前時間戳(13位) const sign = generateSignature(key, path, ts); console.log(sign); // 輸出簽名值
到此這篇關(guān)于如何使用Spring Boot實現(xiàn)接口時間戳鑒權(quán)的文章就介紹到這了,更多相關(guān)Spring Boot接口時間戳鑒權(quán)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Kotlin常用函數(shù)let,with,run,apply用法與區(qū)別案例詳解
這篇文章主要介紹了Kotlin常用函數(shù)let,with,run,apply用法與區(qū)別案例詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細內(nèi)容,需要的朋友可以參考下2021-09-09IDEA 程序包不存在,找不到符號但是明明存在對應(yīng)的jar包(問題分析及解決方案)
這篇文章主要介紹了IDEA 程序包不存在,找不到符號但是明明存在對應(yīng)的jar包 的解決方案,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08Spring Boot整合Elasticsearch實現(xiàn)全文搜索引擎案例解析
ElasticSearch作為基于Lucene的搜索服務(wù)器,既可以作為一個獨立的服務(wù)部署,也可以簽入Web應(yīng)用中。SpringBoot作為Spring家族的全新框架,使得使用SpringBoot開發(fā)Spring應(yīng)用變得非常簡單,在本案例中我們給大家介紹Spring Boot整合Elasticsearch實現(xiàn)全文搜索引擎2017-11-11Java實現(xiàn)提取Word文檔表格數(shù)據(jù)
使用Java實現(xiàn)Word文檔表格數(shù)據(jù)的提取,可以確保數(shù)據(jù)處理的一致性和準確性,同時大大減少所需的時間和成本,下面我們來看看具體實現(xiàn)方法吧2025-01-01詳解自動注冊Gateway網(wǎng)關(guān)路由配置
這篇文章主要為大家介紹了自動注冊Gateway網(wǎng)關(guān)路由配置的方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03Spring學(xué)習(xí)筆記之RedisTemplate的配置與使用教程
這篇文章主要給大家介紹了關(guān)于Spring學(xué)習(xí)筆記之RedisTemplate配置與使用的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用spring具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-06-06