第4章:企业级SSO方案
Keycloak实战
安装Keycloak
Docker安装:
# 1. 启动Keycloak
docker run -d \
--name keycloak \
-p 8080:8080 \
-e KEYCLOAK_ADMIN=admin \
-e KEYCLOAK_ADMIN_PASSWORD=admin \
quay.io/keycloak/keycloak:latest start-dev
# 2. 访问管理界面
# http://localhost:8080
# 用户名:admin
# 密码:admin
生产环境安装:
# docker-compose.yml
version: '3'
services:
postgres:
image: postgres:15
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
keycloak:
image: quay.io/keycloak/keycloak:latest
command: start
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: password
KC_HOSTNAME: sso.example.com
KEYCLOAK_ADMIN: admin
KEYCLOAK_ADMIN_PASSWORD: admin
ports:
- 8080:8080
depends_on:
- postgres
volumes:
postgres_data:
Realm配置
创建Realm:
1. 登录Keycloak管理界面
2. 点击左上角Realm下拉框 → Create Realm
3. Realm name: mycompany
4. 点击Create
配置客户端:
1. Clients → Create Client
2. Client ID: myapp
3. Client Protocol: openid-connect
4. Root URL: http://localhost:3000
5. Valid redirect URIs: http://localhost:3000/*
6. Web origins: http://localhost:3000
7. Save
Go客户端集成Keycloak
package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
"github.com/coreos/go-oidc/v3/oidc"
"golang.org/x/oauth2"
)
var (
clientID = "myapp"
clientSecret = "your-client-secret"
redirectURL = "http://localhost:8080/callback"
keycloakURL = "http://localhost:8080/realms/mycompany"
)
func main() {
ctx := context.Background()
// 配置OIDC Provider
provider, _ := oidc.NewProvider(ctx, keycloakURL)
// 配置OAuth2
oauth2Config := oauth2.Config{
ClientID: clientID,
ClientSecret: clientSecret,
RedirectURL: redirectURL,
Endpoint: provider.Endpoint(),
Scopes: []string{oidc.ScopeOpenID, "profile", "email"},
}
// OIDC验证器
verifier := provider.Verifier(&oidc.Config{ClientID: clientID})
// 登录
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
url := oauth2Config.AuthCodeURL("state")
http.Redirect(w, r, url, http.StatusFound)
})
// 回调
http.HandleFunc("/callback", func(w http.ResponseWriter, r *http.Request) {
// 交换code
oauth2Token, _ := oauth2Config.Exchange(ctx, r.URL.Query().Get("code"))
// 验证ID Token
rawIDToken, _ := oauth2Token.Extra("id_token").(string)
idToken, _ := verifier.Verify(ctx, rawIDToken)
// 解析用户信息
var claims struct {
Email string `json:"email"`
Name string `json:"name"`
}
idToken.Claims(&claims)
fmt.Fprintf(w, "Welcome, %s (%s)!", claims.Name, claims.Email)
})
http.ListenAndServe(":8080", nil)
}
用户联邦
LDAP集成
配置LDAP:
1. Keycloak → User Federation → Add provider → ldap
2. Edit Mode: READ_ONLY
3. Vendor: Active Directory
4. Connection URL: ldap://ldap.example.com:389
5. Users DN: ou=Users,dc=example,dc=com
6. Bind DN: cn=admin,dc=example,dc=com
7. Bind Credential: admin_password
8. Test connection
9. Save
同步LDAP用户:
User Federation → ldap → Synchronize all users
社交登录
配置GitHub登录:
1. Identity Providers → Add provider → GitHub
2. Redirect URI: 复制URL
3. 在GitHub创建OAuth App
- Homepage URL: http://localhost:8080
- Authorization callback URL: (粘贴上面的Redirect URI)
4. 获取Client ID和Client Secret
5. 填入Keycloak配置
6. Save
配置Google登录:
1. Identity Providers → Add provider → Google
2. 在Google Cloud Console创建OAuth 2.0客户端
3. 获取Client ID和Client Secret
4. 填入Keycloak
5. Save
多因素认证
配置OTP(Google Authenticator)
启用OTP:
1. Realm → Authentication → Flows
2. Browser → Actions → Duplicate
3. 命名:Browser with OTP
4. OTP Form → Requirement: REQUIRED
5. Bindings → Browser Flow: Browser with OTP
6. Save
用户使用OTP:
1. 用户登录后访问 Account Console
2. Signing In → Two-factor Authentication → Setup Authenticator
3. 扫描二维码(使用Google Authenticator)
4. 输入验证码验证
5. 下次登录需要输入密码 + OTP
WebAuthn(无密码认证)
1. Authentication → Required Actions
2. Webauthn Register → Enabled
3. 用户首次登录时会被要求注册硬件密钥
4. 后续可使用指纹/Face ID登录
企业SSO选型
主流方案对比
| 维度 | Keycloak | Auth0 | Okta | CAS |
|---|---|---|---|---|
| 类型 | 开源 | 商业(SaaS) | 商业(SaaS) | 开源 |
| 部署 | 自托管 | 云端 | 云端 | 自托管 |
| 价格 | 免费 | 付费 | 付费 | 免费 |
| 易用性 | ||||
| 功能 | 丰富 | 非常丰富 | 非常丰富 | 基础 |
| 社交登录 | ||||
| MFA | ||||
| LDAP | ||||
| 适用 | 中大型企业 | 初创公司 | 大型企业 | 传统企业 |
选型建议
选择Keycloak:
需要自托管
预算有限
技术团队强
功能要求高
支持OAuth/OIDC/SAML
选择Auth0:
快速上线
SaaS服务
技术团队小
社交登录需求多
选择Okta:
大型企业
合规要求高
预算充足
需要企业支持
选择CAS:
传统企业
简单SSO需求
Java技术栈
面试问答
Keycloak和CAS有什么区别?
答案:
| 维度 | Keycloak | CAS |
|---|---|---|
| 协议支持 | OAuth 2.0, OIDC, SAML | CAS协议 |
| 功能 | 丰富(MFA、社交登录、LDAP) | 基础(SSO) |
| 易用性 | Web UI配置 | XML配置 |
| 社区 | 活跃 | 较少 |
| 适用 | 现代应用 | 传统应用 |