见字如面,与大家分享实践中的经验与思考。

一篇文章带你了解单点登录系统,包括不限于:SSO 是什么、SSO 的常用协议、SSO 的登录流程、SSO 的几种常见解决方案以及最后的企业级SSO 系统搭建。

什么是 SSO单点登录(SSO)是一种身份验证解决方案,可让用户通过一次性用户身份验证登录多个应用程序和网站。这意味着用户只需输入一次用户名和密码,即可访问所有相互信任的系统,而无需在每个系统中单独登录。鉴于当今的用户经常直接从其浏览器访问应用程序,因此组织正在优先考虑改善安全性和用户体验的访问管理策略。SSO 兼具这两方面的优点,因为一旦验证身份,用户就可以访问所有受密码保护的资源,而无需重复登录。

SSO 的主要优点包括:

用户体验改进:用户只需记住一个用户名和密码,减少了重复登录的麻烦。

安全性增强:通过集中管理认证信息,可以更好地控制和保护用户数据,降低密码泄露的风险。

效率提升:减少了因多次登录导致的时间浪费,提高了工作效率。

在 SSO(单点登录)系统中,身份提供者(Identity Provider,IdP)和服务提供者(Service Provider,SP)是两个关键角色。SSO 依赖于身份提供者(Identity Provider,IdP)和服务提供者(Service Provider,SP)之间的信任关系。

身份提供者(Identity Provider, IdP):

定义:IdP 是负责验证用户身份并提供身份信息的实体。它管理用户的认证信息(如用户名、密码、令牌等)并提供这些信息给信任它的服务提供者。

例子:

企业内部 IdP:如 Microsoft Active Directory Federation Services(AD FS),它为企业内部应用提供单点登录服务。

第三方 IdP:如 Google、Facebook、Okta 等,它们为各种第三方应用提供认证服务。

服务提供者(Service Provider, SP):

定义:SP 是提供某种服务或应用的实体,它依赖 IdP 来验证用户身份。SP 信任 IdP 提供的身份验证信息,并根据这些信息决定用户的访问权限。

例子:

企业应用:如企业的邮件系统、CRM(客户关系管理)系统、ERP(企业资源计划)系统等,这些系统通过企业内部的 IdP 提供单点登录功能。

在线服务:如 Dropbox、Salesforce、Slack 等,这些在线服务可以通过第三方 IdP(如 Google 或 Okta)提供单点登录功能。

SSO 常见的协议和技术SAML(Security Assertion Markup Language):一种基于 XML 的开放标准,用于在身份提供者和服务提供者之间交换认证和授权数据。

OAuth:一种开放标准,允许第三方应用程序在不暴露用户密码的情况下访问用户信息。

OIDC:OpenID Connect 是使用一组用户凭证访问多个站点的方法。它允许服务提供商承担验证用户凭证的角色。Web 应用程序不是将身份验证令牌传递给第三方身份提供商,而是使用 OIDC 来请求附加信息并验证用户的真实性。

LDAP:轻量级目录访问协议 (LDAP) 是一种行业标准,基于 X.500 标准的轻量级目录访问协议,用来进行统一账号管理、身份验证平台。

Kerberos:Kerberos 是一种基于票证的身份验证系统,可让两方或多方在网络上相互验证其身份。它使用安全密码学来防止未经授权访问在服务器、客户端和密钥分发中心之间传输的标识信息。

SSO 的登录流程图

详细步骤说明:

步骤 1 和 2:用户请求资源,系统 A 发现用户未登录,返回重定向指令。

步骤 3 和 4:用户浏览器重定向到 SSO,用户在 SSO 登录。

步骤 5:SSO 验证成功后,重定向回 系统 A ,并附带 token。

步骤 6:用户浏览器重定向到 系统 A 的回调页面。

步骤 7 和 8:系统 A 向 SSO 验证 token,SSO 返回用户信息。

步骤 9:系统 A 创建或更新用户登录信息。

步骤 10:系统 A 返回用户请求的资源页面。

搭建 SSO 常用解决方案搭建一个 SSO(单点登录)系统有多种方法,具体选择取决于组织的需求、技术栈以及安全要求。以下是几种常见的方法:

1. 使用现有的 SSO 解决方案商业解决方案:

Okta:提供广泛的 SSO 服务,包括云和本地应用的集成。

Microsoft Azure Active Directory:适用于使用 Microsoft 技术的组织,提供强大的身份管理和 SSO 功能。

Ping Identity:提供企业级的身份管理和 SSO 解决方案。

开源解决方案:

