您的位置:首页 > 编程语言 > C#

.net C# 调用 XFire发布的Webservice 安全访问控制

2009-12-31 16:13 489 查看
最近接触到的项目要使用.net调用xfire发布webservice,在网上找了很多方法,遇到一些“牛人”粘贴了千篇一律的代码,看着头痛,但实际的问题并没有解决,在一次调试过程中发现服务端的安全处理Handler是有状态的,于是想了个办法让服务器端保存客户端调用的认证信息,认证一次后并不再需要对身份进行多次认证

这里和大家分享一下具体的代码
关于使用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"));
}


纠正一点,其实Java与C#通过Webservice通信的安全控制还是可以用session来控制的,只是客户端需要保存一cookie,C#提供了一个cookieContainer来为我们保存Session
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