CXF学习笔记(1)-HelloWorld!-发布webservice
CXF学习笔记(3)-HelloWorld!-通过servlet发布webservice
前3节中介绍了如何发布一个webservice和客户端如何调用,一切貌似都正常,但存在着安全隐患-这样导致任意的客户端都可以调用我们的webservice服务,接下来将介绍如何采用基于用户名和密码认证的方式来实现客户端调用
1.服务器端配置
a.在发布service的时候为该service添加一个WSS4JInInterceptor 拦截器
表示我们的service需要用户提供用户名和密码认证后才能调用
package com.crazycoder2010.webservice.cxf.server;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletConfig;
import org.apache.cxf.endpoint.Endpoint;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.frontend.ServerFactoryBean;
import org.apache.cxf.service.invoker.BeanInvoker;
import org.apache.cxf.transport.servlet.CXFNonSpringServlet;
import org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor;
import org.apache.ws.security.WSConstants;
import org.apache.ws.security.handler.WSHandlerConstants;
import com.crazycoder2010.webservice.cxf.server.HelloWorldServiceImpl;
public class WebServiceServlet extends CXFNonSpringServlet {
private static final long serialVersionUID = -5314312869027558456L;
@Override
protected void loadBus(ServletConfig servletConfig) {
super.loadBus(servletConfig);
System.out.println("#####################");
ServerFactoryBean svrFactory = new ServerFactoryBean();
svrFactory.setServiceClass(HelloWorldService.class);
svrFactory.setAddress("/passportService");
svrFactory.setInvoker(new BeanInvoker(new HelloWorldServiceImp()));
Server server = svrFactory.create();
Endpoint cxfEndpoint = server.getEndpoint();
Map<String, Object> inProps = new HashMap<String, Object>();
inProps.put(WSHandlerConstants.ACTION,
WSHandlerConstants.USERNAME_TOKEN);
inProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);
inProps.put(WSHandlerConstants.PW_CALLBACK_CLASS,
ServerPasswordHandler.class.getName());
cxfEndpoint.getInInterceptors().add(new WSS4JInInterceptor(inProps));
}
}
b.处理用户名和密码的逻辑
添加一个ServerPasswordHandler类,该类实现CallbackHandler接口,user='kevin',password='111111'为该service的访问用户名密码
public class ServerPasswordHandler implements CallbackHandler{
private String user = "kevin";
private String password = "111111";
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
if(user.equals(pc.getIdentifier())){
pc.setPassword(password);
}
}
}
2.客户端配置
a.配置WSS4JOutInterceptor拦截器,表示发出请求的时候将以提供的用户名和密码信息提交到服务器端认证
public class WebServiceFactory {
public static PassportService getHelloWorldService(){
Map<String,Object> outProps = new HashMap<String,Object>();
outProps.put(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
outProps.put(WSHandlerConstants.USER, "kevin");//这个用户即服务器端配置的用户名
outProps.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_DIGEST);
outProps.put(WSHandlerConstants.PW_CALLBACK_CLASS, ClientPasswordHandler.class.getName());//这个类用来获取客户端认证用户名密码信息
JaxWsProxyFactoryBean bean = new JaxWsProxyFactoryBean();
bean.getInInterceptors().add(new LoggingInInterceptor());
bean.getInFaultInterceptors().add(new LoggingOutInterceptor());
bean.setServiceClass(PassportService.class);
bean.setAddress("http://localhost:8080/CXF-Server/webservice/helloWorldService");
HelloWorldService helloWorldService = (HelloWorldService)bean.create();
ClientProxy clientProxy = (ClientProxy)Proxy.getInvocationHandler(passportService);
Client client = clientProxy.getClient();
client.getOutInterceptors().add(new WSS4JOutInterceptor(outProps));//配置拦截器
return helloWorldService;
}
}
b.配置客户端认证信息类
public class ClientPasswordHandler implements CallbackHandler{
@Override
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
WSPasswordCallback pc = (WSPasswordCallback) callbacks[0];
pc.setPassword("kevin");//这个地方的用户名和密码与服务器端保持一致
pc.setIdentifier("111111");
}
}
c.客户端调用
public class DemoClient {
public static void main(String[] args) {
HelloWorldService helloWorldService = WebServiceFactory.getHelloWorldService();
helloWorldService.sayHello("John");
}
}
小结:
这种方式利用服务器端与客户端共享同一用户名密码的方式实现了webservice的安全访问,流程图如下
参考资料:http://cxf.apache.org/docs/ws-security.html