Keycloak:一个开源的身份和访问管理工具,支持 SSO、身份联合和管理。

Gluu Server:一个灵活的开源 SSO 和身份管理平台。

Shibboleth:一个支持 SAML 的开源身份提供者和服务提供者解决方案。

适用场景快速启动:项目需要快速部署且时间紧迫。

广泛支持:需要支持多种应用和服务的集成。

企业级支持:需要企业级的技术支持和维护。

2. 自定义开发实现 SSOSAML(Security Assertion Markup Language):

SAML 是一个基于 XML 的开放标准,用于在身份提供者和服务提供者之间交换认证和授权数据。

适用于企业级应用和内部系统集成。

OAuth 2.0 和 OpenID Connect:

OAuth 2.0 是一种授权框架,允许第三方应用在不暴露用户密码的情况下访问用户信息。

OpenID Connect 是基于 OAuth 2.0 的认证协议,提供简单而强大的身份验证功能。

适用于现代 web 和移动应用的 SSO 实现。

使用 JWT Token 自定义开发:

对于特定需求,可以自定义开发一个 SSO 系统,使用 JWT(JSON Web Token)等技术进行认证和授权。

需要较高的技术投入和安全管理。

适用场景协议标准化:需要使用标准化协议(如 SAML、OAuth 2.0、OpenID Connect)进行认证和授权。

灵活性:需要灵活的配置和扩展能力。

定制需求:现有解决方案无法完全满足项目的特殊需求。

控制和安全:需要完全控制系统的每个方面,包括安全和性能。

3. 集成现有身份管理系统LDAP(轻量级目录访问协议):

使用 LDAP 服务器(如 OpenLDAP、Microsoft Active Directory)集中管理用户身份,并通过 LDAP 进行认证。

适用于需要集中管理用户和组的组织。

Kerberos:

使用 Kerberos 协议进行网络认证,通过中心认证服务器验证用户身份。

适用于需要强身份验证和单点登录的企业环境。

适用场景现有系统扩展:已有身份管理系统(如 LDAP、Active Directory)并希望扩展其功能以实现 SSO。

集中管理:希望统一管理用户身份和访问权限。

4. 使用 WAM 解决方案Web Access Management 工具

使用 WAM 工具(如 CA SiteMinder、IBM Tivoli Access Manager)管理 web 应用的访问和 SSO。

适用于大型企业和复杂的 web 应用环境。

适用场景复杂环境:需要复杂的访问控制和策略管理,通常用于大型企业。

多种身份验证方法:需要支持多种身份验证方法和复杂的访问策略。

假设一个业务背景:使用低成本、快速来完成 SSO 系统平台的搭建,比较推荐以下两种方式:

1、采用 SpringBoot + Oauth2 + JWT Token 技术栈,进行代码的定制化开发

2、采用开源工具(比如:Keycloak) 来快速进行搭建,在此基础上进行基础以及一定的定制化插件开发

除了低成本、快速外,我们还需要更加强大的功能,比如:支持 two-factor 双因子校验、复杂的 password strategy 等,那可以尝试使用 Keycloak 来进行快速的搭建和集成。如果你有一整套基于 Oauth2 的代码可以进行快速的复用,采用第一种方案也是一种不错的考虑,从零开始开发的话,相较于第二种方案成本会大一些。下面就来介绍一下方案二如何使用。

使用 Keycloak 搭建企业 SSOKeycloak 是一个开源的身份和访问管理解决方案,提供了 SSO(单点登录)、多因素认证、LDAP 和 Active Directory 集成、社交登录(如 Google、Facebook 等)、用户管理等功能。它基于现代身份协议(如 OAuth 2.0、OpenID Connect 和 SAML),并且非常适合微服务架构和现代 Web 应用。

如何开始使用 KeyCloak大致可以分为四步:

1. 安装 Keycloak:

可以使用 Docker 部署 Keycloak,或下载二进制包进行安装。

官方文档 提供详细的安装和配置指南。

2. 配置域和用户:

通过管理控制台创建和配置域、用户、角色和客户端。

3. 集成应用:

使用客户端适配器或直接调用 Keycloak 的 API,将应用与 Keycloak 集成。

配置应用的认证和授权策略。

4. 自定义和扩展:

根据需求进行自定义,如定制登录界面、邮件模板,或扩展 Keycloak 的功能。

01 安装 KeycloakPre Start1、需要准备本地的云容器环境,可以参考本文最后的往期文章推荐。在之前的文章中我采用的 Rancher Desktop 来构建本地的云环境,是因为 Docker Desktop 开始商用收费,如果是个人电脑做研究,还是可以直接使用 Docker Desktop 的。两者总体体验下来差异不大。

