ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

若依SSO OAuth2环境配置全攻略:从零搭建统一登录认证中心

若依SSO OAuth2环境配置全攻略:从零搭建统一登录认证中心 前阵子接了个内部需求几个后台系统各自维护一套账号用户每换一个系统就要重新登录一次吐槽声不断。领导让我研究单点登录我在若依社区找了一圈发现了ruoyi-sso-oauth2这个开源项目——它把 OAuth2 授权协议接到了若依的用户体系上用一套若依账号就能打通多个系统的登录态。这篇是第一篇环境配置是整个系列里最枯燥、但最容易劝退人的一环我把自己踩过的坑和配置逻辑完整写出来后面再单独聊认证流程和系统接入。1. 先看懂架构ruoyi-sso-oauth2到底要解决什么问题1.1 从“多个系统各自登录”到“一套账号通走全网”你现在的局面可能是这样若依后台一个登录页进销存系统一个登录页运营后台又一个登录页每个系统的用户表还可能是分开的。SSO 要解决的就是“用户只需要在某一个系统上登录一次其他系统自动信任这个登录状态”。而 OAuth2 在这里的作用是定义“授权怎么发生、令牌怎么签发、资源怎么访问”的标准流程。两者配合之后登录页可以统一收敛到认证中心业务系统不需要再保存用户密码。我用一个简单的类比若依的用户体系相当于公司人事部掌握的员工名册SSO 是那张“进门刷一次卡、整栋楼通用”的工牌OAuth2 则是“如何发卡、如何验卡、如何回收卡”的刷卡协议。认证中心就是发卡室各业务系统就是大楼里的不同办公区。1.2 这套开源项目里到底有哪几个角色不管代码仓库里的模块怎么命名只要涉及 SSO 和 OAuth2都跑不出这几个角色认证中心Authorization Server负责展示统一登录页、校验若依的sys_user账号密码、签发授权码和令牌。它承担的职责相当于“总闸门”。业务系统Client / Resource Server这里是接入方。比如若依后台、进销存系统、报表系统每个系统都有自己的clientId和clientSecret用来标识自己是谁也有权向认证中心换取用户信息。统一缓存Redis保存授权码、令牌、用户会话映射关系。这一步是整个 SSO 能跨系统共享登录态的关键。前端工程Vue3登录成功后持有令牌后续请求通过 HTTP 头把令牌带给业务后端。理解这些角色的最好办法就是拉下代码后看启动类所在包。有auth、sso、oauth相关字样的大概率是认证中心剩下的业务模块就是接入方。如果只是埋头按 README 顺序启动很容易把端口和职责搞混。1.3 授权码模式为什么适合SSOSSO 场景里最常用的是 OAuth2 的授权码模式authorization_code。为什么不用若依原本的“用户名密码直接换 token”因为若依原来的模型解决的是“单系统登录”它无法替你解决“业务系统 A 不能替你在业务系统 B 登录”的问题。授权码模式的流程是这样的用户访问业务系统的受保护资源未登录则跳转到认证中心。用户在认证中心输入若依的账号密码。认证中心校验通过生成一次性授权码通过回调地址传给业务系统。业务系统拿着授权码向认证中心的后端接口换取真正的令牌。整个过程中业务系统始终接触不到用户的密码用户也只需要在认证中心输入一次账号密码。后面一旦接入第三个、第四个系统只需要让它们都信任同一个认证中心就行。2. 环境清单每一样工具都对应一个“为什么”2.1 JDK与Maven版本不匹配是第一个翻车点这套项目是基于若依改造的若依主流分支构建在 Spring Boot 2.5.x 上所以 99% 的情况下你该选JDK 8而不是最新的 JDK 21。很多人觉得“版本越新越好”结果一编译就遇到CGLIB、反射和类库兼容问题折腾一晚才发现是 JDK 版本太高。如果你计划把项目升级到 Spring Boot 3 Spring Security 6 再接入新版本 OAuth2那才需要考虑 JDK 17但那是另一个话题第一篇文章不建议在环境上做超前升级。Maven 建议 3.6.x 或 3.8.x不推荐 4.x。安装完成之后本地settings.xml一定要配阿里云镜像否则拉依赖的速度会非常感人甚至直接超时失败。配好之后用两条命令验证java -version mvn -v这两条命令不仅看版本号还要注意Maven home底下的 JDK 是否是你指定的那个。IDEA 里经常出现mvn clean install报“无效的目标发行版1.8”的诡异错误就是因为 Maven 进程用的是 IDEA 自带的高版本 JDK不是系统装的 JDK 8。2.2 MySQL与RedisSSO的会话状态都得落在Redis里数据库层面MySQL 5.7 和 8.0 都可以配置时字符集统一用utf8mb4表排序规则建议utf8mb4_general_ci避免后面出现中文乱码和表情符号写入失败。Redis 的版本稍微灵活一些5.x、6.x、7.x 都能跑但新版 Redis 默认开启了protected-mode如果你本地没有配置requirepass外部连接可能被拒。若依系列项目默认配置里 Redis 密码通常是空字符串所以本地开发阶段建议直接关闭保护模式或者给 Redis 设置密码后同步改到项目配置里。Windows 机器上玩 Redis 最省事的方案是用 Docker 拉一个官方镜像docker run -d --name redis-local -p 6379:6379 redis:7-alpine如果不方便用 Docker也可以下载 Windows 编译版但稳定性一般。遇到 Redis 连接超时先不要怀疑代码用redis-cli ping确认服务本身活着再检查端口和密码。2.3 Node与npm版本不对连依赖都装不上前端工程如果是 Vue3 版本Node.js 建议用 16.x 或 18.x LTS不要一上来装最新的 22.x。Node 版本过高时npm run dev经常报error:0308010C:digital envelope routines::unsupported这是 OpenSSL 版本变化导致的兼容问题虽然有人用NODE_OPTIONS--openssl-legacy-provider绕过去但更稳妥的做法是用 nvm 切换回 LTS 版本。npm 的 registry 也要提前换好npm config set registry https://registry.npmmirror.com还有一类经典问题老版本若依前端依赖node-sass这东西安装时经常要求 Python 和 C 编译环境属于天生的“环境终结者”。如果你拉到的仓库里 package.json 还在用node-sass建议直接改成sassDart Sass用法基本兼容。新版本若依很多已经切到纯sass了遇到类似问题就先看依赖再看报错。工具推荐版本主要用途验证命令JDK1.8后端编译运行java -versionMaven3.6.x / 3.8.x依赖管理与构建mvn -vMySQL5.7 / 8.0若依业务数据mysql -uroot -pRedis5.x授权码、令牌、会话缓存redis-cli pingNode.js16.x / 18.x LTS前端构建运行node -v3. 代码拉取与工程导入先看目录再去启动3.1 拉代码与分支选择代码从 Gitee 或 GitHub 拉取都行地址以你找到的仓库主页为准拉下来之后不要急着mvn spring-boot:run先看两样东西README 里的启动文档以及项目根目录下的sql或db目录。前者告诉你作者预期的启动顺序后者告诉你数据库初始化需要哪些脚本。分支建议选master或main。开发分支可能正在重构依赖关系随时变动新手拿着一个未完成的dev分支去编译报错之后根本分不清是自己环境问题还是代码问题非常劝退。git clone 仓库地址 cd ruoyi-sso-oauth23.2 多模块工程里藏着的依赖顺序这类项目一般是 Maven 多模块结构常见模块大概是模块名职责典型端口sso-oauth2-common公共工具、常量、通用返回体无sso-oauth2-auth-server认证中心统一登录页和令牌签发8080sso-oauth2-client业务系统示例演示接入方式8081sso-oauth2-uiVue3 前端工程80 / 8080具体模块名以你拉到的仓库为准但思路一致。先编译公共模块再编译认证中心最后编译业务系统。最省事的方式是在项目根目录一次性执行mvn clean install -DskipTests这一步会把公共模块安装到本地 Maven 仓库之后单独启动认证中心和业务系统才不会出现“找不到某个依赖包”的错误。如果只在 IDEA 里启动某个模块而不提前 install经常会出现类找不到的报错本质就是公共模块没装进本地仓库。3.3 IDEA导入时的三个细节第一个细节导入工程时选择“作为 Maven 项目导入”并开启自动导入依赖第二个细节Project SDK 和 Module SDK 必须统一IDEA 会自动检测 JDK但你可能装了多个版本一定要手动指向 JDK 8第三个细节装 Lombok 插件并且开启注解处理。如果漏了 Lombok 相关的配置编译时会报getter/setter 找不到之类的错误因为若依底层大量用了Data注解IDE 不识别注解时就会把正常的代码当成一堆错误。遇到这种报错先别慌不是代码有问题是编译环境缺插件。4. 配置文件的逐项改动配错一个地方启动报错完全不一样4.1 数据库连接driverClassName和时区若依系列项目的数据源配置通常在application-druid.yml或application.yml的spring.datasource节点下。如果你用的是 MySQL 8驱动类要写成com.mysql.cj.jdbc.Driver老版本用的com.mysql.jdbc.Driver在新驱动里已经不建议使用了。URL 里的参数很有讲究最少要包含三样东西UTF-8 编码、时区、SSL 关闭。推荐配置spring: datasource: url: jdbc:mysql://localhost:3306/ruoyi_sso?useUnicodetruecharacterEncodingutf8serverTimezoneAsia/ShanghaiuseSSLfalse username: root password: 你的密码 driver-class-name: com.mysql.cj.jdbc.Driver如果你连 MySQL 8 时遇到了Public Key Retrieval is not allowed这是因为用户认证插件是caching_sha2_password开发环境最省事的处理是加allowPublicKeyRetrievaltrue或者把用户密码认证方式改成mysql_native_password。生产环境建议保持默认加密策略这里不展开。4.2 Redis连接密码、database和序列化Redis 配置一般在application.yml里项目如果引入了 Redisson 或 Spring Data Redis可能会有独立的配置节点。开发环境需要的只有几项host、port、password、database。spring: redis: host: localhost port: 6379 password: # 如果Redis没有密码留空 database: 0database的坑很容易被忽略如果你本机 Redis 之前被别的项目写过数据里面可能存在同名 key干扰 SSO 的缓存逻辑。开发环境建议单独用一个 database比如database: 3这样既能和其他项目隔离也不会误删别人数据。另一个需要注意的是序列化器若依框架通常会配置 JSON 序列化方式如果 Redis 里的数据肉眼看到一堆\xac\xed\x00之类的字节说明序列化方式不统一登录和验权就会出现反序列化失败。4.3 SSO与OAuth2相关参数端口、clientId、redirect_uri这一部分是环境配置里最容易出差错、也最容易被忽略的。认证中心端口和业务系统端口先要固定下来后续所有跳转都会基于这些端口。一般认证中心是 8080业务系统是 8081前端是 80 或 8080。然后是一组 OAuth2 客户端参数通常是oauth2: client: client-id: sso-client client-secret: sso-client-secret redirect-uri: http://localhost:8081/callback这里的关键是redirect-uri。认证中心只管按白名单校验回调地址你在业务系统里写死了http://localhost:8081/callback认证中心里也必须放行同样的地址。很多人启动之后发现登录后一直 302 循环八成就是这里不一致。令牌有效期也要注意。开发调试阶段把 token 有效期设短一点是有好处的比如 30 分钟这样你测试刷新令牌流程时不用等上几个小时生产环境再按业务要求调长。源码里常见的端点/oauth/authorize、/oauth/token是 Spring Security OAuth2 旧版端点不同版本可能不完全一致配置前先看本仓库的SecurityConfig或AuthorizationServerConfig确认路径不要照抄网上的旧教程。4.4 前端代理与跨域SSO跳转必须能访问到认证中心前端 Vue3 工程里Vite 的vite.config.js通常配了代理把/api之类的路径转发到后端端口。SSO 跳转之所以“看起来像跨域”是因为浏览器地址栏从业务系统页面跳到了认证中心的域名和端口。但实际上 OAuth2 授权码模式大量依赖浏览器的 302 跳转这种场景不属于 AJAX 跨域只要前后端都通过浏览器正常访问即可不需要额外处理 CORS。真正需要关注的是开发环境里前端如何访问业务系统。如果你用npm run dev启动 Vue3端口假设是 80那么代理配置大概长这样server: { port: 80, proxy: { /api: { target: http://localhost:8081, changeOrigin: true } } }登录完成后前端调http://localhost/api/system/user/list时会被代理到业务系统 8081前后的上下文路径必须对齐否则会出现页面能打开、接口全部 404 的诡异情况。5. 初始化数据库与前端的“最后一公里”5.1 SQL脚本导入字符集和初始账号在导入 SQL 脚本之前先手动创建数据库不要直接拿mysql命令行导入的时候再让数据库自动创建避免字符集不统一CREATE DATABASE IF NOT EXISTS ruoyi_sso DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;然后在项目源码的sql目录里找到初始化脚本按文件名顺序导入。顺序很重要比如先有菜单表、用户表再有业务表否则外键和关联关系会乱。若依沿用下来的初始账号一般是admin / admin123如果认证中心和业务系统共用同一个库那么两边的登录用户自然就通了如果是各自独立的数据库你需要保证两边用户表的数据一致SSO 才能认同一套账号体系。导入完成后用 Navicat 或命令行随便查一下sys_user表确认admin用户存在密码字段是 BCrypt 加密串。如果用户名对不上或者表是空的后面认证中心无论如何都不可能登录成功。5.2 npm install依赖装到一半卡住怎么办前端依赖安装是这个环节最折磨人的一步。如果你遇到npm install卡住不动或者报网络错误先检查 registry 是否切到了国内镜像然后把package-lock.json和node_modules一起删掉再试rm -rf node_modules package-lock.json npm cache clean --force npm install这里插一句不要在npm install之后顺手执行npm audit fix虽然它会提示有安全漏洞但这个命令很可能带来破坏性的依赖升级让项目启动报新的兼容错误。开发环境只要项目能正常启动先跑通核心流程要紧。启动前端时用npm run dev看到终端输出VITE ready之类的提示后浏览器访问对应的端口。如果项目默认端口被占用Vite 会自动换端口但你要记住新端口因为前端代理配置、SSO 回调地址也可能和这个端口有关联。6. 首次启动的完整验证从后端到浏览器全过程6.1 启动顺序认证中心先于业务系统启动顺序是有讲究的先启动认证中心再启动业务系统最后启动前端。理由很简单业务系统启动时虽然不强制依赖认证中心在线但你在浏览器里走完整流程时认证中心必须先处于可用状态。如果顺序颠倒业务系统已经调到认证中心了结果认证中心还在启动中你会看到连接被拒的报错容易误判是配置问题。观察启动日志的时候重点看几个关键信息Tomcat started on port(s): 8080说明认证中心起来了。没有出现Unknown database、Access denied说明数据库连接正常。没有出现RedisConnectionFailureException说明 Redis 也通了。任何一个环节报错都先回查第 4 节里的配置不要往下走流程。6.2 浏览器完整走一遍SSO登录流程我建议你按下面的路径完整验证一次浏览器访问业务系统受保护页面比如http://localhost:8081/system/user/list。系统检测到未登录302 跳转到认证中心的授权地址。你会发现地址栏变成了类似http://localhost:8080/oauth/authorize?client_idsso-clientresponse_typecoderedirect_urihttp://localhost:8081/callback的样子。认证中心展示统一登录页输入admin / admin123。登录成功后认证中心回跳到http://localhost:8081/callback?codexxx。业务系统后端拿到code向认证中心换取令牌然后加载用户信息最终展示用户列表页面。如果流程走到第 4 步就断了比如一直在登录页和业务系统之间来回跳基本可以确定是redirect_uri不一致。如果流程走到了第 5 步但页面报 401排查令牌是否真正换取成功可以打开浏览器的开发者工具看网络请求里有没有携带Authorization请求头。6.3 常见的四个启动失败现场与排查顺序把这几个问题单独拎出来是因为我在实操中每个都遇到过而且报错信息特别容易误导人。现象常见原因处理方式启动时报数据库连接失败数据库名不对、密码错误、驱动类不对检查application-druid.yml中的 URL、账号、密码、驱动类登录页能打开但提交账号后报 Redis 连接超时Redis 没启动、密码不一致、database 被占用先用redis-cli ping验证再核对配置登录后一直 302 跳转回登录页回调地址不一致统一redirect-uri并检查浏览器地址栏是 localhost 还是 127.0.0.1前端页面打开但接口全部 404Vite 代理没生效、后端上下文路径不匹配检查vite.config.js的 proxy target 和后端 context-path排查顺序是固定的先看 Redis 和 MySQL 是否连通其次看后端日志里的异常堆栈最后再怀疑前端代理。后端日志的报错最关键它不会骗你比任何猜测试都准确。6.4 一个容易被忽略的细节回调地址里的localhost和127.0.0.1这个细节坑过很多人http://localhost:8081/callback和http://127.0.0.1:8081/callback在浏览器看来是同一个东西但在 OAuth2 的严格校验里它们不是同一个地址。如果你在认证中心配置的回调地址是localhost但浏览器访问业务系统时用的却是127.0.0.1就会导致回调地址校验失败登录流程直接中断。开发环境最好从头到尾统一用localhost不要一会儿打localhost一会儿打127.0.0.1。还有浏览器 HTTP 与 HTTPS 的差异也要注意认证中心如果是 HTTP回调地址就不要配 HTTPS。这类问题不影响编译也不影响启动但会在你测试 SSO 流程时突然出现非常消耗耐心。整个环境配置阶段我犯过最大的错误就是在一开始装了 JDK 21结果编译报错时先怀疑代码后怀疑 Maven最后一查才发现是版本不匹配。后来老老实实按 JDK 8 Maven 3.6 阿里云镜像 Node 16 这套组合一次通过。环境通了之后后面的授权码流程、令牌刷新、业务系统接入才有意义。下一篇我准备写认证中心的完整工作流程包括授权码是如何生成、如何换取令牌以及 token 在 Redis 里的数据结构把这些链路真正吃透之后你就不只是“能用”而是“能改”。
返回列表