posted at 2008.9.30 10:22 by Spoony
一 引言
随着Web Service的出现,其应用也是越来越广,同时也深受开发者的喜爱。下面我将引用一个实际应用例子说明本文的目的。
假设有一个网上购物系统LiveShopping。在LiveShopping上,当客户已经选好他自己想买的商品之后,接下来就该付帐了。LiveShopping可以直接用信用卡付帐。另外假设LiveShopping的电子付款是与VeriSign合作。也就是说LiveShopping是VeriSign的一个客户。假设VeriSign提供了一些Web Services供LiveShopping使用。假设这些方法是:
1.VerifyCC(string cc_no,string expire_date,float amt)
2.ProcessCC(string transaction_type, string cc_no,string expire_date,float amt,CardHolder holder)
其中方法1验证信用卡是否有效,方法2是一个Transaction,将从信用卡上划出amt数额的交易款。
参数说明
cc_no 信用卡卡号码
expire-date 有效日期
amt金额
transaction_type 事务类型,比如说sale, force等等
holder 持卡人信息
这里有个问题,如果VeriSign没有身份验证,那怎么知道客户是LiveShopping。换句话说,如果没有身份验证,每个人都可以使用这两个方法。所以身份验证必不可少。
二 实现身份验证
身份验证有很多方法,这里将介绍一种非常简单的方法,并且在.NET中实现。
可以应用WebService的Soap 头实现。也就是说可以利用Soap头传递验证的信息,比如用户名,密码等等。
首先从客户端看,可以对其应用有一个直观的了解。代码如下
private void Button1_Click(object sender, System.EventArgs e)
{
AuthHeader auth = new AuthHeader();
WebServices webService = new WebServices();
auth.UserName = this.txtName.Text.Trim();
auth.Password = this.txtPwd.Text.Trim();
webService.authHeader = auth;
string rtStr = webService.GetPassword();
this.txtReturn.Text = rtStr;
}
解释一下,AuthHeader为前面提及的Soap头的实现,其定义如下:
public class AuthHeader : SoapHeader
{
public string UserName;
public string Password;
}
继续看看WebServices是如何实现的,代码如下:
public class WebServices : System.Web.Services.WebService
{
public AuthHeader authHeader;
[SoapHeader("authHeader")]
[WebMethod(Description = "This method will return the sensitive data")]
public string GetPassword()
{
if (authHeader.UserName.Equals("user") && authHeader.Password.Equals("pwd"))
{
return "pwd";
}
return "Invalid Authentication ";
}
}
可以发现,加入了一个AuthHeader公共成员。这个可以供调用者传输验证信息。另外重要的一点是SoapHeader属性,它明确了Soap头。具体可以参见MSDN。
在GetPassword()中,可以加入你的代码。它第一步就是验证信息,如果验证成功,继续完成你的事情,如果不成功,则退出。
三 进一步
如果为了使应用更加安全,我们可以对数据进行加密,比如说我们可以对验证信息进行加密。可以在客户端进行加密,然后到了server端进行解密。加密和解密是另外一个话题,在这里不多假描述。
从性能方面来看,加密解密这个过程将会降低性能。所以一般可以折中考虑,只对于一些敏感的数据进行加密和解密,比如说密码等。除非是一些高安全性的应用,这时就另当别论了。
posted at 2008.9.30 10:03 by Spoony
在安全性要求不是很高的ASP.Net程序中,基于Forms的身份验证是经常使用的一种方式,而如果需要对WebService进行身份验证,最常用的可能是基于Soap 标头的自定义身份验证方式。如果对两者做一下比较的话,显然,基于Forms的验证方式更加方便易用,能否将Forms验证方式应用到WebService中去呢?
从理论上讲,使用基于Forms的方式对WebService进行身份验证是可行的,但是使用过程中会存在以下两个问题:
1.基于Forms的验证方式同时也是基于Cookie的验证方式,在使用浏览器时,这个问题是不需要我们考虑的。但对于使用WebService的应用程序来说,默认是不能保存Cookie的,需要我们自己去做这个工作。
2.WebService既然是一个A2A(Application To Application)应用程序,使用Web表单进行身份验证显然不太合适,而且,这将不可避免的造成人机交互,使WebService的应用大打折扣。
接下来,我们就分步解决这两个问题:
1.Cookie的保存问题
WebService的客户端代理类有一个属性CookieContainer可用于设置或获取Cookie集合,保存Cookie的任务就交给他了:
System.Net.CookieContainer cookieContainer = new System.Net.CookieContainer();
MyService.WebService service = new App.MyService.WebService();
service.CookieContainer = cookieContainer;
2.我们不想使用Web表单进行身份验证,幸运的是,ASP.Net表单验证中的表单页(即Web.config文件中 forms 元素内的loginUrl)同样可以指定为WebService文件。
我们创建一个专门用作身份验证的Web服务,暂且命名为Login.asmx,然后让 loginUrl 等于 “Login.asmx”,当然,还需要在Web.config文件中的 authorization 节中禁止匿名访问(否则我们可就白忙活了),完成配置后的Web.config文件如下:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation debug="false" />
<authentication mode="Forms">
<forms name="MyService" loginUrl="Login.asmx"></forms>
</authentication>
<authorization >
<deny users="?" />
</authorization>
</system.web>
</configuration>
其实我们并不想在未通过身份验证时让浏览器转向到Login.asmx,对于使用WebService的客户程序来说,真正的实惠在于:可以匿名访问Login.asmx中的方法(当然我们也可以把Login.asmx放在单独的目录中,然后允许对该目录的匿名访问来达个这个目的,但我觉得还是用loginUrl更优雅一些)。
接下来,我们为Login.asmx添加用于身份验证的WebMethod:
public bool Check(string userName, string password)
{
if (userName == "aaaaaa" && password == "123456")//添加验证逻辑
{
System.Web.Security.FormsAuthentication.SetAuthCookie(userName, false);
return true;
}
else
{
return false;
}
}
最后一步工作就是:让客户程序中的WebService实例与Login实例共享CookieContainer。
class Sample
{
System.Net.CookieContainer cookieContainer = new System.Net.CookieContainer();
public void Login()
{
MyServiceLogin.Login login = new App.MyServiceLogin.Login();
login.CookieContainer = cookieContainer;
login.Check("aaaaaa", "123456");
}
public void ShowHelloWorld()
{
MyService.WebService service = new App.MyService.WebService();
service.CookieContainer = cookieContainer;
Console.WriteLine(service.HelloWorld());
}
}
Login()以后再ShowHelloWorld(),你是否看到了我们熟悉的“Hello World”?Ok,就这么简单!
posted at 2008.9.29 09:37 by Spoony
博易目前的 TroubleShooting 主要是通过用户交流群来做的。经过规划和考量,已打算把这部分工作转移到论坛上来。那么以后博易用户交流群仅用作用户之间的交流,而官方将把精力在论坛上去集中。这么做对博易的发展有一些好处。
A.内容归档,可追溯,减少重复的解答同样的问题。
B.内容共享范围扩大,原本仅在群内,而在论坛上的话可以扩大到所有Web浏览者。
C.交流可以异步。这么一来可以给双方都减轻工作负荷。
D.促使Web良性发展。论坛的帖子可以被搜索引擎收录,实现一个比较完备的Web的发展。
E.言论的所有权得以控制。
上面好处多多,是促使博易更好地发展的一个要素。不过也有不便之处,还请大家积极配合了。
posted at 2008.9.27 15:15 by Spoony
区别IE6与FF:
background:orange;*background:blue;
区别IE6与IE7:
background:green !important;background:blue;
区别IE7与FF:
background:orange; *background:green;
区别FF,IE7,IE6:
background:orange;*background:green !important;*background:blue;
posted at 2008.9.24 16:33 by Spoony
如果现在你要问我感觉如何。“脑子麻木了。”我的回答道!
刚才人肉把从我的第一个博客到现在的博客里面的所有文章都温习了一次,上千篇文章呐,筛选出了比较符合“永恒意义”的文章转发过来了。我的精力之旺盛连我自己都为之折服!
昨天已经做好了主题模板,今天给换上。我想这次,如果我的审美标准不会出现重大颠覆的话就会一直使用,更新这一模板了。
通过浏览以前的文章,发现自己一直在成长。感概啊……
posted at 2008.9.19 14:36 by Spoony
群里面一位朋友提出了的,昨天测试了下,果然二级分类链接有问题。
回去之后修改好了,现在把改好的文件发出来给大家下载。
这个问题并不严重,如果你没有使用或者也不打算使用二级分类,可以不用下载。
这里是下载包,解压替换 App_Code\Controls 下的相应文件即可。
CategoryList.zip (1.47 kb)
posted at 2008.9.16 12:19 by Spoony
昨天的创意让我瞎忙活了一阵,还把自言自语的所有文章全部重新分类、标记Tag。结果还是把分类给恢复过来了。
开始是准备在自言自语的基础上完成我的创意,可惜当时没想太远。后来是把自言自语所有文章整理了一遍,才了解最初建立自言自语时的初衷。
认识到以后发展了,还是得继续自言自语下去。于是权当给自言自语来了一次大清理。
至于昨天的创意,另起炉灶了,嘎嘎~
posted at 2008.9.14 12:50 by Spoony
前几天出于某些因素在后台把博易官方和自言自语的在线发送邮件功能中的发送附件给禁用了。本以为一切OK,也没有再去测试发送邮件。
但这几天都没收到任何关于博易的邮件,于是感到奇怪。

