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用户享有与普通登录用户相同的体验