在Keycloak中添加API密钥认证 - Elestio博客
背景
API密钥身份验证是确保访问资源和API最直接的方法之一。这种方法通过提供一个静态密钥来实现,该密钥需要妥善保管,并用于访问受保护的API,通常通过特定的请求头或身份验证头传递。如果您正在使用 Keycloak 并希望结合 API 密钥验证机制,请继续阅读。本指南将演示如何通过添加简单的 API 密钥认证机制来扩展 Keycloak。这种方法特别适合微服务架构,因为不同服务可能需要不同的认证方式。
设计
假设一个由两个服务组成的系统:一个是提供仪表板页面的 Spring Boot 应用程序,另一个是提供天气预报数据的无状态 Node.js REST API。这两个服务通过不同的 URI 独立访问,但需要通过仪表板注册后才能使用。用户注册后会获得一个 API 密钥,该密钥用于访问天气 REST API。这种场景在 API 即服务(API-as-a-Service)应用中非常常见。
此外,该系统还包含一个 Keycloak 身份验证服务器,用于身份验证和授权。为了保护仪表板服务,我们采用了 Keycloak 的单点登录(SSO)机制。而为了保护 REST API 服务,我们引入了 API 密钥认证机制:在用户注册时生成并存储一个随机密钥,并提供一个端点用于验证 API 密钥的有效性。
为实现上述目标,我们扩展了 Keycloak 模块,新增以下功能:
- 在用户注册过程中生成随机密钥并存储为用户属性。
- 提供一个端点,用于验证 API 密钥的有效性。
实施
密钥生成
Keycloak 的可扩展性允许通过 SPI 接口或覆盖提供者来轻松实现新功能。我们首先从 API 密钥生成开始,这需要捕获用户注册事件以生成密钥。通过实现 EventListenerProvider,可以捕获 Keycloak 的内部事件并执行相应操作。
以下是实现代码的核心部分:
public class RegisterEventListenerProvider implements EventListenerProvider {
private KeycloakSession session;
private RealmProvider model;
private RandomString randomString;
private EntityManager entityManager;
public RegisterEventListenerProvider(KeycloakSession session) {
this.session = session;
this.model = session.realms();
this.entityManager = session.getProvider(JpaConnectionProvider.class).getEntityManager();
this.randomString = new RandomString(50);
} public void onEvent(Event event) {
if (event.getType().equals(EventType.REGISTER)) {
RealmModel realmModel = model.getRealm(event.getRealmId());
String userId = event.getUserId();
addApiKeyAttribute(userId);
}
} public void addApiKeyAttribute(String userId) {
String apiKey = randomString.nextString();
UserEntity userEntity = entityManager.find(UserEntity.class, userId);
UserAttributeEntity attributeEntity = new UserAttributeEntity();
attributeEntity.setName("apiKey");
attributeEntity.setValue(apiKey);
attributeEntity.setId(UUID.randomUUID().toString());
entityManager.persist(attributeEntity);
} public void close() {
// 清理资源
}
}
在 Keycloak 中,每个提供者都需要一个工厂类来创建实例。以下是 EventListenerProviderFactory 的实现:
public class RegisterEventListenerProviderFactory implements EventListenerProviderFactory {
public EventListenerProvider create(KeycloakSession session) {
return new RegisterEventListenerProvider(session);
}
public String getId() {
return "api-key-registration-generator";
}
}
API 密钥验证端点
接下来,我们创建一个端点,用于验证 API 密钥是否有效:
public class ApiKeyResource {
private KeycloakSession session;
public ApiKeyResource(KeycloakSession session) {
this.session = session;
} @GET
@Produces("application/json")
public Response checkApiKey(@QueryParam("apiKey") String apiKey) {
List result = session.userStorageManager()
.searchForUserByUserAttribute("apiKey", apiKey, session.realms().getRealm("example"));
return result.isEmpty() ? Response.status(401).build() : Response.ok().build();
}
}
为了让 Keycloak 识别我们的端点,我们需要实现 RealmResourceProvider 和 RealmResourceProviderFactory:
public class ApiKeyResourceProvider implements RealmResourceProvider {
private KeycloakSession session;
public ApiKeyResourceProvider(KeycloakSession session) {
this.session = session;
} public Object getResource() {
return new ApiKeyResource(session);
} public void close() {
// 清理资源
}
}public class ApiKeyResourceProviderFactory implements RealmResourceProviderFactory {
public RealmResourceProvider create(KeycloakSession session) {
return new ApiKeyResourceProvider(session);
} public String getId() {
return "api-key-resource-provider";
}
}
提供者配置
为了让 Keycloak 知道我们新增的提供者,需要在 META-INF/services 目录下创建以下映射文件:
-
文件名:org.keycloak.events.EventListenerProviderFactory
com.gwidgets.providers.RegisterEventListenerProviderFactory -
文件名:org.keycloak.services.resource.RealmResourceProviderFactory
com.gwidgets.providers.ApiKeyResourceProviderFactory
模块打包
Keycloak 是一个运行在 Wildfly 上的独立 Web 应用程序,允许通过 .ear 或 .jar 文件将模块安装到 standalone/deployments 目录下。以下是项目结构示例:
api-key-ear/
api-key-module/
pom.xml
更多详细信息请参考 Keycloak 官方文档。
测试 API 密钥
使用正确的 API 密钥调用 REST API 服务:
curl -H "X-API-KEY: YPqIeqhbxUcOgDd6ld2jl9txfDrHxAPme89WLMuC8e0oaYXeA7" https://[CNAME]
响应示例:
{
"forecast": "今天天气凉爽"
}
使用错误的 API 密钥会返回 401 未授权响应:
curl -v -H "X-API-KEY: invalid-key" https://[CNAME]
总结
通过扩展 Keycloak,我们可以轻松实现 API 密钥认证机制,为微服务架构中的 REST API 提供额外的安全层。这种方法不仅灵活,还能与 Keycloak 的现有功能无缝集成。如果您正在寻找一种简单而高效的方式来保护 API,不妨尝试本文介绍的实现方法。
原文链接: https://blog.elest.io/adding-api-key-authentication-in-keycloak/
热门API
- 1. AI文本生成
- 2. AI图片生成_文生图
- 3. AI图片生成_图生图
- 4. AI图像编辑
- 5. AI视频生成_文生视频
- 6. AI视频生成_图生视频
- 7. AI语音合成_文生语音
- 8. AI文本生成(中国)