
智能語(yǔ)音新革命:有道與Azure的API服務(wù)對(duì)決
假設(shè)一個(gè)系統(tǒng)由兩個(gè)服務(wù)組成:
用戶注冊(cè)后將獲得一個(gè) API 密鑰,用于訪問(wèn)天氣 REST API。系統(tǒng)還包含 Keycloak 身份驗(yàn)證服務(wù)器:
為實(shí)現(xiàn)該場(chǎng)景,需要擴(kuò)展 Keycloak 模塊,實(shí)現(xiàn):
Keycloak 支持通過(guò) SPI 接口或覆蓋提供者擴(kuò)展功能。我們通過(guò)實(shí)現(xiàn) EventListenerProvider
捕獲用戶注冊(cè)事件,并生成 API 密鑰。
核心實(shí)現(xiàn)示例:
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)) {
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() {
// 清理資源
}
}
提供者工廠類(lèi)實(shí)現(xiàn):
public class RegisterEventListenerProviderFactory implements EventListenerProviderFactory {
public EventListenerProvider create(KeycloakSession session) {
return new RegisterEventListenerProvider(session);
}
public String getId() {
return "api-key-registration-generator";
}
}
創(chuàng)建端點(diǎn)用于驗(yàn)證 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 識(shí)別該端點(diǎn),需要實(shí)現(xiàn) RealmResourceProvider
和工廠類(lèi):
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";
}
}
在 META-INF/services
目錄下添加映射文件:
org.keycloak.events.EventListenerProviderFactory
com.gwidgets.providers.RegisterEventListenerProviderFactory
org.keycloak.services.resource.RealmResourceProviderFactory
com.gwidgets.providers.ApiKeyResourceProviderFactory
Keycloak 允許通過(guò) .jar
或 .ear
文件安裝模塊到 standalone/deployments
目錄。示例項(xiàng)目結(jié)構(gòu):
api-key-ear/
api-key-module/
pom.xml
使用正確的 API 密鑰訪問(wèn) REST API:
curl -H "X-API-KEY: YPqIeqhbxUcOgDd6ld2jl9txfDrHxAPme89WLMuC8e0oaYXeA7" https://[CNAME]
響應(yīng)示例:
{
"forecast": "今天天氣涼爽"
}
錯(cuò)誤密鑰返回 401 未授權(quán):
curl -v -H "X-API-KEY: invalid-key" https://[CNAME]
通過(guò)擴(kuò)展 Keycloak,我們可以:
這種方式簡(jiǎn)單高效,非常適合希望保護(hù) API 的微服務(wù)系統(tǒng)。
Adding API Key Authentication in Keycloak
智能語(yǔ)音新革命:有道與Azure的API服務(wù)對(duì)決
vue3?使用?高德地圖api
用ASP.NET Core 給你的API接口打造一個(gè)自定義認(rèn)證授體系
REST API與WebSocket API區(qū)別?
獲取 YouTube API Key 密鑰的教程與示例
Python人工智能學(xué)習(xí)路線(長(zhǎng)篇干貨)
用花粉季節(jié)查詢api提高生活質(zhì)量:Ambee的季節(jié)性追蹤功能
如何在Python中使用免費(fèi)的DeepL翻譯API
如何使用Java Spring Boot構(gòu)建REST API
對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力
一鍵對(duì)比試用API 限時(shí)免費(fèi)