目錄
- 概述
- 系統架構
- 單點登錄流程
- 令牌管理機制
- 接口調用流程
- 關鍵代碼實現
- 數據結構
- 安全性考慮
- 常見問題與解決
概述
本文檔詳細說明若依系統如何實現與BladeX的單點登錄集成,包括令牌管理和接口調用的完整流程。整個集成采用基于OAuth2的授權碼流程,允許用戶通過BladeX賬號登錄若依系統,并使用BladeX令牌訪問BladeX的各類API。
系統架構
整個單點登錄與令牌管理系統主要包含以下組件:
前端組件
BladeCallback.vue
:處理BladeX認證回調的前端頁面/src/api/blade/apiTest.js
:BladeX API封裝
后端服務
BladeAuthController
:處理BladeX認證回調和token獲取BladeApiController
:提供BladeX API代理接口BladeTokenManager
:管理BladeX令牌的存儲和檢索BladeApiClient
:調用BladeX API的客戶端BladeAuthUtil
:提供BladeX認證工具方法
數據存儲
- Redis:存儲BladeX令牌與若依用戶ID的映射關系
單點登錄流程
詳細步驟
-
發起BladeX授權:用戶在登錄頁點擊"使用BladeX登錄"按鈕,前端將用戶重定向到BladeX授權頁面。
-
BladeX認證:用戶在BladeX系統中完成登錄和授權,BladeX認證服務生成授權碼并重定向回若依系統的回調URL。
-
處理授權回調:
- 前端:
BladeCallback.vue
組件接收授權碼,并調用后端接口 - 后端:
BladeAuthController.getTokenInfo
方法處理授權碼
- 前端:
-
獲取BladeX令牌:
BladeAuthUtil.getTokenByCode
方法向BladeX認證服務發送請求,交換授權碼獲取訪問令牌- 解析響應,獲取訪問令牌、過期時間、用戶信息等
-
查找對應若依用戶:
- 根據BladeX返回的用戶名(account)或username在若依系統中查找對應用戶
- 如未找到匹配用戶,返回錯誤信息
-
創建若依登錄會話:
- 使用與原生登錄完全相同的流程創建LoginUser對象
- 記錄登錄IP和時間
- 使用TokenService生成若依系統的JWT令牌
- 保存登錄狀態到Redis
-
保存BladeX令牌:
- 使用BladeTokenManager將BladeX訪問令牌存入Redis
- 將令牌與若依用戶ID建立映射關系
- 設置與BladeX令牌相同的過期時間
-
返回登錄結果:
- 前端接收若依JWT令牌并保存
- 獲取用戶信息和路由
- 跳轉到系統首頁
令牌管理機制
BladeX令牌的管理由BladeTokenManager
類負責,主要功能包括:
-
令牌保存:
- 將BladeX令牌信息封裝為
BladeToken
對象存儲在Redis中 - 使用"blade_tokens:userId"作為Redis鍵名
- 設置與BladeX原始令牌相同的過期時間
- 將BladeX令牌信息封裝為
-
令牌獲取:
- 通過用戶ID快速檢索對應的BladeX令牌
- 提供訪問令牌(access_token)的便捷獲取方法
-
令牌驗證:
- 檢查用戶是否擁有有效的BladeX令牌
- 令牌自動隨Redis過期機制失效
-
令牌刪除:
- 在用戶登出或手動清除令牌時刪除Redis中的對應記錄
令牌數據結構
BladeToken
類包含以下字段:
userId
:若依系統用戶IDuserName
:用戶名accessToken
:BladeX訪問令牌loginTime
:令牌獲取時間(毫秒時間戳)expireTime
:令牌過期時間(毫秒時間戳)
接口調用流程
詳細步驟
-
前端發起請求:
- 前端調用若依系統API,例如
/blade/api/getUserInfo
- 前端調用若依系統API,例如
-
獲取BladeX令牌:
BladeApiController
從SecurityUtils
獲取當前登錄用戶ID- 調用
BladeTokenManager.getAccessToken(userId)
獲取令牌
-
構建API請求:
BladeApiClient
負責構建請求并添加必要的請求頭- 添加"Blade-Auth: bearer {accessToken}"頭
- 添加Basic認證頭用于API身份驗證
-
發送API請求:
- 使用RestTemplate發送HTTP請求到BladeX API
- 處理各類響應和異常
-
錯誤處理:
- 當遇到401未授權響應時,識別為令牌過期
- 提示用戶令牌已過期,需要重新登錄
關鍵代碼實現
保存BladeX令牌
// BladeAuthController.java
String accessToken = (String) tokenInfo.get("access_token");
Integer expiresIn = (Integer) tokenInfo.get("expires_in");
if (accessToken != null && expiresIn != null) {bladeTokenManager.setBladeToken(user.getUserId(), user.getUserName(), accessToken, expiresIn);log.info("成功保存用戶BladeX令牌, userId={}, expiresIn={}秒", user.getUserId(), expiresIn);
}
令牌保存實現
// BladeTokenManager.java
public void setBladeToken(Long userId, String userName, String accessToken, int expiresIn) {BladeToken bladeToken = new BladeToken();bladeToken.setUserId(userId);bladeToken.setUserName(userName);bladeToken.setAccessToken(accessToken);bladeToken.setLoginTime(System.currentTimeMillis());bladeToken.setExpireTime(bladeToken.getLoginTime() + expiresIn * 1000L);// 存儲到Redis,過期時間設置為令牌有效期String tokenKey = getTokenKey(userId);redisCache.setCacheObject(tokenKey, bladeToken, expiresIn, TimeUnit.SECONDS);
}
API調用示例
// BladeApiClient.java
public <T> T callBladeApi(Long userId, String url, HttpMethod method, Object requestBody, Class<T> responseType) {// 獲取用戶的訪問令牌String accessToken = tokenManager.getAccessToken(userId);if (StringUtils.isEmpty(accessToken)) {throw new ServiceException("用戶沒有有效的BladeX訪問令牌,請重新登錄");}// 構建請求頭HttpHeaders headers = new HttpHeaders();headers.set("Blade-Auth", "bearer " + accessToken);headers.set("Blade-Requested-With", "BladeHttpRequest");// 添加Basic認證String auth = clientId + ":" + clientSecret;byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());String authHeader = "Basic " + new String(encodedAuth);headers.set("Authorization", authHeader);// 構建請求實體HttpEntity<?> requestEntity = new HttpEntity<>(requestBody, headers);// 發送請求并返回結果ResponseEntity<T> response = restTemplate.exchange(url, method, requestEntity, responseType);return response.getBody();
}
數據結構
配置參數
在application.yml
中配置BladeX相關參數:
blade:auth:# BladeX認證服務地址url: https://auth.we-safer.net/oauth/token# 客戶端IDclient-id: chem_ruoyi# 客戶端密鑰client-secret: chem_ruoyi_secret# 重定向URIredirect-uri: http://192.168.100.106:81/auth/blade-callbackapi:# BladeX API基礎地址base-url: https://we-safer.net/api
Redis存儲結構
BladeX令牌在Redis中的存儲格式:
- 鍵名格式:
blade_tokens:userId
- 值格式:序列化的
BladeToken
對象 - 過期時間:與BladeX令牌過期時間一致(通常為7200秒)
安全性考慮
-
令牌安全存儲:
- BladeX令牌僅存儲在服務器端Redis中,不暴露給前端
- 使用與BladeX原始令牌相同的過期時間,確保令牌及時失效
-
認證請求安全:
- BladeX認證請求使用HTTPS協議
- 客戶端密鑰僅在服務器端使用,不暴露給前端
-
授權碼流程:
- 使用標準的OAuth2授權碼流程,提高安全性
- 授權碼使用一次后立即失效
-
請求安全性:
- API調用添加Basic認證頭
- 添加BladeX特定請求頭標識請求來源
常見問題與解決
-
用戶未找到問題:
- 問題:BladeX認證成功但未找到對應的若依用戶
- 解決:確保在若依系統中創建與BladeX賬號同名的用戶
-
令牌過期問題:
- 問題:BladeX令牌過期導致API調用失敗
- 解決:檢測到401錯誤時提示用戶重新登錄,自動跳轉到登錄頁
-
認證服務配置問題:
- 問題:未正確配置BladeX認證服務參數
- 解決:檢查application.yml中的BladeX認證配置是否完整