2、官方给出的 quick start demo 实在是太简单了,没有高可用,没有数据存储,我会调整脚本以支持高可用 HA、MySQL 数据库存储防止数据丢失等,最终以 K8S yaml 脚本进行部署。

3、Keycloak的数据默认持久化在本地文件中,在生产环境中需要通过数据库来持久化数据,我这里使用容器化部署的 MySQL。

4、通过 Ingress 配置域名,并且自动配置 HTTPS,可以参考往期文章,这里因为是本地安装,暂时改用 NodePort 方式访问。

Docker本地快速启动体验可以使用这种方式。

docker run -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:25.0.1 start-dev安装成功后通过本地 8080 端口进行访问,用户名和密码分别为 admin、admin。

Kubernetes脚本编写:

支持高可用 HA K8S,同时数据持久化到 MySQL 中。其中k8s secret 中的配置按需进行调整,完整的脚本如下:

apiVersion: v1

kind: Service

metadata:

name: keycloak

labels:

app: keycloak

spec:

ports:

- name: http

port: 8080

targetPort: 8080

nodePort: 30008

selector:

app: keycloak

type: NodePort

---

apiVersion: v1

kind: Secret

metadata:

name: keycloak-secret

labels:

app: keycloak

type: Opaque

data: # changme

keycloak_admin_user: YWRtaW4= # admin

keycloak_admin_password: YWRtaW4= # admin

db_provider: bXlzcWw= # mysql

db_url: amRiYzpteXNxbDovL215c3FsLmRldm9wcy5zdmMuY2x1c3Rlci5sb2NhbDozMzA2L2tleWNsb2FrP2NoYXJhY3RlckVuY29kaW5nPVVURi04 # jdbc:mysql://mysql.devops.svc.cluster.local:3306/keycloak?characterEncoding=UTF-8

db_user: cm9vdA== # root

db_password: cGFzc3dvcmQ= # password

---

apiVersion: apps/v1

kind: Deployment

metadata:

name: keycloak

labels:

app: keycloak

spec:

replicas: 2 # changeme

selector:

matchLabels:

app: keycloak

template:

metadata:

labels:

app: keycloak

spec:

containers:

- name: keycloak

image: quay.io/keycloak/keycloak:25.0.1

args:

- --verbose

- start

env:

- name: KEYCLOAK_ADMIN

valueFrom:

secretKeyRef:

name: keycloak-secret

key: keycloak_admin_user

- name: KEYCLOAK_ADMIN_PASSWORD

valueFrom:

secretKeyRef:

name: keycloak-secret

key: keycloak_admin_password

- name: KC_PROXY

value: "edge"

- name: KC_DB

valueFrom:

secretKeyRef:

name: keycloak-secret

key: db_provider

- name: KC_DB_URL

valueFrom:

secretKeyRef:

name: keycloak-secret

key: db_url

- name: KC_DB_USERNAME

valueFrom:

secretKeyRef:

name: keycloak-secret

key: db_user

- name: KC_DB_PASSWORD

valueFrom:

secretKeyRef:

name: keycloak-secret

key: db_password

ports:

- name: http

containerPort: 8080

readinessProbe:

httpGet:

path: /realms/master

port: 8080

resources:

limits:

cpu: "4"

memory: 2048M

requests:

cpu: "2"

memory: 1024M核心的环境变量如下表所示:

https://www.keycloak.org/server/all-config

环境变量

取值

说明

KC_HOSTNAME

test.keycloak.org

访问 Keycloak 时的域名

KC_HTTP_PORT

8080

HTTP 端口

KC_HTTPS_PORT

8443

HTTPS 端口

KC_HTTPS_CERTIFICATE_FILE

/mnt/certificates/tls.crt

生产环境需通过 HTTPS 访问,这里是之前部署的 SSL 证书

KC_HTTPS_CERTIFICATE_KEY_FILE

/mnt/certificates/tls.key

生产环境需通过 HTTPS 访问,这里是之前部署的 SSL 证书

KC_DB

mysql

数据库类型,这里用 mysql

KC_DB_URL

jdbc:mysql://mysql-db-service.mysql:3306/keycloak?characterEncoding=UTF-8

数据库连接地址,这里通过之前部署的 mysql 的 Service 进行访问

KC_DB_USERNAME

root

mysql账号

KC_DB_PASSWORD

testpassword

mysql密码

KC_HEALTH_ENABLED

true

开启健康检查

