最近在搞webservice+cxf 安全问题
遇到了这样的问题,就是服务端和客户端使用WSHandlerConstants.USERNAME_TOKEN和WSConstants.PW_TEXT 明文校验安全认证,客户端调服务端是没有问题,正常调用能返回值。
但是,如果客户端和服务端采用WSConstants.PW_DIGEST密码类型为加密时就会报错。
求解!!!!!!!!!!!!!!!!
springboot 服务端配置类
@Configuration
public class WebServiceConfig {
@Autowired
private Bus bus;
@Autowired
CommonService service;
@Autowired
AuthInterceptor authinterceptor;
/*jax-ws*/
@Bean
public Endpoint endpoint() {
EndpointImpl endpoint = new EndpointImpl(bus, service);
// endpoint.getInInterceptors().add(authinterceptor);//添加校验拦截器
endpoint.getInInterceptors().add(new LoggingInInterceptor());
endpoint.getInInterceptors().add(new LoggingOutInterceptor());
Map<String, Object> inProps = new HashMap<String, Object>();
inProps.put(WSHandlerConstants.USER, "admin");
inProps.put(WSHandlerConstants.ACTION,WSHandlerConstants.USERNAME_TOKEN);//设置加密类型
inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST); //设置密码类型为加密
inProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,
ExampleServiceInterceptor.class.getName()); //密码回调函数
endpoint.getInInterceptors().add( new SAAJInInterceptor());
endpoint.getInInterceptors().add(new WSS4JInInterceptor(inProps));
endpoint.publish("/CommonService");
return endpoint;
}
}
服务端密码回调函数
public class ExampleServiceInterceptor implements CallbackHandler{
private Map<String, String> passwords = new HashMap<String, String>();
public ExampleServiceInterceptor() {
passwords.put("admin", "password");//此处的对应的是验证信息-用户名+密码,必须与客户端一致才可验证通过
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
String identifier = pc.getIdentifier();//用户名
int usage = pc.getUsage();//验证方式
if (usage == WSPasswordCallback.USERNAME_TOKEN) {// 密钥方式USERNAME_TOKEN
// username token pwd...
// ▲这里的值必须和客户端设的值相同,从cxf2.4.x后校验方式改为cxf内部实现校验,不必自己比较password是否相同
// 请参考:http://cxf.apache.org/docs/24-migration-guide.html的Runtime
// Changes片段
pc.setPassword(passwords.get(identifier));// ▲【这里非常重要】▲
// ▲PS 如果和客户端不同将抛出org.apache.ws.security.WSSecurityException:
// The
// security token could not be authenticated or
// authorized异常,服务端会认为客户端为非法调用
}else if (usage == WSPasswordCallback.SIGNATURE) {// 密钥方式SIGNATURE
// set the password for client's keystore.keyPassword
// ▲这里的值必须和客户端设的值相同,从cxf2.4.x后校验方式改为cxf内部实现校验,不必自己比较password是否相同;
// 请参考:http://cxf.apache.org/docs/24-migration-guide.html的Runtime
// Changes片段
pc.setPassword(passwords.get(identifier));// //▲【这里非常重要】▲
// ▲PS:如果和客户端不同将抛出org.apache.ws.security.WSSecurityException:The
// security token could not be authenticated or
// authorized异常,服务端会认为客户端为非法调用
}
}
}
}
客户端调用类
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
import org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor;
import org.apache.wss4j.dom.WSConstants;
import org.apache.wss4j.dom.handler.WSHandlerConstants;
public class webserviceclient {
//动态调用
public static void main(String[] args) throws Exception {
JaxWsDynamicClientFactory dcflient=JaxWsDynamicClientFactory.newInstance();
Client client=dcflient.createClient("http://localhost:8080/services/CommonService?wsdl");
//client.getOutInterceptors().add(new LoginInterceptor("root","admin"));
Map<String, Object> outProps = new HashMap<String, Object>();
outProps.put(WSHandlerConstants.ACTION,
WSHandlerConstants.USERNAME_TOKEN);
outProps.put(WSHandlerConstants.USER, "admin");
outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);
// 指定在调用远程ws之前触发的回调函数WsClinetAuthHandler,其实类似于一个拦截器
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,
ExampleServiceClientInterceptor.class.getName());
ArrayList list = new ArrayList();
// 添加cxf安全验证拦截器,必须
list.add(new SAAJOutInterceptor());
list.add(new WSS4JOutInterceptor(outProps));
client.getOutInterceptors().addAll(list);
QName name=new QName("http://www.webservice.xxx.com","HelloWorld");
Object[] objects=client.invoke(name,"88888");
System.out.println("*******"+objects[0].toString());
}
客户端回调函数
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import org.apache.wss4j.common.ext.WSPasswordCallback;
/**
* @author
* 类说明
*/
public class ExampleServiceClientInterceptor implements CallbackHandler{
private Map<String, String> passwords = new HashMap<String, String>();
public ExampleServiceClientInterceptor() {
passwords.put("admin", "password");
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
String identifier = pc.getIdentifier();
int usage = pc.getUsage();
if (usage == WSPasswordCallback.USERNAME_TOKEN) {// 密钥方式USERNAME_TOKEN
System.out.println(passwords.containsKey(identifier)+"="+passwords.get(identifier)+"-"+identifier);
pc.setPassword(passwords.get(identifier));// //▲【这里非常重要】▲
}else if (usage == WSPasswordCallback.SIGNATURE) {// 密钥方式SIGNATURE
pc.setPassword(passwords.get(identifier));// //▲【这里非常重要】▲
}
}
}
}
报错信息:
16:22:32.774 [main] WARN o.a.c.p.PhaseInterceptorChain - [doLog,475] - Interceptor for {http://www.webservice.xxx.com}CommonService#{http://www.webservice.xxx.com}HelloWorld has thrown exception, unwinding now
org.apache.cxf.binding.soap.SoapFault: Error reading XMLStreamReader: Unexpected character '{' (code 123) in prolog; expected '<'
at [row,col {unknown-source}]: [1,1]
at org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor.handleMessage(ReadHeadersInterceptor.java:292)
at org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor.handleMessage(ReadHeadersInterceptor.java:70)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:833)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1695)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1572)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1373)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:673)
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:63)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:537)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:446)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:361)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:319)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:339)
at webserviceclient.main(webserviceclient.java:37)
Caused by: com.ctc.wstx.exc.WstxUnexpectedCharException: Unexpected character '{' (code 123) in prolog; expected '<'
at [row,col {unknown-source}]: [1,1]
at com.ctc.wstx.sr.StreamScanner.throwUnexpectedChar(StreamScanner.java:653)
at com.ctc.wstx.sr.BasicStreamReader.nextFromProlog(BasicStreamReader.java:2133)
at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1181)
at com.ctc.wstx.sr.BasicStreamReader.nextTag(BasicStreamReader.java:1204)
at org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor.handleMessage(ReadHeadersInterceptor.java:173)
... 16 common frames omitted
Exception in thread "main" org.apache.cxf.binding.soap.SoapFault: Error reading XMLStreamReader: Unexpected character '{' (code 123) in prolog; expected '<'
at [row,col {unknown-source}]: [1,1]
at org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor.handleMessage(ReadHeadersInterceptor.java:292)
at org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor.handleMessage(ReadHeadersInterceptor.java:70)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
at org.apache.cxf.endpoint.ClientImpl.onMessage(ClientImpl.java:833)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1695)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1572)
at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1373)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:673)
at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:63)
at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:537)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:446)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:361)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:319)
at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:339)
at webserviceclient.main(webserviceclient.java:37)
Caused by: com.ctc.wstx.exc.WstxUnexpectedCharException: Unexpected character '{' (code 123) in prolog; expected '<'
at [row,col {unknown-source}]: [1,1]
at com.ctc.wstx.sr.StreamScanner.throwUnexpectedChar(StreamScanner.java:653)
at com.ctc.wstx.sr.BasicStreamReader.nextFromProlog(BasicStreamReader.java:2133)
at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1181)
at com.ctc.wstx.sr.BasicStreamReader.nextTag(BasicStreamReader.java:1204)
at org.apache.cxf.binding.soap.interceptor.ReadHeadersInterceptor.handleMessage(ReadHeadersInterceptor.java:173)
... 16 more
<p>好几天了,自己终于找到问题了,是ehcache-xxx.jar 和ehcache-core-xxx.jar冲突, </p>
解决方法:
<!-- Shiro使用EhCache-core缓存框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 使用EhCache缓存框架 -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-ws-security</artifactId>
<version>3.2.5</version>
</dependency>
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。