keycloak/standalone/configuration/standalone.xml
在 KeyCLoak 15.0 (即 WildFly 23.0)中,我 嘗試將存取日誌配置為在使用者登入時也包含使用者名稱(或使用者的任何 ID)。XML:/server/profile/subsystem[@xmlns="urn:jboss:domain:undertow:12.0"]/server/host/access-log/@pattern
pattern="%h %l %u %t "%r" %s/%S %b %T %I "%{i,User-Agent}""
日誌正確列印在我配置的文件中。但是, %u
or的值%{REMOTE_USER}
始終為空(即-
)。
我發現記錄某些使用者 ID 的唯一方法是使用%{c,KEYCLOAK_SESSION}
(它包含realm/user-ID/secret
)來記錄會話 cookie 值。這在生產中並不是一個好主意。
關於如何在存取日誌中記錄使用者名稱或使用者 ID 的任何想法嗎?
即使 KeyCloak 中存在活動使用者會話,它%u
還是空的還是KeyCLoak 錯誤?%{REMOTE_USER}
或者是否可以在 KeyCLoak 中配置哪個使用者屬性值進入REMOTE_USER
?
另類地,如何將 userID 放入某些標頭中以使用以下其中一項?
%{i,xxx}
對於傳入標頭%{o,xxx}
用於傳出響應標頭%{c,xxx}
對於特定的cookie%{r,xxx}
其中 xxx 是 ServletRequest 中的屬性%{s,xxx}
其中 xxx 是 HttpSession 中的屬性
其中,我嘗試過這些。他們都無人居住。
%{s,user}
%{s,userId}
%{s,client_id}
%{s,USER_ID}
%{s,USER}
%{s,org.keycloak.adapters.spi.KeycloakAccount}
%{s,KeycloakAccount}
%{s,org.keycloak.adapters.tomcat.CatalinaSessionTokenStore.SerializableKeycloakAccount}
%{s,SerializableKeycloakAccount}
%{s,org.keycloak.adapters.saml.SamlSession}
%{s,SamlSession}
%{s,org.keycloak.adapters.undertow.KeycloakUndertowAccount}
%{s,KeycloakUndertowAccount}
%{s,org.keycloak.KeycloakSecurityContext}
%{s,KeycloakSecurityContext}
%{s,io.undertow.servlet.util.SavedRequest}
%{s,SavedRequest}
%{r,tokenInfo}
%{r,KeycloakSecurityContext}
%{r,ElytronHttpFacade}
%{r,AdapterDeploymentContext}
%{r,TOKEN_STORE_NOTE}
答案1
我遇到了類似的問題(我的客戶要求我記錄客戶 ID)並最終尋找解決方案。透過查看原始程式碼以及存取日誌的填充方式,我可以告訴您日誌的形成位置和實際工作完成位置之間存在相當大的差距。
如果您查看過 Keycloak,它是基於 Wildfly,它使用 Undertow 來託管 http 伺服器功能。雖然一旦請求得到服務就會發出存取日誌條目,但幾乎沒有間隙和抽象,這使得事情變得複雜。
從軟體角度來看,有 undertow 處理程序,然後是 servlet,然後是 Resteasy Servlet,然後是 keycloak 應用程式和特定資源。當您使用 Keycloak 使用者或管理控制台時,在大多數地方它是一個由 Web 瀏覽器呈現的「瘦」用戶端。並且該瀏覽器調用剩餘資源。
如果您希望經常獲取用戶相關信息,則在會話中找不到該信息,因為 Kecloak 所做的大部分工作是代表用戶發行令牌。正式地,發送請求的客戶端代表用戶進行操作,這意味著它不是每個傳入請求可用的顯式訊息。此外,根據定義,大多數剩餘資源都是無狀態的,這意味著它們確實以某種方式與使用者一起操作,但不會過多填充會話。只有當使用者實際登入並在使用者帳戶控制台中執行某些操作時,您才可以依賴存取使用者資訊。除此之外,它可能會失敗,因為在大多數情況下發行令牌的 keycloak 資源將處理客戶端或客戶端相關的會話。
說到這一點-我來到了我所在的位置進行訪問日誌格式解析。它基於 UndertowExchangeAttribute
思想,允許您使用自己的日誌巨集。此巨集可用於遍歷記憶體結構以取得必要的資訊。對我來說,這是一個 client_id 正在做的工作。為此,我最終實現了FormAttribute
.我仍然需要找到一種方法來連接它,但從單元測試的角度來看,它已經「點擊」了,看看基本程式碼是怎樣的:
package org.code_house.wildfly.stuff.undertow.attributes;
// remember to create META-INF/services/io.undertow.attribute.ExchangeAttributeBuilder
// with line containing class name, ie.
// org.code_house.wildfly.stuff.undertow.attributes.FormAttribute$Builder
/**
* Expose form parameters within exchange attributes which can be logged in access log.
* Use %{F,*} to dump all params or %{F,client_id} to render selected from field.
*
* @author Łukasz Dywicki @ code-house.org
**/
public class FormAttribute implements ExchangeAttribute {
private final String paramName;
public FormAttribute(String paramName) {
this.paramName = paramName;
}
@Override
public String readAttribute(HttpServerExchange exchange) {
FormData formData = exchange.getAttachment(FormDataParser.FORM_DATA);
if ("*".equals(paramName)) {
return "" + formData;
}
return formData == null ? "" : "" + formData.get(paramName);
}
@Override
public void writeAttribute(HttpServerExchange exchange, String newValue) throws ReadOnlyAttributeException {
throw new ReadOnlyAttributeException("Form", newValue);
}
public static final class Builder implements ExchangeAttributeBuilder {
@Override
public String name() {
return "form";
}
@Override
public ExchangeAttribute build(final String token) {
if (token.startsWith("%{F,") && token.endsWith("}")) {
final String paramName = token.substring(4, token.length() - 1);
return new FormAttribute(paramName);
}
return null;
}
@Override
public int priority() {
return 0;
}
}
}
重點 - 透過使用表單屬性記錄在登入表單的“使用者名稱”欄位中輸入的值來獲取“誰”,然後您可以將其與瀏覽器保留的會話 cookie 結合。透過以上兩個王牌的基本合併,您可以獲得必要的結果。使用上面的藍圖,您可以實現自己的東西並追蹤令牌和其他東西,這將讓您建立您的應用程式。
當我找到一個黏合邏輯來正確地將日誌格式的附加屬性注入到 undertow 中時,我可能會更新答案。編輯:到目前為止,我發現注入額外屬性的唯一一種方法是將它們複製到此目錄中$JBOSS_HOME/modules/system/layers/base/org/wildfly/extension/undertow/main/
並在其中更新:module.xml
<module name="org.wildfly.extension.undertow" xmlns="urn:jboss:module:1.5">
...
<resources>
<resource-root path="wildfly-undertow-20.0.1.Final.jar"/>
<!-- put here name of jar you made -->
<resource-root path="undertow-client-request-filter-1.0.0-SNAPSHOT.jar"/>
</resources>
...
</module>