1.访问安全性

    WebService对于我们来说并不陌生,在很多地方我们都会使用到它,它为我们带来了很多方便,同时解决了多平台之间的通讯协议问题等等,因为WebService是以一种Http请求和Xml响应的方式来达成多平台之间的接入。这种方式我们一般称之为‘接口’。这里需要说明的是:所谓平台是指开发平台(例如ASP.NET和Java等开发平台)和站点平台(例如淘宝网站和支付宝网站)。就因为WebService给我们带来种种方便,导致有很多’同学‘大量的、无选择性的使用WebService,从而易导致对系统性能的降低,同时,如未对WebService访问安全性做防御的话极有可能对系统安全性造成的致命的漏洞。因为只要知道WebService的Http请求地址,那任何一个客户端都可以进行请求。而WebService将会面临的有它所认可的客户端和不认可的客户端请求。

  我们来举个例子,例如:中国移动公司对外提供了一个发送手机短信的WebService接口,并此请求地址已被公开。那任何一个客户端都可以请求这个WebService。当这个接口没有验证请求的客户端身份的话,那就意味着任何客户端都可调用此接口进行发送短信。这样移动不亏死才怪。所以它就会在每个客户端请求过来时先验证请求的客户端是否是跟此接口达成了一种合法请求协议的客户端。如果是合法请求则为此请求提供服务,否则对请求一概否决。

  那我们如何来判断这些请求中哪些是合法、哪些是非法呢?以本人对WebService的开发,总结了以下比较好的三种方式验证,并每种验证处于不同安全级别,也可说不同使用场合。

  1.级别:低

     使用场合:在本站点使用,不对外开放。

     验证方式:通过验证码验证

     具体说明:我们可在webService服务端配置一段任意字符串(最好是MD5加密),然后客户端发送请求过来时,同时将验证码发送服务端,然后再跟服务端的验证码进行比较来判断是否是合法请求。例如:

 

代码
[WebMethod(Description = "发送短信")]
public bool SendSms(string authString,string mobiles, string smsContent, DateTime? sendTime, ref string error)
{
//根据客户端发送的验证码进行根服务器的验证码进行匹配
if (authString != "980017891ff67cf8a20f23aa810e7b5a")
{
//不是合法客户端请求时,将拒绝对此请求提供服务
error = "非法请求,验证身份失败";
return false;
}
//如果是合法请求,则继续为此请求提供服务
using (SmsFacade smsFacade = new SmsFacade())
{
if (!smsFacade.SendSms(smsContent, mobiles, sendTime))
{
error
= smsFacade.PromptInfo.CustomMessage;
return false;
}
}
return true;
}

 

 

  2.级别:中上

    使用场合:提供第三方平台使用,完全开发性

    验证方式:通过请求的客户端IP验证

   具体说明:我们可以将合法请求的客户端IP保存在服务端(可存入数据库等方式保存),当客户端发送请求过来时,可根据客户端的IP在服务端保存的IP中验证是否为合法请求。例如:

 

代码
/// <summary>
/// 发送短信服务
/// </summary>
/// <param name="mobiles">接收的手机号码</param>
/// <param name="smsContent">短信内容</param>
/// <param name="sendTime">发送时间,为空则立刻发送</param>
/// <param name="error">当请求失败时的详细失败原因</param>
/// <returns></returns>
[WebMethod(Description = "发送短信")]
public bool SendSms(string mobiles, string smsContent, DateTime? sendTime, ref string error)
{
//根据客户端请求的IP进行跟服务端所配置的IP进行验证(IP可配置在文件中或数据库)
if (Context.Request.UserHostAddress != "218.18.69.86")
{
//不是合法客户端请求时,将拒绝对此请求提供服务
error = "非法请求";
return false;
}
//如果是合法请求,则继续为此请求提供服务
using (SmsFacade smsFacade = new SmsFacade())
{
if (!smsFacade.SendSms(smsContent, mobiles, sendTime))
{
error
= smsFacade.PromptInfo.CustomMessage;
return false;
}
}
return true;
}

 

 

 

 

  3.级别:高

   使用场合:提供第三方平台使用,完全开发性

   验证方式:身份登陆验证

   具体说明:我们可以在服务端建一张第三方用户信息表,包含用户账号和密码等相关信息。客户端请求时,必须将账号和密码发送到服务端进行登陆,来验证是否为合法请求。例如:

 

