前端接口使用restful格式,post與get的區別是什么?
HTTP網絡返回的狀態碼有哪些?
go語言切片與數組的區別是什么?
MySQL實現并發安全避免兩個事務同時對一個記錄寫操作的手段有哪些?
如何實現業務的冪等性(在golang代碼中如何避免消息重復或處理已出現的消息重復)?
如何設置redis分布式鎖?
SETNX
是 Redis 中的一個命令,全稱為 “SET if Not eXists”。它的作用是在鍵不存在時設置鍵的值。具體來說,SETNX
的功能如下:
語法
SETNX key value
返回值
- 1: 如果鍵成功設置(即鍵不存在)。
- 0: 如果鍵已經存在,設置失敗。
用法示例
1. 設置一個鍵
SETNX my_key "some_value"
- 如果
my_key
不存在,則它的值被設置為"some_value"
,返回 1。 - 如果
my_key
已經存在,則不做任何操作,返回 0。
2. 用于分布式鎖
SETNX
常用于實現分布式鎖,因為它可以確保只有一個進程可以獲得鎖。例如:
import redis# 連接到 Redis
client = redis.StrictRedis(host='localhost', port=6379, db=0)# 嘗試獲取鎖
if client.setnx("my_lock", "some_unique_value"):print("Lock acquired")# 執行臨界區代碼# 釋放鎖client.delete("my_lock")
else:print("Lock already acquired")
注意事項
- 不適合復雜操作:
SETNX
只能用于簡單的鍵值設置,不能用于復雜的條件判斷。 - 鎖的有效性: 在實現分布式鎖時,結合使用
SETNX
和設置過期時間可以防止死鎖。
ThreadLocal
ThreadLocal
是 Java 中的一個類,用于提供線程局部變量。每個使用 ThreadLocal
的線程都可以獨立地存儲和訪問自己的變量副本,而不會與其他線程共享。以下是關于 ThreadLocal
的詳細解釋:
1. 基本概念
- 線程局部變量: 每個線程在訪問
ThreadLocal
變量時,會得到自己獨立的副本。這意味著一個線程對ThreadLocal
變量的修改不會影響其他線程。 - 存儲位置:
ThreadLocal
變量存儲在每個線程的ThreadLocalMap
中。
2. 使用方法
2.1 創建 ThreadLocal
變量
ThreadLocal<String> threadLocalVar = new ThreadLocal<>();
2.2 設置值
使用 set()
方法將值存儲到當前線程的 ThreadLocal
變量中。
threadLocalVar.set("Hello, ThreadLocal!");
2.3 獲取值
使用 get()
方法從當前線程的 ThreadLocal
變量中獲取值。
String value = threadLocalVar.get(); // 返回 "Hello, ThreadLocal!"
2.4 清除值
使用 remove()
方法可以清除當前線程的 ThreadLocal
變量值。
threadLocalVar.remove();
3. 示例代碼
以下是一個使用 ThreadLocal
的簡單示例:
public class ThreadLocalExample {private static ThreadLocal<Integer> threadLocalValue = ThreadLocal.withInitial(() -> 0);public static void main(String[] args) {Runnable task = () -> {Integer value = threadLocalValue.get();value++;threadLocalValue.set(value);System.out.println(Thread.currentThread().getName() + ": " + threadLocalValue.get());};Thread thread1 = new Thread(task);Thread thread2 = new Thread(task);thread1.start();thread2.start();}
}
4. 適用場景
- 用戶會話信息: 在 Web 應用中,可以使用
ThreadLocal
存儲每個請求的用戶信息。 - 數據庫連接: 每個線程可以持有自己的數據庫連接,避免共享連接導致的線程安全問題。
- 性能優化: 減少對象的創建和銷毀,避免頻繁的上下文傳遞。
5. 注意事項
- 內存泄漏: 如果不調用
remove()
方法,線程局部變量可能會導致內存泄漏,尤其在使用線程池時。 - 不適合跨線程使用:
ThreadLocal
變量僅在創建它的線程中可見,其他線程無法訪問。 - 調試困難: 使用
ThreadLocal
可能會讓調試變得復雜,因為變量的狀態依賴于線程的生命周期。
總結
ThreadLocal
是一個強大的工具,適用于需要線程隔離的數據存儲場景。合理使用可以提高性能和簡化代碼,但也需要注意內存管理和線程安全問題。
超賣問題怎么解決?
- redis使用lua腳本判斷和扣減庫存
- 使用redis隊列避免數據不一致的問題(先將數據存入redis隊列中,從redis隊列中取出記錄添加到數據庫)
后端如何對一個請求鑒權?為什么JWT要雙簽發?被截獲了怎么辦?如果人為地想要禁止某個用戶的訪問應該怎么做?
一、后端請求鑒權流程
后端通常通過以下步驟驗證請求合法性:
- Token 提取
從請求頭(如Authorization: Bearer <token>
)或 Cookie 中獲取 JWT。 - 簽名驗證
用預設密鑰驗證 JWT 簽名是否被篡改(例如使用 HMAC 或 RSA 算法)。 - 有效期檢查
校驗exp
(過期時間)和nbf
(生效時間)字段。 - 業務邏輯鑒權
- 從 JWT 解析用戶角色/權限(如
role: admin
)。 - 對比請求資源所需的權限(如 RBAC 模型)。
- 從 JWT 解析用戶角色/權限(如
- 敏感操作二次驗證
關鍵操作(如支付)要求重新輸入密碼或 2FA 驗證。
# Python 偽代碼示例(使用 PyJWT)
def verify_request(request):token = request.headers.get("Authorization").split("Bearer ")[1]try:payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])if payload["role"] != "admin":raise PermissionError("無權訪問")return Trueexcept jwt.ExpiredSignatureError:raise Unauthorized("Token過期")
二、JWT 雙簽發機制及作用
雙簽發(Dual-Issuer) 指同時使用兩個密鑰簽發 Token:
- 主密鑰(Primary Key)
- 用于簽發長期有效的 訪問令牌(Access Token)(如有效期 1 小時)。
- 從密鑰(Secondary Key)
- 用于簽發短期有效的 刷新令牌(Refresh Token)(如有效期 7 天)。
? 核心目的:安全性隔離
- 訪問令牌泄露風險高:頻繁在網絡傳輸,暴露概率大。
- 刷新令牌嚴格保護:僅用于獲取新訪問令牌,存儲于安全環境(如 HttpOnly Cookie)。
- 攻擊窗口最小化:即使 Access Token 被截獲,有效期短且無法直接獲取新 Token。
三、JWT 被截獲的應對措施
攻擊類型 | 防御方案 | 示例 |
---|---|---|
中間人竊聽 | 強制 HTTPS + HSTS 頭 | 服務器配置 TLS 1.3 |
客戶端腳本竊取 | HttpOnly Cookie 存儲 + XSS 防護 | 設置 Set-Cookie: HttpOnly; Secure |
Token 泄露 | 短期有效期 + 刷新令牌輪轉 | Access Token 有效期 ≤15 分鐘 |
重放攻擊 | JTI(JWT ID)唯一標識 + 服務端黑名單 | 使用 Redis 記錄已使用的 JTI |
刷新令牌輪轉示例:
每次用 Refresh Token 獲取新 Access Token 時,同步生成新 Refresh Token 并作廢舊令牌。這樣即使舊刷新令牌被截獲,攻擊者只能使用一次。
四、禁止特定用戶訪問的解決方案
1. 短期封禁:令牌黑名單(Token Blacklist)
- 適用場景:立即踢出已登錄用戶。
- 實現方式:
- 用戶注銷或封禁時,將 JWT 的
jti
(唯一ID)加入 Redis 黑名單。 - 鑒權時校驗
jti
是否在黑名單中。
- 用戶注銷或封禁時,將 JWT 的
- 優點:實時生效。
- 缺點:增加數據庫查詢開銷。
# 封禁用戶時
redis.set(f"blacklist:{jti}", "1", ex=ACCESS_TOKEN_EXPIRE)# 鑒權時檢查
if redis.exists(f"blacklist:{jti}"):raise Forbidden("用戶已被封禁")
2. 長期封禁:用戶狀態標記
- 適用場景:永久禁止訪問。
- 實現方式:
- 在用戶數據庫添加
is_active
字段。 - 鑒權時查詢用戶狀態(注意緩存用戶信息避免頻繁查庫)。
- 在用戶數據庫添加
- 優點:一勞永逸。
- 缺點:狀態變更后需等待 Token 自然過期。
3. 強制令牌失效:刷新令牌回收
- 封禁用戶時,刪除該用戶的刷新令牌。
- 用戶 Access Token 過期后無法續簽,自動退出。
五、最佳實踐總結
- 雙簽發必要性
? 隔離高風險令牌(Access Token)與高價值令牌(Refresh Token)。 - 防截獲組合拳
? HTTPS + 短有效期 + HttpOnly Cookie + 刷新令牌輪轉。 - 封禁用戶策略
- 緊急場景:令牌黑名單(實時生效)。
- 永久封禁:標記用戶狀態 + 回收刷新令牌。
- 性能優化
- 黑名單用 Redis 存儲并設置自動過期(與 Token 有效期對齊)。
- 用戶狀態變化時清理緩存(如 Redis 中的用戶信息)。
關鍵原則:JWT 本身無狀態,需通過黑名單/用戶狀態引入必要狀態控制,在安全性和性能間取得平衡。