今天,我们将深入了解 Keycloak,亲自动手进行自定义映射、扩展和集成。系好安全带,因为这次旅程将会非常刺激!
总结
我们将深入探讨 Keycloak 的自定义,包括:
- 自定义用户属性映射
- 构建 Keycloak 扩展(SPI)
- 实现自定义认证流程
- 与外部系统集成
如果你准备好将 Keycloak 变成你的个人认证游乐场,那就继续阅读吧!
自定义用户属性映射:因为一刀切并不适合所有人
说实话,Keycloak 中的默认用户属性就像香草冰淇淋一样无趣。但别担心!我们可以通过自定义属性映射来增加趣味性。
添加自定义属性
首先,让我们为用户添加一个自定义属性。在 Keycloak 管理控制台中:
- 导航到 用户 > 属性
- 添加一个新属性,比如 "favoriteProgLanguage"
现在,让我们将其映射到 JWT 令牌中的声明。前往 客户端 > [你的客户端] > 客户端范围 > 专用范围 > 添加映射器 > 通过配置 > 用户属性。
填写详细信息:
- 名称:Favorite Programming Language
- 用户属性:favoriteProgLanguage
- 令牌声明名称:fav_lang
完成!现在,当用户登录时,他们的 JWT 将包含他们最喜欢的编程语言。为什么不呢?
自定义协议映射器
但等等,还有更多!如果我们想在属性进入令牌之前进行一些高级处理呢?这时就需要自定义协议映射器。
让我们创建一个映射器,将我们最喜欢的语言转换为大写(因为大声表达我们对 Python 的热爱是完全正常的)。
public class UppercaseLanguageMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {
public static final String PROVIDER_ID = "uppercase-language-mapper";
@Override
public String getDisplayCategory() {
return TOKEN_MAPPER_CATEGORY;
}
@Override
public String getDisplayType() {
return "Uppercase Language Mapper";
}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
protected void setClaim(IDToken token, ProtocolMapperModel mappingModel, UserSessionModel userSession) {
UserModel user = userSession.getUser();
String favLang = user.getFirstAttribute("favoriteProgLanguage");
if (favLang != null) {
token.getOtherClaims().put("FAV_LANG", favLang.toUpperCase());
}
}
}
这就是我所说的自定义映射!你的最爱语言将从屋顶(或至少从你的 JWT)大声喊出。
Keycloak 扩展:因为有时候你需要打破规则
Keycloak 的可扩展性就像是认证爱好者的游乐场。让我们构建一个简单的 SPI(服务提供者接口),为认证流程添加自定义操作。
创建自定义认证器
想象一下,我们想要添加一个认证器来检查用户的密码是否包含他们的用户名(这是一个安全禁忌)。这是一个简化版本:
public class UsernamePasswordValidator implements Authenticator {
@Override
public void authenticate(AuthenticationFlowContext context) {
UserModel user = context.getUser();
CredentialInput input = context.getHttpRequest().getDecodedFormParameters().getFirst(CredentialForm.PASSWORD);
if (input.getValue().contains(user.getUsername())) {
context.failureChallenge(AuthenticationFlowError.INVALID_CREDENTIALS,
context.form().setError("passwordContainsUsername").createErrorPage());
return;
}
context.success();
}
// ... other required methods
}
现在,你需要在 Keycloak 中注册这个认证器并将其添加到你的认证流程中。你的用户稍后会感谢你(或者现在就诅咒你,这很难说)。
自定义认证逻辑:因为有时候你需要成为一个特别的存在
假设你的公司有一种超级秘密的认证方法,涉及一个魔法 8 球和一杯咖啡。别担心,Keycloak 会支持你!
实现自定义认证流程
以下是自定义认证流程可能的样子:
public class CoffeeAuthenticator implements Authenticator {
@Override
public void authenticate(AuthenticationFlowContext context) {
if (isCoffeeBrewed() && magicBallSaysYes()) {
context.success();
} else {
context.failureChallenge(AuthenticationFlowError.INVALID_CREDENTIALS,
context.form().setError("needMoreCoffee").createErrorPage());
}
}
private boolean isCoffeeBrewed() {
// 实现你的咖啡检查逻辑
return true; // 乐观主义者,团结起来!
}
private boolean magicBallSaysYes() {
// 咨询魔法 8 球
return Math.random() > 0.5; // 50/50 的机会,似乎很合理
}
// ... other required methods
}
记住,能力越大,责任越大。明智地使用这些知识,否则你可能会得到一个只在咖啡用完之前有效的认证系统。
与外部系统集成:与他人友好相处
Keycloak 不必是孤狼。让我们看看如何让它与外部系统友好相处。
自定义用户存储提供者
想象一下,你有用户数据存储在一个使用打孔卡的遗留系统中(因为为什么不呢?)。以下是如何将其与 Keycloak 集成的简化示例:
public class PunchCardUserStorageProvider implements UserStorageProvider, UserLookupProvider, CredentialInputValidator {
private PunchCardSystem punchCardSystem;
@Override
public UserModel getUserByUsername(String username, RealmModel realm) {
PunchCardUser punchCardUser = punchCardSystem.findUserByHoles(username);
if (punchCardUser != null) {
return new UserAdapter(session, realm, model, punchCardUser);
}
return null;
}
@Override
public boolean isValid(RealmModel realm, UserModel user, CredentialInput input) {
if (!supportsCredentialType(input.getType())) return false;
return punchCardSystem.validateCard(user.getUsername(), input.getChallengeResponse());
}
// ... other required methods
}
现在,你的复古打孔卡系统可以在 Keycloak 中认证用户。欢迎来到 21 世纪……某种程度上。
总结:Keycloak 是你的珍珠
我们只是触及了 Keycloak 自定义的表面。从调整用户属性到构建完整的认证提供者,Keycloak 提供了一个强大的平台,让你可以根据自己的心意定制认证系统。
记住,能力越大,责任越大(以及可能的头痛)。彻底测试,认真记录,愿认证之神永远眷顾你。
关键要点:
- 自定义属性映射让你的令牌更具特色
- SPI 打开了可扩展性的世界
- 自定义认证流程允许独特(且可能是咖啡驱动的)认证逻辑
- 即使是最古老的系统,也可以进行外部系统集成
现在去定制吧!记住,如果有人问你为什么花了一周时间实现一个基于咖啡的认证系统,就告诉他们这是为了“增强安全性”。他们一定会相信的。
“做伟大工作的唯一方法就是热爱你所做的事情。” - 史蒂夫·乔布斯
(他可能不是在谈论 Keycloak 自定义,但我们可以假装。)
编码愉快,愿你的令牌永远有效,咖啡永远浓郁!