java - 使用 WSS4J (SOAP) 在 CXF WebServices 中实现身份验证
问题描述
我正在尝试在我的网络服务中使用用户名/密码来实现身份验证。目前我学习了 CXF 以及如何配置东西,但是对于我的生活,我只是无法将我的头包裹在安全部分上。
我使用 CXF 从 WSDL 创建 Java 类。这是我的 Web 服务 XML 配置。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<jaxws:endpoint id="pacService" implementor="com.logicalprovisioning.internal.PacWS" address="/PacRequestSoapHttpPort">
<jaxws:properties>
<entry key="exceptionMessageCauseEnabled" value="true" />
<entry key="security.callback-handler" value="com.logicalprovisioning.webservices.clients.autheticate.AuthenticationCallback"/>
</jaxws:properties>
</jaxws:endpoint>
</beans>
我作为验证用户名密码的一部分添加的 AuthenticationCallback 条目。
我的 AutheitcationCallback 目前看起来像这样:
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
public class AuthenticationCallback {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
WSPasswordCallback wsPasswordCallback = (WSPasswordCallback) callbacks[0];
if (wsPasswordCallback.getIdentifier().equals("TIM")) {
wsPasswordCallback.setPassword("my_password");
}
}
}
现在是一个粗略的草案。
我编写了一个客户端,用于初始化 WebService(一个抽象类),并继承它以用于不同的 Web 服务。
public abstract class WebServiceClientBase implements HandlerResolver, SOAPHandler<SOAPMessageContext> {
protected int connectTimeout;
protected String endPointUrl;
protected String password;
protected String userName;
protected Logger logger = null;
private Service service = null;
public WebServiceClientBase () {
super();
}
public void init() {
// Set the security handler
getService().setHandlerResolver(new HandlerResolverImpl());
// Setting endpoint URL and timeout...
getBindingProvider().getRequestContext().put("javax.xml.ws.client.receiveTimeout", connectTimeout);
getBindingProvider().getRequestContext().put("javax.xml.ws.client.connectionTimeout", connectTimeout);
getBindingProvider().getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endPointUrl);
Map<String, List<String>> headers = new HashMap<String, List<String>>();
headers.put("Content-Type", Collections.singletonList("application/soap+xml"));
headers.put(Message.ENCODING, Collections.singletonList("UTF-8"));
getBindingProvider().getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, headers);
}
@Override
@SuppressWarnings("rawtypes")
public List<Handler> getHandlerChain(PortInfo arg0) {
List<Handler> handlerChain = new ArrayList<Handler>();
handlerChain.add(this);
return handlerChain;
}
@Override
public boolean handleMessage(SOAPMessageContext soapMessageContext) {
if (!((Boolean) soapMessageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)). booleanValue()) {
return true;
}
return true;
}
@Override
public boolean handleFault(SOAPMessageContext arg0) {
return false;
}
@Override
public void close(MessageContext arg0) {
}
@Override
public Set<QName> getHeaders() {
return null;
}
protected Service getService() {
return service;
}
protected void setService(Service service) {
this.service = service;
}
protected abstract BindingProvider getBindingProvider();
}
这就是我已经走了多远。我不确定如何将身份验证信息与 Web 服务调用连接起来。
任何指针都会有所帮助。我也是在正确的轨道上开始吗?通过查看所有教程和示例,我可能会陷入死胡同。
解决方案
假设 com.logicalprovisioning.internal.PacWS 是你的 jaxws 生成的 PortType 类,你可以做这样的事情......
...
com.logicalprovisioning.internal.PacWS pacWsPort = getService().get...Port();
org.apache.cxf.endpoint.Client client = org.apache.cxf.frontend.ClientProxy.getClient(pacWSPort);
org.apache.cxf.endpoint.Endpoint endpoint = client.getEndpoint();
Map<String, Object> props = new HashMap<>();
props.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
props.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
props.put(WSHandlerConstants.PW_CALLBACK_CLASS, AuthenticationCallback.class.getName());
props.put(WSHandlerConstants.USER, "TIM");
WSS4JOutInterceptor wssOut = new WSS4JOutInterceptor(props);
endpoint.getOutInterceptors().add(wssOut);
// you can then call @WebMethod annotated methods on your PacWS object, and it should populate the wss-security soap header
上面的部分代码大概可以用cxf xml配置文件中的配置代替
推荐阅读
- angular - 不同设备上的 Ionic 5 响应行
- r - 在 R 中将数值组合为数据框以运行 EstCRM
- python - 如果在字符串中找到 sin( 或 cos( 或 tan( ),如何附加弧度?
- python - Javascript ID 未显示对输入文本框的引用 - Django
- ruby-on-rails - 如何根据用户在活动管理员中的角色显示范围?
- excel - 无法在 Windows Docker 容器中安装 Excel - 错误 17002
- php - 显示昨天和旧 30 天而不是日期 laravel
- jquery - jQuery 上的选项卡内容
- emscripten - 在 Emscripten 中,通过活动循环等待生成的线程失败。我该如何修改它?
- javascript - Wicket Ajax 适用于 Firefox 和 IE,但不适用于 Chrome 和 Safari