[英]CXF Logging request & response with content filtering or masking soap fields
我想记录来自某个特定端点的所有传入请求和响应,并进行内容过滤。 即当我有这样的要求时:
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope">
<soap:Body>
<m:ProcessPhoto xmlns:m="http://www.w3schools.com/photos">
<m:Name>Apples</m:Name>
<m:Description>Photo with some apples in it</m:Description>
<!-- large encoded binary below -->
<m:Photo>anVzdCBhIHJhbmRvbSB0ZXh0DQpqdXN0IGEgcmFuZG9tIHRleHQNCmp1c3QgYSByYW5kb20gdGV4dA0KanVzdCBhIHJhbmRvbSB0ZXh0DQpqdXN0IGEgcmFuZG9tIHRleHQNCmp1c3QgYSByYW5kb20gdGV4dA0KanVzdCBhIHJhbmRvbSB0ZXh0DQp3b3csIGkgZGlkbid0IHRob3VnaHQgdGhhdCBhbnlvbmUgd291bGQgYmUgaW50ZXJlc3RlZCBpbiBkZWNvZGluZyB0aGlzLiBjb25ncmF0cyE=</m:Photo>
</m:ProcessPhoto>
</soap:Body>
</soap:Envelope>
我想过滤它,以便它看起来像这样的日志
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope">
<soap:Body>
<m:ProcessPhoto xmlns:m="http://www.w3schools.com/photos">
<m:Name>Apples</m:Name>
<m:Description>Photo with some apples in it</m:Description>
<m:Photo>hidden</m:Photo>
</m:ProcessPhoto>
</soap:Body>
</soap:Envelope>
或完全删除了m:Photo元素。
我发现CXF有一些LoggingInInterceptor和LoggingOutInterceptor,我可以编写自己的拦截器来做到这一点。 但是,这需要做一些工作,所以我的问题是:您知道什么更好的即用型解决方案吗?
我遇到了类似的问题,需要在输入请求中屏蔽密码。 我对现有的LogginInterceptor和覆盖的格式方法做了一些小的更改,并添加了我的方法来屏蔽密码。 这是一个例子
public class CustomLogInInterceptor extends LoggingInInterceptor {
@Override
protected String formatLoggingMessage(LoggingMessage loggingMessage) {
String str = loggingMessage.toString();
String output = maskPasswords(str);
return(output);
}
private String maskPasswords(String str) {
final String[] keys = { "password", "passwords" };
for (String key : keys) {
int beginIndex = 0;
int lastIndex = -1;
boolean emptyPass = false;
while (beginIndex != -1
&& (beginIndex = StringUtils.indexOfIgnoreCase(str, key,
beginIndex)) > 0) {
beginIndex = StringUtils.indexOf(str, ">", beginIndex);
if (beginIndex != -1) {
char ch = str.charAt(beginIndex - 1);
if (ch == '/') {
emptyPass = true;
}
if (!emptyPass) {
lastIndex = StringUtils.indexOf(str, "<", beginIndex);
if (lastIndex != -1) {
String overlay = "*";
String str2 = StringUtils.substring(str,
beginIndex + 1, lastIndex);
if (str2 != null && str2.length() > 1) {
overlay = StringUtils.rightPad(overlay,
str2.length(), "*");
str = StringUtils.overlay(str, overlay,
beginIndex + 1, lastIndex);
}
}
}
if (emptyPass) {
emptyPass = false;
lastIndex = beginIndex + 1;
} else {
if (lastIndex != -1) {
lastIndex = StringUtils
.indexOf(str, ">", lastIndex);
}
}
}
beginIndex = lastIndex;
}
}
return str;
}
}
并在我的cxf-bean.xml中添加了custtom cxf日志记录bean
<bean id="kpInInterceptor" class="com.kp.util.CustomLogInInterceptor" />
<cxf:bus>
<cxf:inInterceptors>
<ref bean="kpInInterceptor" />
</cxf:inInterceptors>
<cxf:inFaultInterceptors>
<ref bean="kpInInterceptor" />
</cxf:inFaultInterceptors>
</cxf:bus>
注意我已经使用Apache commons-lang3 jar进行String操作。 同样,您也可以将其用于响应
使用模式,并使用属性使键可配置。
拦截器
public class CustomLogInInterceptor extends LoggingInInterceptor {
private static final String MASK_PATTERN = "<\\s*{}\\s*>(.*)</\\s*{}\\s*>|<\\s*name\\s*>\\s*{}\\s*</\\s*name\\s*>\\s*<\\s*value\\s*>(.*)<";
private Pattern pattern;
private String[] keys;
public void init() {
StringBuilder builder = new StringBuilder();
for (String str : keys) {
builder.append(MASK_PATTERN.replace("{}", str));
builder.append("|");
}
builder.setLength(builder.length()-1);
pattern = Pattern.compile(builder.toString(), Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
}
public void setKeys(String[] keys) {
this.keys = keys;
}
@Override
protected String formatLoggingMessage(LoggingMessage loggingMessage) {
String output = maskPasswords(loggingMessage.toString());
return(output);
}
private String maskPasswords(String str) {
Matcher matcher = pattern.matcher(str);
final StringBuilder builder = new StringBuilder(str);
while (matcher.find()) {
int group = 1;
while (group <= matcher.groupCount()) {
if (matcher.group(group) != null) {
for (int i = matcher.start(group); i < matcher.end(group); i++) {
builder.setCharAt(i, '*');
}
}
group++;
}
}
return builder.toString();
}
}
豆创作
<bean id="kpInInterceptor" class="com.kp.util.CustomLogInInterceptor" init-method="init">
<property name="keys">
<array value-type="java.lang.String">
<value>password</value>
<value>accountId</value>
</array>
</property>
</bean>
样本输入
<?xml version="1.0" encoding="UTF-8"?>
<test>
<hello>adffas</hello>
<vsdsd>dfsdf</vsdsd>
<password>sdfsfs</password>
<sdfsfsf>sdfsfsf</sdfsfsf>
<password>3434</password>
<name>password</name>
<value>sdfsfs</value>
<password />
<name>password</name>
<value />
<accountId>123456</accountId>
<hello>
<inner1>
<password>
<password>sdfsfs</password>
</password>
</inner>
</hello>
</test>
和输出
<?xml version="1.0" encoding="UTF-8"?>
<test>
<hello>adffas</hello>
<vsdsd>dfsdf</vsdsd>
<password>******</password>
<sdfsfsf>sdfsfsf</sdfsfsf>
<password>****</password>
<name>password</name>
<value>******</value>
<password />
<name>password</name>
<value />
<accountId>******</accountId>
<hello>
<inner1>
<password>
<password>******</password>
</password>
</inner>
</hello>
</test>
我已经编写了一个旨在有效打印漂亮的SOAP消息的开源库: xml-formatter-components-cxf 。 功能包括:
编辑:上面的库已经重构为一个更通用的库 ,对于大多数普通用例来说可能更好,即没有XML封装在XML中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.