最近在公司做多个系统整合,用户抱怨要反复登录不同平台,体验很差。老板一句话:搞个统一登录,别让用户天天输账号密码。于是我就接了这个活——把现有的几个系统接入SSO单点登录框架。
为什么选SSO?
我们有OA、CRM、内部博客和项目管理工具,四个系统用的都是不同的技术栈,有的是Spring Boot,有的是老Java Web,还有一个是PHP写的。如果每个都自己实现登录逻辑,维护起来太累。更麻烦的是,一旦用户离职,管理员得一个个系统去删账号。
SSO(Single Sign-On)的好处就是一次登录,到处通行。用户登录OA之后,点链接跳到CRM,不需要再输入密码,直接就能进。这种体验现在早就不是大厂专属了,中小项目也能轻松上。
技术选型:Keycloak vs CAS vs 自研?
一开始我也纠结过要不要自己写一个简单的Token服务,后来发现坑太多。比如登出同步、会话管理、跨域问题,看似简单,真做起来能熬掉几根头发。
最后选了Keycloak,开源、功能全、支持OIDC和SAML,而且社区活跃。部署起来也简单,Docker一条命令就跑起来了:
docker run -p 8080:8080 \
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak:start-dev
Spring Boot怎么接?
我们的主系统是Spring Boot写的,集成最方便。加个依赖就行:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
然后在application.yml里配置一下:
spring:
security:
oauth2:
client:
provider:
keycloak:
issuer-uri: http://localhost:8080/realms/my-realm
registration:
keycloak:
provider: keycloak
client-id: my-app
client-secret: your-client-secret
重启后访问接口,就会自动跳转到Keycloak登录页。登录完拿回ID Token和Access Token,用户信息从claims里取,角色权限也一并带过来,省事。
老系统怎么办?
那个PHP写的内部博客没法直接上Spring Security。我们用了反向代理方案,在Nginx前面加了一层验证逻辑。
用户访问博客时,先被重定向到Keycloak登录。登录成功后,Keycloak回调我们的验证服务,服务生成一个短期Token,写进Cookie。Nginx检查这个Cookie,通过了才放行到后端PHP应用。
虽然绕了点,但不用改老代码,运维也接受。
登出别忘了同步
有个坑刚开始没注意:用户点了登出,只退出当前系统,其他还在登录状态。这显然不行。
解决方案是前端登出时,除了清本地Session,还得跳转到Keycloak的登出地址:
http://localhost:8080/realms/my-realm/protocol/openid-connect/logout?redirect_uri=http://my-app.com
这样Keycloak会清理全局会话,下次登录就得重新认证。
测试时的小技巧
开发阶段不想每次都输账号密码,可以在Keycloak里建个测试用户,或者用浏览器插件临时注入Token。但我们规定上线前必须走完整流程测试一遍,避免配置遗漏。
还有就是跨域问题,前后端分离时记得在Keycloak客户端配置Web Origins,不然Redirect回来时会被拦住。
现在四个系统都接上了SSO,用户反馈明显变好了。管理员也在Keycloak后台统一管用户,新增、禁用一键搞定。后续还想加上LDAP同步,直接对接公司AD,到时候就更省心了。