1. 项目背景与整体思路拆解
先说结论:MaxKey和JeecgBoot的集成,本质上解决的是企业里“账号泛滥”和“重复登录”这两个老大难问题。我最早接到这个需求,是因为公司内部同时跑了OA、报表、低代码平台好几套系统,每个系统都有一套独立的账号体系。业务人员每天要在不同系统间切换,密码记混了就去点“找回密码”,IT部门光是处理密码重置工单就占用不少精力。后来我们决定用统一身份认证的思路来收口,调研了一圈,最终选了MaxKey作为认证中心,JeecgBoot作为业务接入方。
1.1 为什么选MaxKey而不是自己写认证
自己写一套统一登录不是不行,但投入产出比太低了。单点登录的核心不只是“登录”这一个动作,它背后要处理会话管理、令牌签发、密钥轮换、客户端注册、审计日志、密码策略、多因素认证这一整套体系。这些功能从零开始开发,没有两三个月拿不下来,而且后续的安全维护成本更高。
MaxKey是开源项目,基于Java技术栈,天然和JeecgBoot的Spring Boot生态匹配。它支持OAuth2.0、OIDC、CAS、SAML等多种协议,这意味着将来不只是JeecgBoot,其他系统比如泛微OA、金蝶云、自研的后台管理系统,都可以通过标准协议接入进来,不用针对每个系统单独做定制开发。这一点非常重要,因为很多公司在实际落地时,往往不是只接一个系统,而是“先试点一个,再批量铺开”,协议的标准化决定了这个架构能走多远。
1.2 协议选型:为什么最终用OAuth2.0授权码模式
MaxKey支持的协议很多,但对接JeecgBoot我们用的OAuth2.0授权码模式。原因有几个:
第一,JeecgBoot本身对OAuth2的集成支持比较完善,社区里已经有可参考的案例,踩坑成本低。第二,授权码模式是OAuth2所有模式里安全性最高的。它经过了两步交互,客户端拿到的授权码并不直接暴露给前端,令牌的换取发生在后端完成,access_token不会经过浏览器端,能有效降低令牌被截获的风险。第三,授权码模式天然支持刷新令牌,access_token失效后可以用refresh_token静默续期,用户的体验是“登录一次,长期有效”,减少了频繁重新认证的打扰。
第四,也是比较实际的一点,JeecgBoot未来如果要做移动端或者第三方应用接入,授权码模式通过PKCE扩展也能适应这些场景。选型的时候往前多想一步,后面就不会被迫推翻重来。
1.3 整体架构与登录流程设计
整个集成的架构其实非常清晰,我画个流程说明一下:
- 用户访问JeecgBoot的业务页面,发现未登录,JeecgBoot将请求重定向到MaxKey的授权端点。
- 用户在MaxKey的统一登录页完成认证(用户名密码、验证码等)。
- MaxKey认证通过后,生成授权码并回调到JeecgBoot预先配置的回调地址。
- JeecgBoot后端用授权码向MaxKey的令牌端点换取access_token和refresh_token。
- JeecgBoot调用MaxKey的用户信息端点获取用户基本信息(用户名、邮箱、手机号等)。
- JeecgBoot根据拿到的用户信息,在自己的用户表里查找或创建对应的本地用户,然后建立本地会话。
这个流程里最关键的设计决策是:JeecgBoot不直接信任前端传过来的用户身份,而是以MaxKey的用户信息端点返回结果为准。很多人第一次做对接容易犯的错误是,前端在URL参数里带个用户名就放行了,这等于把身份认证的信任边界直接暴露给了攻击者。后端换token、后端拉取用户信息、后端建立会话,这个链路必须完整走通。
2. 环境准备:MaxKey与JeecgBoot部署要点
动手配置之前,先把环境准备好。这部分看着基础,但很多问题排查到最后,发现都是环境不对导致的,所以单独拿出来说说。
2.1 MaxKey服务端部署方式选择
MaxKey服务端官方提供了多种部署方式,包括二进制包、Docker镜像、源码编译。我建议优先考虑Docker Compose方式,原因很简单:MaxKey依赖的组件比较多,包括MySQL(或PostgreSQL)数据库、Redis缓存,Docker Compose可以一次性把这些服务编排起来,避免手动配置数据库连接、初始化脚本这些繁琐的步骤。
version: '3' services: maxkey-mysql: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: maxkey123 MYSQL_DATABASE: maxkey volumes: - ./mysql-data:/var/lib/mysql ports: - "3306:3306" maxkey-redis: image: redis:6-alpine ports: - "6379:6379" maxkey-server: image: maxkeytop/maxkey:latest ports: - "9527:9527" depends_on: - maxkey-mysql - maxkey-redis environment: MYSQL_HOST: maxkey-mysql MYSQL_PORT: 3306 MYSQL_DATABASE: maxkey MYSQL_USERNAME: root MYSQL_PASSWORD: maxkey123 REDIS_HOST: maxkey-redis REDIS_PORT: 6379 volumes: - ./maxkey-logs:/opt/maxkey/logs注意几个细节。MySQL数据库一旦初始化完成后,数据库实例的编码和排序规则要确认是utf8mb4,否则后面账户同步如果涉及中文用户名或者特殊字符,存储会有问题。Redis主要用来管理会话和授权码的临时状态,生产环境建议给Redis设置密码,不要裸奔在公网。MaxKey默认端口是9527,配置反向代理时要把这个端口映射出去。
2.2 JeecgBoot环境准备
JeecgBoot的部署相对简单,它的后端是基于Spring Boot的,前端是Vue3。本地开发环境需要准备的工具包括:
- JDK 1.8或更高版本,建议JDK 8即可,兼容性最好。
- Maven 3.6+,配置好阿里云镜像仓库,国内拉取依赖速度会快很多。
- Node.js 16+,npm或yarn安装前端依赖。
- Redis,JeecgBoot的本地缓存和会话管理依赖Redis。
- MySQL 5.7+,JeecgBoot的业务数据存储在MySQL。
这些工具的安装和配置网上资料很多,我就不展开了,重点提醒几个容易踩的坑。Maven一定要配阿里云仓库,否则第一次构建项目时下载依赖可能要等半小时以上。Node.js版本不要太新,有些老项目的依赖对Node版本有要求,我自己遇到过Node 18下构建报错、退回Node 16就正常的情况。JDK环境变量配置好之后,命令行执行java -version必须能看到正确的版本信息,很多IDE启动失败都是环境变量配置不正确导致的。
2.3 网络规划与域名配置
MaxKey和JeecgBoot之间的交互都是HTTP请求,需要保证两个服务之间网络是通的。生产环境建议用内网域名通信,避免走公网。同时,MaxKey的回调地址需要配置成JeecgBoot实际可访问的地址,如果配置了Nginx反向代理,要注意回调地址是外网访问地址还是内网地址,这个不一致会导致授权码回调失败。
我在本地实验时,习惯在hosts文件里配置两个虚拟域名,比如maxkey.local指向127.0.0.1,jeecg.local也指向127.0.0.1。这样配置的好处是,后续调整端口或部署环境时,不用反复修改代码里的回调地址。
3. MaxKey端配置:注册应用与用户体系
MaxKey部署完成之后,通过浏览器访问http://maxkey.local:9527,默认管理员账号是admin,初始密码需要参考官方文档,首次登录会要求修改密码。登录进入管理控制台后,核心需要配置两块:一个是接入应用的信息,一个是用户和权限体系。
3.1 在MaxKey中注册客户端应用
在MaxKey管理控制台的“应用管理”中,新增一个应用。这里有几个关键参数:
应用名称:建议写“JeecgBoot”,方便后续维护时辨认。
应用协议:选OAuth2.0。
回调地址:这是最重要的参数。它必须是JeecgBoot后端实际处理OAuth2回调的接口地址。比如JeecgBoot部署在http://jeecg.local:8080,回调地址就是http://jeecg.local:8080/jeecg-boot/sso/callback。如果这个地址配错了,MaxKey虽然会生成授权码,但回调请求发不到正确的位置,整个登录流程就断了。
授权范围:一般选择read或all。范围决定了访问令牌能获取哪些用户信息端点。我们最终需要获取用户的基本信息,所以选all比较省事。
配置完成后,MaxKey会生成一个Client ID和Client Secret。这两个值要妥善保管,Client ID相当于应用的身份证号,Client Secret是应用与MaxKey通信的密钥。特别提醒,Client Secret不要打包进前端代码,也不要提交到Git仓库,一旦泄露,任何人都可以伪造你的应用去向MaxKey申请令牌。在实际项目里,我们会把它配置在后端的环境变量或配置中心。
3.2 MaxKey用户体系与JeecgBoot的映射关系
MaxKey用户体系里有两个核心概念:用户(User)和组织机构(Organization)。在对接JeecgBoot时,业务上通常只需要同步用户信息,不一定要同步组织机构。因为JeecgBoot本身有自己的一套组织架构和角色权限体系,强行走组织机构同步反而会造成两边数据结构不一致,维护起来很麻烦。
在MaxKey里创建一个测试用户,比如用户名是zhangsan,填写真实姓名、邮箱、手机号。这些字段后续会作为属性传递给JeecgBoot。
这里要注意一个设计问题:JeecgBoot本地的用户表中,用户名(username)字段必须是唯一的。而MaxKey里用户名也是唯一的。所以最自然的映射关系是:MaxKey的username直接对应JeecgBoot的username。但如果MaxKey的用户名格式和JeecgBoot本地用户的用户名格式不一致,比如MaxKey用工号,JeecgBoot用手机号,那就需要在JeecgBoot侧做一次映射转换。
这种映射逻辑最好实现在独立的适配层,不要散落在业务代码里。后续如果调整映射规则,只改一处就可以了。
3.3 MaxKey的应用权限与访问策略
MaxKey支持为应用配置访问策略,比如只允许某些用户或某些用户组访问这个应用。这个功能在企业场景下非常实用,比如只允许IT部门的用户通过单点登录访问JeecgBoot,其他用户即使有MaxKey账号,也不能访问JeecgBoot。
配置逻辑也很简单:在应用详情里选择“访问控制”,指定允许访问的用户组即可。默认情况下是允许所有合法用户访问,如果不需要做限制,这步可以跳过。
4. JeecgBoot端集成:OAuth2客户端封装
JeecgBoot端的集成是整个项目的关键。它的核心工作包括:引入OAuth2客户端依赖、配置认证服务器参数、实现回调接口、将MaxKey用户信息转换为本地会话。
4.1 在JeecgBoot中配置OAuth2客户端参数
JeecgBoot的后端是一个标准的Spring Boot工程。我们在pom.xml中引入Spring Security OAuth2 Client依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> </dependency>然后在application.yml中配置OAuth2客户端相关信息:
spring: security: oauth2: client: registration: maxkey: client-id: your-client-id client-secret: your-client-secret authorization-grant-type: authorization_code redirect-uri: "{baseUrl}/login/oauth2/code/maxkey" scope: all provider: maxkey: authorization-uri: http://maxkey.local:9527/maxkey/authz/authorize token-uri: http://maxkey.local:9527/maxkey/authz/token user-info-uri: http://maxkey.local:9527/maxkey/api/oauth/v1/me user-name-attribute: username这里需要解释几个参数的含义。authorization-grant-type指定了授权模式,我们用的是authorization_code,即授权码模式。redirect-uri是Spring Security自动生成的回调地址,{baseUrl}会自动替换成当前JeecgBoot服务的实际地址。authorization-uri、token-uri、user-info-uri是MaxKey暴露的端点地址,这三个地址必须和MaxKey实际部署的地址完全一致,任何路径拼写错误都会导致流程中断。
user-name-attribute指定了哪个字段作为用户的唯一标识,对应MaxKey用户信息返回JSON中的username字段。这个字段会用于后续查找本地用户。
4.2 实现回调接口与令牌处理
Spring Security OAuth2 Client依赖已经帮我们处理了大部分底层逻辑,包括授权码的接收、令牌的换取。但这些逻辑是框架自动完成的,如果我们要在登录成功后执行一些自定义逻辑,比如在本地用户表中查找或创建用户,就需要覆写相关处理器。
一个比较简洁的做法是自定义OAuth2UserService。当MaxKey返回用户信息后,框架会调用这个Service来加载用户。我们在加载用户时,同步在本地创建会话。
@Service public class MaxKeyOAuth2UserService extends DefaultOAuth2UserService { @Autowired private SysUserService sysUserService; @Override public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { OAuth2User oAuth2User = super.loadUser(userRequest); String username = oAuth2User.getAttribute("username"); String email = oAuth2User.getAttribute("email"); String displayName = oAuth2User.getAttribute("displayName"); // 检查本地用户是否存在,不存在则创建 SysUser localUser = sysUserService.getUserByName(username); if (localUser == null) { localUser = new SysUser(); localUser.setUsername(username); localUser.setEmail(email); localUser.setRealname(displayName); sysUserService.saveUser(localUser); } return oAuth2User; } }这段代码的逻辑是:先从MaxKey返回的OAuth2User对象中提取用户属性,然后调用本地用户服务查找用户。如果本地没有这个用户就自动创建,实现“首次登录即自动开通账号”的效果。这里有一个业务决策需要注意:新创建的用户应该赋予什么角色和权限?默认情况下我给的是普通用户角色,后续由管理员手动分配权限。企业里也可以做成自动映射,比如根据MaxKey的用户组动态分配JeecgBoot的角色,但这需要额外开发,且要考虑安全边界。
4.3 单点登录回调URL与OAuth2授权码流程
虽然Spring Security帮我们处理了大部分逻辑,但理解整个授权码流程对排查问题非常有帮助。特别是在对接过程中,我们需要查看日志、比对请求参数,如果脑子里没有完整的流程模型,定位问题会非常吃力。
完整流程如下:
第一步,用户访问JeecgBoot任意受保护页面,JeecgBoot检测到未登录,Spring Security将请求重定向到authorization-uri,同时携带参数:response_type=code、client_id=your-client-id、redirect_uri=...。
第二步,MaxKey展示统一登录页面,用户输入用户名密码。认证通过后,MaxKey生成一个授权码(code),并重定向到redirect_uri。
第三步,JeecgBoot后端接收到携带code的回调请求,Spring Security自动使用这个code向token-uri发起POST请求,换取access_token。
第四步,获取到access_token后,Spring Security调用user-info-uri获取用户信息。
第五步,用户信息返回后,OAuth2UserService将用户信息与本地用户绑定,创建本地会话。
整个流程涉及两次HTTP重定向和两次后端HTTP调用。我在排查问题时,习惯于在后端日志里跟踪这几个关键节点的请求参数和响应结果:
- 是否有
code参数到达回调接口? - 换取token的POST请求是否成功?返回的是200还是400?
- 用户信息接口返回的字段名是否与代码中取属性名一致?
4.4 实现JeecgBoot本地会话与MaxKey的对接
用户认证成功之后,JeecgBoot需要建立自己的一套会话机制。因为前端和业务系统内部,并不直接依赖MaxKey的token,而是依赖JeecgBoot自身的session或JWT。
一种合理的做法是:在OAuth2UserService中完成本地用户查找或创建后,再通过JeecgBoot自己的登录状态管理工具,生成一个本地的登录令牌返回给前端。这样业务系统内部的权限控制逻辑不需要做任何修改,仍然是基于JeecgBoot的认证体系。
这里有一个细节值得注意:如果JeecgBoot使用的是JWT模式,本地的JWT中需要包含用户ID、用户名、角色等常用信息。这个JWT的有效期可以由我们自行控制,比如设为8小时或24小时。MaxKey发出来的access_token的有效期一般比较短,比如默认5分钟或30分钟,它只用于与MaxKey之间的通信,不能直接作为JeecgBoot的业务令牌。
5. 账户同步机制:从MaxKey到JeecgBoot
单点登录解决了“登录一次、到处使用”的问题,但还有一个前置问题没有解决:JeecgBoot本地用户表里的账号从哪里来?如果每次都是第一个人登录时自动创建,确实能解决新账号的问题,但无法解决“离职账号回收”和“用户信息变更”的问题。所以我们需要一个账户同步机制。
5.1 账户同步的常见方案对比
账户同步有几种常见的实现思路,我分别说说利弊:
方案一:实时同步。在MaxKey里增加用户时,通过消息队列或Webhook实时推送用户信息到JeecgBoot。优点是及时性好,用户新增后马上就可以登录。缺点是需要修改MaxKey的代码或配置,集成成本高。
方案二:定时同步。JeecgBoot写一个定时任务,每隔一定时间(比如5分钟)调用MaxKey的用户管理API,拉取全量用户或增量用户,然后更新本地用户表。优点是实现简单,不侵入MaxKey。缺点是有时延,用户新增后最多要等一个同步周期才能登录。
方案三:SCIM协议同步。SCIM是专门用于身份管理的标准协议,MaxKey支持SCIM 2.0,JeecgBoot如果也能支持这个协议,两边可以无缝对接。但实际上大多数业务系统不会直接实现SCIM协议,所以这个方案更多是理想化的,落地成本不低。
在实际项目中,我选择的是定时同步+实时创建的混合策略:用户第一次通过单点登录访问时,实时创建本地账号;后续用户信息的变更(比如手机号、邮箱、姓名),通过定时任务从MaxKey批量同步更新。这种策略兼顾了体验和实现复杂度。
5.2 通过MaxKey API实现批量用户同步
MaxKey提供了用户管理相关的API,可以用来批量拉取用户列表。比如获取用户列表的接口大致是:
GET /maxkey/api/users Authorization: Bearer {access_token}返回的用户信息包括用户名、姓名、邮箱、手机号、部门、状态等。我们可以在JeecgBoot里写一个定时任务,调用这个接口,将用户列表与本地用户表做比对:
@Component public class MaxKeyUserSyncTask { @Autowired private SysUserService sysUserService; @Scheduled(cron = "0 */5 * * * ?") // 每5分钟执行一次 public void syncUsers() { List<MaxKeyUser> remoteUsers = maxKeyApiClient.getAllUsers(); for (MaxKeyUser remoteUser : remoteUsers) { SysUser localUser = sysUserService.getUserByName(remoteUser.getUsername()); if (localUser == null) { // 本地不存在,创建新用户 createLocalUser(remoteUser); } else { // 本地存在,更新用户信息 updateLocalUser(localUser, remoteUser); } } } }这个任务的核心逻辑是“比对差异、增量更新”。注意,不要简单粗暴地删除本地不存在的用户,因为JeecgBoot本地用户可能关联了业务数据,比如某个用户发起了一个审批流程,如果直接删除账号,会导致流程的历史数据关联不上。正确的做法是把本地用户状态标记为“已停用”,而不是物理删除。
5.3 用户状态同步与离职账号处理
账户同步最容易忽略的是用户状态字段。MaxKey用户有“启用/禁用”的概念,JeecgBoot用户也有。当某员工离职后,管理员在MaxKey里禁用该账号,那么JeecgBoot本地对应的账号也应该被禁用。
处理逻辑如下:
private void syncUserStatus(MaxKeyUser remoteUser, SysUser localUser) { if ("disabled".equals(remoteUser.getStatus())) { localUser.setStatus(2); // JeecgBoot中2表示禁用 } else { localUser.setStatus(1); } sysUserService.updateById(localUser); }这个功能非常重要。如果不做状态同步,离职人员的账号在JeecgBoot里依然是启用的,他可以通过直接访问JeecgBoot的登录页面(如果本地密码没有失效)进入系统,这会造成数据泄露的安全隐患。所以账号生命周期管理是账户同步里不可缺失的一环。
5.4 账户同步的日志与监控
账户同步任务看似简单,但执行频率高、涉及全量数据,一旦出问题影响面很大。比如MaxKey接口突然超时,定时任务抛出异常,如果吞掉了异常,会导致当天所有用户变更没有同步。所以一定要记录同步日志。
我一般会记录三个维度:任务执行记录(开始时间、结束时间、同步数量)、异常记录(哪些用户同步失败、失败原因)、变更记录(哪个用户新增了、哪个用户被禁用了)。后续如果出现数据不一致的问题,通过日志能快速定位是哪一次的同步异常导致的。
6. 常见问题与排查技巧实录
无论配置文档写得多详细,实际对接过程中总会遇到各种问题。下面这些是我在MaxKey+JeecgBoot对接过程中真实踩过的坑,整理成速查表,希望对你有帮助。
6.1 授权码回调404或redirect_uri不匹配
这个问题出现频率最高。原因通常是MaxKey应用配置的回调地址与JeecgBoot实际接收回调的地址不一致。注意检查几个点:
- MaxKey应用配置里填写的回调地址是否和JeecgBoot的
redirect-uri参数完全一致,包括协议、域名、端口、路径,必须是精确匹配。 - 如果JeecgBoot配置了Nginx反向代理,回调地址是外网地址还是内网地址?可能两边看到的是不同的地址,需要统一。
- Spring Security的
redirect-uri模板里如果写了{baseUrl},要看它最终解析成的实际地址是什么。
排查方法:在后端日志中搜索redirect_uri,把MaxKey回调请求里携带的redirect_uri参数值和MaxKey应用配置里的回调地址做对比,逐字符比对。
6.2 用户信息端点返回字段与代码不匹配
OAuth2用户信息接口返回的字段名是MaxKey定义的,不同版本的MaxKey可能字段名有差异。比如有的版本用username,有的版本用preferred_username,还有的版本返回displayName和nickname两个不同字段。
我的建议是:在写代码之前,先用Postman模拟一次完整的OAuth2流程,拿到用户信息接口的真实返回JSON,对照着字段名来写属性映射代码。不要想当然地根据文档写,文档经常和实际返回不一致。
另外,如果用户信息接口返回的是嵌套JSON结构,比如{"user": {"username": "zhangsan"}},那么属性解析要相应地写成oAuth2User.getAttribute("user")再转成Map,再取里面的username字段。
6.3 授权码换token失败或token无效
授权码换token失败,最常见的两个原因:一个是client_id和client_secret配置错误,一个是授权码已经过期。授权码的有效期通常很短,一般是几分钟,如果JeecgBoot处理回调逻辑耗时过长(比如回调里做了大量数据库操作),可能授权码已经失效了。
排查时先看MaxKey的日志,确认token端点是否收到了请求。再看响应内容,如果是invalid_grant,说明授权码无效或已过期,重新走一遍登录流程就好。如果是invalid_client,检查client配置。
还有一点容易忽略:JeecgBoot(发起换取token)的服务器IP和时间,要在MaxKey允许的范围内。MaxKey可能配置了IP白名单,如果JeecgBoot的服务器IP不在白名单内,即使client配置正确,也会被拒绝。
6.4 登录成功后本地用户不存在或权限异常
如果OAuth2流程已经走通,但登录后用户无法访问JeecgBoot的业务页面,优先检查本地用户的角色和权限是否配置正确。
在OAuth2UserService中自动创建的用户,默认可能没有分配任何角色。需要在用户创建的逻辑中,为新用户指定一个默认角色。比如:
localUser.setRoles(Collections.singletonList("ROLE_USER"));JeecgBoot的权限模型比较灵活,控制到按钮级别。如果用户登录后页面菜单为空,大概率是角色没有关联菜单权限。可以先用管理员账号登录后台,给这个新用户手工分配一下权限,验证是不是权限分配的问题。
6.5 高频排查点速查
| 问题现象 | 可能原因 | 排查优先级 |
|---|---|---|
| 点击登录后页面跳转到MaxKey再跳回来,出现404 | 回调地址不一致 | 高 |
| MaxKey登录成功后报错“授权码无效” | client配置错误或授权码过期 | 高 |
| 登录成功但页面提示“无权限” | 本地用户未分配角色 | 中 |
| 用户能登录但用户信息是空的 | user-info-uri返回的字段名不匹配 | 中 |
| 定时同步任务执行失败 | MaxKey接口超时或token过期 | 中 |
| 同步后用户状态未更新 | 状态字段映射逻辑缺失 | 低 |
7. 经验总结与扩展建议
整个MaxKey和JeecgBoot的对接做下来,我个人最大的体会是:单点登录这类企业级集成,技术上并没有特别高不可攀的门槛,真正的难点在于对接前的架构思考和对细节的耐心。
几个建议分享给大家:
第一,先定协议,再写代码。OAuth2、OIDC、CAS这几个协议各有适合的场景,不要一上来就看代码。先把协议理解清楚,再开始动手,能少走很多弯路。
第二,一切以真实接口返回为准。不要完全信任文档,文档和实际版本之间会有偏差。对接过程中,多用Postman或curl模拟请求,看看真实返回的数据长什么样。
第三,预留扩展的可能。比如这次接的是JeecgBoot,但下次可能接的是泛微OA,再下次可能是金蝶系统。所以MaxKey端配置的应用信息要分类管理,JeecgBoot端的OAuth2配置要独立封装,不要和业务代码耦合在一起。
这个项目如果继续往下扩展,可以往几个方向走:一是增加多因素认证,比如MaxKey开启短信验证码或TOTP动态口令;二是把MaxKey的审计日志接入公司的日志平台,方便安全审计;三是在JeecgBoot里增加一个“单点登录用户自助绑定”功能,让用户首次登录时可以选择绑定已有的本地账号,而不是自动创建新账号。
最后再分享一个小细节。在实际部署时,MaxKey的访问一定要全站HTTPS,因为授权码和令牌都是通过URL参数和请求头传递的,如果走明文HTTP,令牌被截获的风险非常大。生产环境不要图省事跳过这一步,这是身份认证系统的基本安全底线。