代码
[WebMethod(Description = "发送短信")]
public bool SendSms(string userCode, string userPwd, string mobiles, string smsContent, DateTime? sendTime, ref string error)
{
//先根据客户端发送用户账号和密码登陆
UserFacade userFacade = new UserFacade();
if (!userFacade.Login(userCode, userPwd))
{
//登陆失败,将拒绝对此请求提供服务
error = "非法请求,登陆失败";
return false;
}
using (SmsFacade smsFacade = new SmsFacade())
{
if (!smsFacade.SendSms(smsContent, mobiles, sendTime))
{
error
= smsFacade.PromptInfo.CustomMessage;
return false;
}
}
return true;
}

 

 

  当然,也还有很多比较好的方式的方式,我这就不一一列出了。希望这些方式能给你写的WebService提高访问的安全性。

posted @ 2010-11-27 16:37 笑看人间 阅读(620) 评论(4) 编辑

    在实际问题中,有些变量的取值被限定在一个有限的范围内。例如,一个星期内只有七天,一年只有十二个月,性别只有男跟女等等。如果把这些量说明为整型、字符型或其它类型显然是不妥当的。为此,C#提供了一种称为“枚举”的类型。在“枚举”类型的定义中列举出所有可能的取值,被说明为该“枚举”类型的变量取值不能超过定义的范围。应该说明的是,枚举类型是一种基本数据类型,而不是一种构造类型,因为它不能再分解为任何基本类型。

1、定义枚举

    定义枚举很简单,直接使用enum关键字声明即可,例如定义性别的枚举,性别只有男和女

public enum Sex
{
= 0,//’0‘是’女‘对应的内部表示,也可以说是女的Value,’女‘是外部表示,也可以说是Name
= 1,
}

2.使用枚举

代码
1 public void UseEnum()
2 {
3 //获取枚举对应的值
4   int enumValue = (int)Sex.男;//enumValue的值则为 1
5
6 //获取枚举的名称
7   string enumText = Sex.男.ToString();//enumText的值则为 男
8
9 //将int类型值转换为对应的枚举
10   int intValue = 1;//int值
11   Sex sex = (Sex)intValue;//sex则为对应男的枚举
12
13 //将名称转换为对应的枚举
14   string strValue = "";
15 sex = (Sex)Enum.Parse(typeof(Sex), strValue);//sex则为对应男的枚举
16
17 //判断int值或名称是否在枚举定义项类
18   if (Enum.IsDefined(typeof(Sex), intValue))//第二个参数也可以传入strValue
19   {
20 //
21   }
22
23 //switch来判断sex (小技巧:先输入switch 再加两个Tab键 ,然后再switch()
24 //里面输入枚举,再回车键,代码段就会自动的将枚举所有项加上case)
25   switch (sex)
26 {
27 case Sex.女:
28 break;
29 case Sex.男:
30 break;
31 default:
32 break;
33 }
34 //........................
35   }

3.通常我们在数据库中,很多的一些状态、类型、性别等等字段保存的是数字,但我们在开发时需要判断这些状态时,直接使用 if(UserInfo.Sex==0)这种方式来判断,显然不太好,如果状态多时,自己都难分辨哪个数字代表什么状态。并且代码也不可观,我们在写代码时应该尽量少写硬代码。如果使用枚举定义,数据库存储的枚举对应的值,而在写代码时使用枚举的名称,这样一看代码就知道数据库储值的是什么状态。非常清楚明了。

4.UI层显示枚举的名称。如果数据库存储的是枚举的值(为数字),而在UI上当然不能已数字的方式显示,应该显示对应的枚举名称。例如在一个用户信息列表中需要绑定用户性别(枚举为上述的Sex),那该如何显示枚举的名称呢?一下提供多种方式

  3.1:GridView控件绑定数据源为例,可以添加一列模板项,通过值获取枚举名称

代码
1 <asp:TemplateField HeaderText="性别">
2 <ItemTemplate>
3 <%#(枚举所在命名空间.Sex)Convert.ToInt32(Eval("Sex"))%>
4 </ItemTemplate>
5</asp:TemplateField>

  3.2:  通过Enum对象获取名称

代码
1 <asp:TemplateField HeaderText="性别">
2 <ItemTemplate>
3 <%#Enum.GetName(typeof(枚举所在命名空间.Sex), Convert.ToInt32(Eval("Sex")))%>
4 </ItemTemplate>
5 </asp:TemplateField>

       还有很多方式来处理这个问题,大家可以自由选择。

5.枚举的‘高级用法’组合运用:例如一个界面里有:增、删、查、改等操作,但对应不同用户就有不同操作权限。例如A用户只能增、删,而B用户只能查、改等等。如果在权限表中某一个字段类型指定用户的操作权限时,问题就出来了。来看看一下3种解决方式:

  1.每个操作权限一条数据,缺点:每次更改权限时,避免不了删除和新增,并且数据量庞大,如果一个用户有一千权限就代表有一千条数据,那这张表的数据就不敢想象了。

  2.一个字段存储所有的操作权限,每个操作权限使用 某个指定的符号作为分隔符,这种方式叫简单、方便。

  3.就是使用我们的枚举组合,在一个字段存储所有的操作权限,但值只为一个数,不像方式2使用分隔符分开。