KC_METRICS_ENABLED

true

开启监控指标

KC_CACHE

ispn

KC_CACHE_STACK

kubernetes

KC_PROXY

passthrough

KEYCLOAK_ADMIN

admin

初始admin账号

KEYCLOAK_ADMIN_PASSWORD

changeme

初始admin密码

KC_TRUSTSTORE_PATHS

/var/run/secrets/kubernetes.io/serviceaccount/ca.crt

用于访问 k8s 集群

部署:

$ kubectl apply -f keycloak.yaml -n dev

$ kgp -n dev

NAME READY STATUS RESTARTS AGE

keycloak-f6cff9b6c-lc6bj 1/1 Running 0 115s

keycloak-f6cff9b6c-nbm2w 1/1 Running 0 115s登录验证:

使用上面的指定端口 30008 进行访问

登录 MySQL 控制台可以看到初始化了很多表和基本数据:

登录成功后页面:

02 配置 Keycloak1)创建一个名为eric-realm的新Realm,Realm 在 Keycloak 中代表租户:

2)创建用户 eric:

3)设置用户密码:

Eric用户首次登录,因 Temporary 开启了,首次登录需要修改密码:

登录Keycloak的地址为https://${Keycloak 服务域名}/realms/${用户所在realm}/account。

这里我们需要登录:http://localhost:30008/realms/eric-realm/account

4)Client端配置:

Client为请求Keycloak对用户进行身份验证的客户端。用户设置完成后,需完成Client的设置。

设置Valid redirect URIs为http://* ,用于设置浏览器登录成功后有效的重定向URL,本例的http://* 表示匹配所有HTTP重定向的网址。然后单击Save。

5)添加 Client Scope:在多个客户端之间共享的一组通用协议Mapper和Role。

添加 client scope 到 client:

6)验证 Client 登录

以下命令需要替换成你的 keycloak 域名、realm 名称、用户名、用户密码、以及 client secret。

curl -ks -X POST http://localhost:30008/realms/eric-realm/protocol/openid-connect/token \

-d grant_type=password -d client_id=eric-client \

-d username=eric -d password=password -d scope=openid \

-d client_secret=WYK8RN2k5VQoARy87LnXpPi27h0cPCSP

成功后,可以获取到 access_token:

7)token 过期时长配置:

03 集成 Keycloak 和 自定义扩展配置好 keycloak 后,我们还要进行如下集成工作:

1、前端界面自定义一个符合企业的 SSO 界面,使用用户名和密码登录,请求上面keycloak提供的获取 access_token 接口

2、批量用户导入:之前看到如果一个新建,数据量大的话,简直。。。初步看有两种解决思路,通过 admin console 获取到 create user 的 api 接口和参数,通过代码批量进行创建;还有一种方式通过 MySQL 数据库直接导入;以上两种方式没有亲自做过,但是落地可行性应该没问题。

3、Two-factor 的支持:目前官网来看,只支持Google Authenticator 和 FreeOTP,需要额外进行定制。我简单查询了下,网络上已经有解决方案了,但是我本地没有发送短信、邮件的服务器,暂时无法验证,感兴趣的可以看下:https://github.com/dasniko/keycloak-2fa-sms-authenticator

4、多种密码策略的支持

总结使用 Keycloak 可以快速搭建起来一个 SSO 单点登录系统,同时基于 MySQL 进行数据的持久化,就算 k8s deployment 应用 crash 或者 强制将应用删除等,当我们重新启动应用时,数据还是可以通过 DB 进行加载,不会出现数据丢失的情况,同时使用 K8S 云原生技术,可以根据企业的用户体量和未来持续增长的数据量,进行动态的副本扩容,真正做到企业级高可用的 SSO 系统。

千万要切记,官方的 demo 不用用于生产环境!!!用于个人学习即可。

Keycloak 有非常多的有点,但个人认为会有如下几点不足:

1、终究使用的现有的工具,不一定满足企业对于安全的所有诉求,而且企业对于安全相关一般都是集团统一制定,需要严格遵守,这点非常重要。

2、扩展定制化有一定的技术门槛,需要阅读该平台的开源代码,从而进行代码扩展,然后打包成 Docker 镜像的等

往期文章推荐打造高效 K8S 本地环境

打造高效MacOS系统环境

kubernetes Ingress 自动化 HTTPS

参考资料什么是 SSO?- 单点登录简介 - AWS (amazon.com)

Keycloak 官网

Keycloak Github

Keycloak quickstart github

欢迎关注我的公众号“Eric技术圈”,原创技术文章第一时间推送。