上一篇提到过CXF的安全性问题..
这里提供一个解决思路 , 在调用CXF服务端的时候,进行用户校验.这样子似乎能提高一些安全..
正式项目使用的话, 用户名和密码都要MD5加密..
不过使用用户名和密码 , 还是有一点 "伪安全"的意思..
别人要是抓个包... 不全部歇菜嘛..
不废话了.. 先把工程代码贴上来.. 下载之后可以直接运行.
服务端接口
package com.cxf.inter;
import javax.jws.WebService;
@WebService
public interface CXFInterface {
public String sayHello(String name);
}
package com.cxf.inter;
import javax.jws.WebService;
@WebService
public class CXFDemoImpl implements CXFInterface {
@Override
public String sayHello(String name) {
return "Interceptor Hello : " + name;
}
}
package com.cxf;
import java.util.List;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class AuthInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
// 在拦截器调用方法之前,拦截SOAP消息.
public AuthInterceptor() {
super(Phase.PRE_INVOKE);
}
@Override
/**
* 拦截器处理方法
*/
public void handleMessage(SoapMessage message) throws Fault {
System.out.println("---- 进入拦截器 ----");
// 获取SOAP携带的所有Header
List<Header> headers = message.getHeaders();
if (null == headers || headers.size() < 1)
throw new Fault(new IllegalArgumentException("拦截器实施拦截 , 没有Header"));
// 获取Header携带的用户名和密码
Header firstHeader = headers.get(0);
Element element = (Element) firstHeader.getObject();
NodeList userNameElement = element.getElementsByTagName("userName");
NodeList passWordElement = element.getElementsByTagName("passWord");
if (userNameElement.getLength() != 1)
throw new Fault(new IllegalArgumentException("用户名不能为空.."));
if (passWordElement.getLength() != 1)
throw new Fault(new IllegalArgumentException("密码不能为空.."));
// 获取元素中的文本内容
String username = userNameElement.item(0).getTextContent();
String password = passWordElement.item(0).getTextContent();
// 实际项目中,是从数据库中取数据做校验
if (!username.equals("cyx") || !password.equals("123456")) {
throw new Fault(new IllegalArgumentException("用户名或密码不正确.."));
} else {
System.out.println("验证成功!!");
}
}
}
服务端发布主类
package com.cxf;
import javax.xml.ws.Endpoint;
import org.apache.cxf.jaxws.EndpointImpl;
import com.cxf.inter.CXFDemoImpl;
/**
* CXF拦截器<br>
* 通过拦截器,进行用户校验.
*
* @author CYX
*
*/
public class StartMain {
public static void main(String[] args) {
String address = "http://localhost:8088/CXFDemo/sayHello";
EndpointImpl epi = (EndpointImpl) Endpoint.publish(address, new CXFDemoImpl());
epi.getInInterceptors().add(new AuthInterceptor());
System.out.println("WebService 发布成功 , address : " + address);
}
}
通过wsdl生成客户端代码就不多说了..去看以前的文章吧...
客户端拦截器
package com.client.interceptor;
import java.util.List;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.SoapMessage;
import org.apache.cxf.headers.Header;
import org.apache.cxf.helpers.DOMUtils;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* 客户端拦截器
*
* @author CYX
*
*/
public class AddHeaderInterceptor extends AbstractPhaseInterceptor<SoapMessage> {
private String userName;
private String passWord;
public AddHeaderInterceptor(String username, String password) {
super(Phase.PREPARE_SEND);
this.userName = username;
this.passWord = password;
}
@Override
public void handleMessage(SoapMessage message) throws Fault {
List<Header> header = message.getHeaders();
// 创建Document对象
Document document = DOMUtils.createDocument();
Element element = document.createElement("authHeader");
// 配置服务端Head信息的用户名和密码
Element userNameElement = document.createElement("userName");
userNameElement.setTextContent(userName);
Element passWordElement = document.createElement("passWord");
passWordElement.setTextContent(passWord);
element.appendChild(userNameElement);
element.appendChild(passWordElement);
header.add(new Header(new QName(""), element));
}
}
package com.client;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.frontend.ClientProxy;
import com.client.interceptor.AddHeaderInterceptor;
import com.cxf.inter.CXFDemoImplService;
import com.cxf.inter.CXFInterface;
public class TestClient {
public static void main(String[] args) {
CXFDemoImplService cxfDemo = new CXFDemoImplService();
CXFInterface cxfInter = cxfDemo.getCXFDemoImplPort();
Client client = ClientProxy.getClient(cxfInter);
client.getOutInterceptors().add(new AddHeaderInterceptor("cy", "123456"));
String response = cxfInter.sayHello("xycheng");
System.out.println("response : " + response);
}
}
这里的'cyx' 和 '123456' 要和服务端拦截器中的相匹配..
正式项目肯定是通过数据库验证..
然后直接运行服务端和客户端就行了...
密码错误
服务端控制台打印
客户端控制台打印信息
密码争取的控制台打印信息
服务端
客户端