1. 概述
本文檔詳細介紹了將BladeX認證系統與若依(RuoYi)框架集成的完整實現過程。集成采用OAuth2.0授權碼流程,使用戶能夠通過BladeX賬號直接登錄若依系統,實現無縫單點登錄體驗。
2. 系統架構
2.1 總體架構
2.2 關鍵組件
- BladeAuthUtil: 工具類,處理與BladeX認證服務的通信
- BladeAuthController: 后端控制器,處理授權碼并生成若依JWT令牌
- BladeCallback.vue: 前端頁面,接收授權回調并處理認證結果
3. 后端實現
3.1 BladeAuthUtil工具類
public class BladeAuthUtil {public static Map<String, Object> getTokenByCode(String authUrl, String clientId, String clientSecret, String code, String redirectUri, String tenantId) {// 構建請求參數MultiValueMap<String, String> params = new LinkedMultiValueMap<>();params.add("grant_type", "authorization_code");params.add("code", code);params.add("client_id", clientId);params.add("client_secret", clientSecret);params.add("redirect_uri", redirectUri);if (tenantId != null && !tenantId.isEmpty()) {params.add("tenant_id", tenantId);}// 發送請求獲取令牌try {RestTemplate restTemplate = new RestTemplate();HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(params, headers);ResponseEntity<Map> response = restTemplate.exchange(authUrl, HttpMethod.POST, requestEntity, Map.class);return response.getBody();} catch (Exception e) {// 處理異常return null;}}
}
3.2 BladeAuthController控制器
@RestController
@RequestMapping("/blade/auth")
public class BladeAuthController {@Value("${blade.auth.url:}")private String authUrl;@Value("${blade.auth.client-id:}")private String clientId;@Value("${blade.auth.client-secret:}")private String clientSecret;@Value("${blade.auth.redirect-uri:}")private String redirectUri;@Autowiredprivate ISysUserService userService;@Autowiredprivate TokenService tokenService;@Autowiredprivate UserDetailsServiceImpl userDetailsService;@GetMapping("/getTokenInfo")public AjaxResult getTokenInfo(@RequestParam("code") String code, @RequestParam(value = "tenant_id", required = false) String tenantId) {// 獲取BladeX令牌Map<String, Object> tokenInfo = BladeAuthUtil.getTokenByCode(authUrl, clientId, clientSecret, code, redirectUri, tenantId);// 提取用戶名并查找若依系統用戶if (tokenInfo != null && tokenInfo.containsKey("account")) {String userName = (String) tokenInfo.get("account");SysUser user = userService.selectUserByUserName(userName);if (user != null) {// 使用UserDetailsServiceImpl創建LoginUser對象LoginUser loginUser = (LoginUser) userDetailsService.createLoginUser(user);// 記錄登錄信息recordLoginInfo(user.getUserId());// 使用TokenService生成JWT令牌String token = tokenService.createToken(loginUser);// 返回令牌AjaxResult ajax = AjaxResult.success();ajax.put(Constants.TOKEN, token);return ajax;}}return AjaxResult.error("認證失敗");}
}
4. 前端實現
4.1 登錄頁面增加BladeX登錄按鈕
<template><div class="login"><!-- 現有登錄表單 --><!-- 添加BladeX登錄按鈕 --><el-button type="primary" class="blade-login-btn" @click="handleBladeLogin">使用BladeX登錄</el-button></div>
</template><script>
export default {methods: {handleBladeLogin() {// BladeX授權頁面URLconst bladeAuthUrl = process.env.VUE_APP_BLADE_AUTH_URL;const clientId = process.env.VUE_APP_BLADE_CLIENT_ID;const redirectUri = encodeURIComponent(process.env.VUE_APP_BLADE_REDIRECT_URI);// 跳轉到BladeX授權頁面window.location.href = `${bladeAuthUrl}?client_id=${clientId}&response_type=code&redirect_uri=${redirectUri}`;}}
}
</script>
4.2 BladeCallback.vue回調處理頁面
<template><div class="blade-callback-container"><div class="callback-card"><div v-if="loading"><h2>正在處理BladeX授權...</h2><el-progress :percentage="progress"></el-progress></div><div v-else-if="error"><h2>授權處理失敗</h2><p>{{ errorMessage }}</p><el-button type="primary" @click="returnToLogin">返回登錄頁</el-button></div></div></div>
</template><script>
import { Message } from 'element-ui';
import { setToken } from '@/utils/auth';export default {data() {return {loading: true,error: false,errorMessage: '',code: '',tenantId: ''};},created() {// 獲取URL參數中的授權碼this.code = this.$route.query.code;this.tenantId = this.$route.query.state || '';// 處理授權碼this.handleAuthorizationCode();},methods: {// 處理授權碼handleAuthorizationCode() {request({url: '/blade/auth/getTokenInfo',method: 'get',params: {code: this.code,tenant_id: this.tenantId}}).then(response => {if (response.code === 200 && response.data && response.data.token) {// 使用若依token登錄this.handleLoginSuccess(response.data.token);} else {// 顯示錯誤信息this.handleError(response.msg || '獲取令牌失敗');}}).catch(error => {this.handleError('獲取令牌失敗: ' + error.message);});},// 處理登錄成功handleLoginSuccess(token) {// 保存tokensetToken(token);// 獲取用戶信息并生成路由this.$store.dispatch('GetInfo').then(() => {this.$store.dispatch('GenerateRoutes').then(accessRoutes => {// 動態添加可訪問路由表this.$router.addRoutes(accessRoutes);// 跳轉到首頁this.$router.push({ path: '/' });});});}}
};
</script>
5. 配置說明
5.1 后端配置 (application.yml)
# BladeX認證配置
blade:auth:# BladeX認證服務地址url: https://auth.example.com/oauth/token# 客戶端IDclient-id: your_client_id# 客戶端密鑰client-secret: your_client_secret# 重定向URIredirect-uri: http://your-app-url/auth/blade-callback
5.2 前端配置 (.env.development)
# BladeX配置
VUE_APP_BLADE_AUTH_URL=https://auth.example.com/oauth/authorize
VUE_APP_BLADE_CLIENT_ID=your_client_id
VUE_APP_BLADE_REDIRECT_URI=http://your-app-url/auth/blade-callback
5.3 安全配置
在SecurityConfig.java
中添加允許匿名訪問的路徑:
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {httpSecurity// 其他配置.antMatchers("/blade/auth/getTokenInfo",// 其他允許匿名訪問的路徑).permitAll()
}
6. 實現步驟
6.1 前置準備
- 向BladeX系統管理員申請OAuth2.0客戶端ID和密鑰
- 確認并配置授權回調URL
- 確保若依系統中存在與BladeX用戶名相匹配的賬號
6.2 后端實現步驟
- 創建BladeAuthUtil工具類
- 實現BladeAuthController控制器
- 在application.yml中添加BladeX配置
- 更新SecurityConfig安全配置
6.3 前端實現步驟
- 在登錄頁添加BladeX登錄按鈕
- 創建回調處理頁面BladeCallback.vue
- 配置前端環境變量
- 更新路由配置,添加回調頁面路由
6.4 路由配置
在前端路由配置中添加BladeX回調頁面:
// router/index.js
export const constantRoutes = [// 其他路由{path: '/auth/blade-callback',component: () => import('@/views/auth/BladeCallback'),hidden: true}
]
7. 集成測試
7.1 測試流程
- 點擊BladeX登錄按鈕,驗證是否正確重定向到BladeX授權頁面
- 在BladeX系統完成登錄授權
- 驗證是否正確重定向回若依系統
- 檢查是否成功獲取若依JWT令牌
- 驗證是否成功進入若依系統首頁
- 測試若依系統的各項功能是否正常
7.2 故障排查
- 檢查瀏覽器控制臺日志
- 查看后端日志輸出
- 使用開發者工具檢查網絡請求
- 驗證Redis中是否成功緩存了登錄用戶信息
8. 安全與性能考慮
8.1 安全
- 確保client_secret不被暴露在前端代碼中
- 實現CSRF防護
- 設置合理的token過期時間
- 考慮實現單點登出功能
8.2 性能
- 緩存用戶權限信息
- 考慮多Redis節點的情況下的token共享
- 優化前端資源加載
9. 常見問題與解決方案
9.1 回調地址配置問題
問題:BladeX系統報錯"重定向URI不匹配"
解決方案:確保在BladeX系統注冊的重定向URI與application.yml和前端環境變量中配置的完全一致,包括協議、域名、端口和路徑。
9.2 無法獲取用戶信息
問題:獲取到BladeX令牌但無法獲取用戶信息
解決方案:檢查請求參數是否正確,特別是client_id和client_secret,并確認BladeX用戶賬號是否有效。
9.3 若依系統找不到對應用戶
問題:BladeX認證成功但若依系統找不到對應用戶
解決方案:確保在若依系統中創建與BladeX用戶名相匹配的賬號,或實現自動創建用戶的功能。
10. 結論
通過本文檔介紹的方法,成功實現了BladeX單點登錄與若依框架的無縫集成,用戶可以使用BladeX賬號直接登錄若依系統,享受到統一認證的便利性。集成過程充分利用了若依現有的登錄機制,最小化了代碼修改,確保了系統的穩定性和安全性。
本集成方案具有以下優勢:
- 完全復用若依原生登錄流程的后半部分,確保與系統其他部分的一致性
- 令牌格式、存儲、過期機制與原生系統保持一致
- 最小化修改,降低集成風險
- BladeX用戶享有與普通登錄用戶相同的體驗