最近接触到的项目要使用.net调用xfire发布webservice,本文将阐述如何使用SOAP Header传递认证信息并且保存客户端的调用状态
这是.net 生成代理类的使用wsdl.exe工具 配置文档如下
- <?xml version="1.0" encoding="utf-8"?>
- <wsdlParameters xmlns="http://microsoft.com/webReference/">
- <nologo>true</nologo>
- <parsableerrors>true</parsableerrors>
- <sharetypes>true</sharetypes>
- <namespace>ConsoleApplication1</namespace>
- <documents>
- <document>http://localhost:8080/v2/services/KillService?wsdl</document>
- </documents>
- </wsdlParameters>
服务器上我们添加验证方法
- package com;
- /**
- * @author Zhang Qi
- * @CreateTime 2009-12-30
- * **/
- import java.util.Date;
- import java.util.HashMap;
- import java.util.Iterator;
- import org.codehaus.xfire.MessageContext;
- import org.codehaus.xfire.fault.XFireFault;
- import org.codehaus.xfire.handler.AbstractHandler;
- import org.codehaus.xfire.transport.http.XFireServletController;
- import org.jdom.Element;
- import org.jdom.Namespace;
- public class AuthenticationHandler extends AbstractHandler implements Runnable {
- public AuthenticationHandler() {
- // 该线程检查用户登录是否超时
- new Thread(this).start();
- }
- // 定义hashMap 存储用户验证信息,key经过验证的用户IP,或者客户端特定信息
- HashMap<String, String> hash = new HashMap<String, String>();
- // 当某个客户端登录成功后,纪录登录的时间,key 为经过验证的用户IP,或者客户端的特定信息
- HashMap<String, Date> createHashDate = new HashMap<String, Date>();
- private final static Namespace TOKEN_NS = Namespace
- .getNamespace("demoService");
- // 统计当前服务访问的人数
- Integer count = 0;
- public void invoke(MessageContext context) throws Exception {
- // 假如hash中存在用户验证信息,则直接跳出该函数,不再进行验证
- if (hash.containsKey(XFireServletController.getRequest()
- .getRemoteAddr())) {
- return;
- }
- // 得到客户soap header 对象
- Element header = context.getInMessage().getHeader();
- if (header == null) {
- throw new XFireFault(
- "Request must include company authentication token1.",
- XFireFault.SENDER);
- }
- // 得到认证令牌
- Element token = header.getChild("AuthenticationToken", TOKEN_NS);
- if (token == null) {
- throw new XFireFault("Request must include authentication token.",
- XFireFault.SENDER);
- }
- Element name = token.getChild("name", TOKEN_NS);
- Element password = token.getChild("password", TOKEN_NS);
- if (name == null || password == null) {
- throw new XFireFault("AuthenticationToken Error,name or password is null", XFireFault.SENDER);
- }
- String nameValue = name.getValue();
- String passwordValue = password.getValue();
- if (nameValue == null||passwordValue==null) {
- throw new XFireFault("name or password's value is null.", XFireFault.SENDER);
- }
- try {
- //进行服务器端验证
- if (nameValue.equals("admin") && passwordValue.equals("admin")) {
- System.out.println("登录成功!登录时间:" + new Date());
- System.out.println("当前人数:" + (++count));
- hash.put(XFireServletController.getRequest().getRemoteAddr(),
- XFireServletController.getRequest().getRemoteAddr());
- createHashDate.put(XFireServletController.getRequest()
- .getRemoteAddr(), new Date());
- } else {
- System.out.println("fail login");
- throw new Exception("Login fail");
- }
- } catch (Exception e) {
- throw new XFireFault("Authentication Failed.", XFireFault.SENDER);
- }
- }
- public void run() {
- service();
- }
- public synchronized void service() {
- while (true) {
- try {
- /**
- * 取出用户登录时间与当前时间进行对比
- * 如果当前时间与用户登录时间之差大于系统设置的某个时间,则将用户登录信息清除
- * **/
- for (Iterator<String> keys = hash.keySet().iterator(); keys.hasNext();) {
- Date now = new Date();
- String key = keys.next();
- long time = now.getTime()
- - createHashDate.get(key).getTime();
- if (time > 20*30 * 1000) {
- System.out.println(now);
- System.out.println(createHashDate.get(key));
- synchronized (hash) {
- hash.remove(key);
- }
- synchronized (count) {
- count--;
- }
- }
- }
- //每10秒钟进行一次用户登录信息检测
- Thread.sleep(10000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
稍微解释下此段代码
当web服务器启动的时候,比如tomcat启动的时候,该类将被实列化,生命周期直到tomcat关闭的时候结束
服务器services.xml
配置如下
- <?xml version="1.0" encoding="UTF-8"?>
- <beans xmlns="http://xfire.codehaus.org/config/1.0">
- <service xmlns="http://xfire.codehaus.org/config/1.0">
- <name>demoService</name>
- <namespace>demoService</namespace>
- <serviceClass>com.kiloway.webservice.demo.Iservice</serviceClass>
- <implementationClass>com.kiloway.webservice.demo.serviceImpl</implementationClass>
- <inHandlers>
- <handler handlerClass="com.kiloway.webservice.demo.AuthenticationHandler"></handler>
- </inHandlers>
- <mce:style><!--
- wrapped
- --></mce:style><style mce_bogus="1">wrapped</style>
- <use>literal</use>
- <scope>application</scope>
- </service>
- </beans>
.net客户端调用的时候添加一个类
- 客户端采用.net调用
- 添加客户端的AuthenticationToken
- 具体代码如下
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Web.Services;
- using System.Web.Services.Protocols;
- namespace ConsoleApplication1
- {
- [System.Serializable]
- [System.Xml.Serialization.XmlType(Namespace = "demoService")]
- [System.Xml.Serialization.XmlRoot(Namespace = "demoService", IsNullable = false)]
- public class AuthenticationToken : SoapHeader
- {
- public string name = null;
- public string password = null;
- }
- }
然后再生成的代理类里面添加
- public AuthenticationToken SoapHeader = new AuthenticationToken();
在生成的代理类的调用方法上再添加如下代码
- [SoapHeader("SoapHeader")]
在调用该方法时候,验证信息将被加入soap header中
调用采用
- demoService demo = new demoService();
- while (true)
- {
- demo.SoapHeader.name = "admin";
- demo.SoapHeader.password = "admin";
- System.Console.WriteLine(demo.sum(1, 23));
- System.Console.WriteLine(demo.example("Hello,Kity"));
- }