当然,还有很多方式可以解决这种问题。我们现在就来看看如何使用枚举组合来代表多个操作权限。

  5.1:定义一个操作权限枚举:

 

[Flags]//必须打上一个标记,打上这个标记系统才能识别这个枚举可使用组合方式
public enum Role
{
        未分配=0,
删除数据
= 1,
修改数据
= 2,
新增数据
= 4,
查看数据
= 8,
}

  5.2:如果用户有删除、修改的权限在枚举定义中只有1和2的枚举,那怎么将这两个枚举值组合成一个枚举值存储到数据库呢?很简单,看一下代码:

 

 

int allRole = ((int)Role.删除数据) + ((int)Role.修改数据);
//这时allRole的值为3 (两个枚举对应值相加:1+2=3),这时直接将allRole值存储到数据就可以了

现在我们就来判断用户是否具有某个操作权限,先从数据库中取出权限值,以上述,allRole则为数据库中取出的值,为3,接下来我们通过位算符来判断:

 

代码
Role myAllRole = (Role)allRole;//将int值强制转换为枚举
//此时,myAllRole的名称为 ‘ 删除数据, 修改数据 ’ ,值为3
//判断是否有删除权限
if ((myAllRole & Role.删除数据) == Role.删除数据)
{
//
}

 

注意此处使用了 位算符& 方式来获取判断,关于位算符的使用在此就不讲了。组合运用大概就是这样。必须注意的地方就是枚举值的定义,我们可以看到Role枚举的定义值的规律,0到1,1到2,2到4,4到8,8到16......当前的值为上个值的2次方,为什么要这样定义呢?是因为任何的组合都可以在枚举范围中某几个值的总和,例如组合值为15,那15就等于枚举定义范围里的定义值为1、2、4、8相加,15=1+2+4+8。只有按规律定义值,就可以组合成任意数。

组合必须注意的几点:

1.枚举定义时,必须打上[Flags]标记,系统才会根据这个标记来决定这个枚举是否可组合使用

2.定义枚举的值必须按以上所说的规律定义,例如:0、1、2、4、8、16、32.......也可以使用3次方的方式,例如:0、3、6、12、24..........

 

6.使用优点总结

  1.规则性:例如数据库某个字段的值只在1、2、3、4,例如状态,当我们在录入数据时,我们可以从枚举中取值,这样避免了这个字段出现其它值,同时也使代码更容易理解,因为在取值时,我们是拿枚举定义的名称,名称是我们自定义的易理解的中文或英文。

  2.易解性:就是上述所说的,枚举名称是用中文和英文来定义,在使用时,则拿枚举的名称,这样一看代码就知道。而不会在代码中写1、2、3、4这样的数字,也许过段时间自己写的都忘了了1代表什么?2代表什么?了,更何况日后他人的维护呢。

还有很多优点。希望大家能更好的用好枚举,上述某些地方讲述的不够清楚,如有需要进步的了解的朋友可以加我Q,大家一起互相学习。QQ:554044818

  

 

 

 

 


posted @ 2010-11-12 17:44 笑看人间 阅读(229) 评论(3) 编辑

   我们在开发中经常写到以下代码:

为什么decimal类型的变量可以使用 <、 <= 、>= 、+、 - 、*、 /等运算符呢?而我们随便定义一个对象却不能两个对象进行使用这些运算符呢?decimal对象是如何做到呢?我们现在就来揭晓Decimal对象。先转定义到Decimal对象,可以从元数据中可以看到以下方法:

可以明显的看到这些运算符,但奇怪的是,这个’方法‘既没有方法名称又所有的都是静态。更明显的是使用了operator关键字来声明。那如果我们自定义一个类怎么使用operator关键字来实现两个类的运算符操作呢?现在我们来写一个简单的类,很快就会明白operator关键字的使用。

我们定义了一个Currency通用货币对象,并且使用了operatro关键字来重载运算符,接下来我就可以直接使用它所重载的运算符:

现在大家应该明白operator关键字的使用了吧。operator可以用在于很多地方,例如一个对象里某个string类型属性的值进行累加等操作时,我们就可以使用这种运算符来处理,就避免了对象 A.Value+=B.Value;直接可以使用:A+=B;希望大家更好的使用operator关键字。

好了,今天就写到这,希望大家多多指教。3Q!

posted @ 2010-11-11 17:10 笑看人间 阅读(241) 评论(0) 编辑