粗看了下相关部分代码,没找出原因。然后进入了回想

。。。
之后我尝试把附件功能开启,居然恢复正常了。那么原因就是在附件这个上面。赶紧重新审视代码,找到问题所在了。
修补这个 BUG 只需要把博易主目录下的
contact.aspx.cs 中第76行,原为:
if (IsCaptchaValid && Page.IsValid && txtAttachment.HasFile)
问题在于如果没有启用附件功能,那么第三个条件永远无法满足,也就发送不了邮件了。
改为如下即可:
if (IsCaptchaValid && Page.IsValid)
再测试,OK!
posted at 2008.9.11 12:45 by Spoony
官方网站改版成功了,博易的服务将越来越成熟,这其中要感谢 SEVEN 给我最初的提示。现在我想写点东西,关于开源软件和开源软件的用户之间的关系。
开源意味着没有任何技术保留,开源的成功与否在我看来是对开源软件的用户以及参与者的某种程度上的引导和调动。其实好的开源软件就像中国的太极理论,是自我修补自我完善的,没有商业软件的锐利的棱角。开源软件的更新取之于用户,用之于更多的用户。而开源项目的引导者可分为很多种,一种是启发型,一种是无为型。
对于启发型的项目引导者,他们会突出地,集中地去做架构和内核的完善。更多的人是去这个开源项目中学习和借鉴技术知识。启发型的项目多是大项目。
而对于无为型的项目引导者,则是在前期实现了一个相对完善的系统,然后自个就成了一台服务器,仅仅是监听需求、监听其他人的更新。然后收集更新,整合完善原有系统。无为型的项目一般不大,且在前期有一个相对完善的,可用的原型。
其实启发和无为也没有什么界限,目前博易还是走无为线路居多,我们要做的仅仅是让这样一个过程良性持续下去并维持其平衡。同时,我们的用户以及参与者在这个项目中将无意中贡献出自己的智慧给这个开源项目,给更多的人,他们是伟大的!