- 浏览: 501041 次
- 性别:
- 来自: 北京
-
文章分类
- 全部博客 (1028)
- [发布至博客园首页] (826)
- [随笔分类]个人生活随笔 (14)
- [网站分类]首页候选区 (26)
- [网站分类]SharePoint (15)
- [网站分类]其他技术区 (6)
- [随笔分类]批处理技巧 (6)
- [随笔分类].net 2.0 (3)
- [随笔分类]SharePoint2007(MOSS2007) (0)
- [网站分类].NET新手区 (6)
- [网站分类]ASP.NET (6)
- [网站分类]架构设计 (18)
- [网站分类]程序人生 (2)
- [网站分类]SQL Server (2)
- WCF (3)
- 编程技巧 (2)
- 模式架构 (2)
- 分析设计 (4)
- 生活随笔 (0)
- 软件工程 (1)
- Android实例 (2)
最新评论
-
zilong0536:
楼主您好:
请问发表博文支持图片的功能怎么实现啊,一直没有思路 ...
新浪微博开放平台开发-android客户端(3) -
nicegege:
小弟 学习了
帮助中国移动设计10086的排队小模块 -
zl7824516:
用什么技术没说啊
通告(公告),消息(站内短信),提醒的设计:通告 -
virusswb:
源码下载: SinaWeibo2 源码下载之后,将后缀改为ra ...
新浪微博开放平台开发-android客户端(3) -
Jimmyxu0311:
找不到源码下载
新浪微博开放平台开发-android客户端(3)
在Silverlight+WCF中应用以角色为基础的安全模式(一)基础篇之角色为基础的安全模式简介
- 博客分类:
- [发布至博客园首页]
引言
最近一直在研究Silverlight+WCF应用中的安全问题,如何设计一个安全,又符合Silverlight和WCF的规范的应用呢?又可以将以前的角色为基础的开发框架拿来主义呢?
我们知道WCF在安全方面提供了很多的绑定协议,可是Silverlight3+WCF的话,只有basicHttpBinding可以使用,这就使得我们的选择不多,还有就是项目本身是一个互联网应用,还是使用比较通用的角色为基础的权限系统比较好。
这个系列有两篇文章,一篇讲解.NET框架提供我们的角色为基础的安全模式,以及如何根据我们的需求,自定义角色为基础的安全模式;一篇讲解在Silverlight+WCF应用中,如何设计的一种角色为基础的应用方法。
文中的代码下载:/Files/virusswb/RetrieveSecurity_src.zip
正文
.NET中的角色为基础的安全
.NET 框架使得 你在应用中实现以角色为基础的安全模式非常容易。迫使安全有两部分组成,认证和授权。认证就是验证你的身份。应用程序验证你就是你所声明的人。通常的做法是用户输入用户名和密码,应用查找你输入的用户名,然后验证你输入的密码是否匹配。更高级的做法是依赖生物认证,例如:指纹或者是视网膜,又或者是一张绑定了个人PIN码的认证卡。如果认证失败,用户将不被允许进入系统,除非系统允许匿名访问,意味着如果系统确认了你的身份,就授予你访问权。授权就是确认用户是否能操作系统的某项功能。授权依赖于已知的用户身份以及和用户相关的安全信息,基于这些安全信息,系统就可以批准或者拒绝用户的请求。
.NET框架提供了通过Identity访问用户信息,通过principal访问授权信息。Thread.CurrentPrincipal提供了当前线程的principal信息,默认情况下,它是一个非认证的授权。框架提供了两种不同的principal,一个是windows principal,一个是通用的授权generic principal。Windows principal工作在windows 操作系统上。所以,当前运行的线程会映射到一个windows帐户上。如果你正在运行一个windows form的应用程序,它就是一个用户。
有两个办法可以访问windows principal
// set that a principal should be attached to the thread and
// it should be a windows principal
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
// get hold of the windows principal
WindowsPrincipal MyPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal;
// get the windows identity
WindowsIdentity MyIdentity = MyPrincipal.Identity;
通过调用当前程序域的SetPrincipalPolicy,你告诉框架当前线程需要附加的principal,你需要在第一次访问principal之前做这些设置。调用Thread.CurrentPrincipal返回和当前线程绑定的principal。第一次这么做的时候,框架会查询windows的帐户信息创建一个windows身份和一个windows授权并且绑定到这个线程。从windows principal你可以访问windows identity。另一个办法是
// get an identity object for the windows user
WindowsIdentity Identity = WindowsIdentity.GetCurrent();
// get hold of the windows principal
WindowsPrincipal MyPrincipal = new WindowsPrincipal(Identity);
WindowsIdentity.GetCurrent()查询windows帐户信息,同时创建一个identity代表当前用户,那样你可以用这个identity创建一个principal。这 样做的缺点就是每次都需要查询windows帐户,然后创建一个identity和一个principal。第一种方法每次都会使用相同的identity和principal。通用的principal允许你创建不绑定任何windows帐户的一个principal和identity。
// create the generic identity GenericIdentity
Identity = new GenericIdentity("Administrator");
// define the roles to associate with the generic principal
string[] Roles = new string[2] { "Manager", "Architect" };
// create the generic principal
GenericPrincipal MyPrincipal = new GenericPrincipal(Identity,Roles);
// bind the generic principal to the thread
Thread.CurrentPrincipal = MyPrincipal;
首先创建一个通用的identity,你需要提供identity的名称,因为他不绑定任何windows帐户,需要一个用户名。然后定义你想要这个授权拥有的角色,最后创建一个principal,然后提供identity和角色列表。然后你可以将这个授权绑定到当前线程。
创建自定义的授权principal和认证identity
.NET框架允许通过实现IPrincipal和IIdentity接口,来自定义授权和认证。本文下面的代码,将展示如何创建一个数据库驱动的认证和授权。
<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype>
这些信息对于自定义认证和授权都是必要的。但是授权还可以更进一步,还可以检查个人权限信息,例如:用户是否被允许查看预算等。这些信息都是从SecurityRightAssign表中读取出来,让我们先创建一个自定义身份。
public class UserIdentity : IIdentity
{
// the authentication type for us is always database
private static string AuthenticationTypeString = "Database";
// hash table with all the user info we have
private Hashtable UserInfo;
// create the user identity; all user information is in the hashtable passed along
private UserIdentity(Hashtable UserInfo)
{
this.UserInfo = UserInfo;
}
//create a user identity and return it to the caller
public static UserIdentity CreateUserIdentity(Hashtable UserInfo)
{
return new UserIdentity(UserInfo);
}
}
UserIdentity实现了IIdentity接口,需要我们事先三个属性。类型的构造函数被私有化,防止通过实例化来构造对象。你需要通过静态方法CreateUserIdentity,传递一个HashTable结构的用户类型,然后创建一个身份的实例。Name属性返回这个身份的名称。
// returns the name of the identity
public string Name
{
get
{
return
Convert.ToString(UserInfo[UserNameKey],CultureInfo.InvariantCulture).Trim();
}
}
// returns if identity is authenticated or not
public bool IsAuthenticated
{
get
{
return true;
}
}
// the type of authentication
public string AuthenticationType
{
get
{
return AuthenticationTypeString;
}
}
IsAuthenticated属性返回用户是否被认证通过,在上面的代码中用户总是被认证功过,因为我们return true。如果你允许匿名访问,你就可以为匿名用户设置为false。最后一个属性AuthenticationType返回的是验证的类型,在我们的代码中返回的是“Database”。WindowsIdentity返回的是NTLM,GenericIdentity返回的是空字符串或者是实例化GenericIdentity的时候传递的验证类型。下面,我们里实现自定义的principal。
public class SecurityPrincipal : IPrincipal
{
// stores the list of security rights the user belongs too
private Hashtable SecurityGroups;
// stores the list of security rights the user has
private Hashtable SecurityRights;
// the user identity we create and associate with this principal
private UserIdentity TheUserIdentity;
// constructor: stores role and permission info and creates custom identity
private SecurityPrincipal(Hashtable SecurityGroups, Hashtable SecurityRights,
Hashtable UserInfo)
{
this.SecurityGroups = SecurityGroups;
this.SecurityRights = SecurityRights;
// creates the IIdentity for the user and associates it with this IPrincipal
TheUserIdentity = UserIdentity.CreateUserIdentity(UserInfo);
}
// create the security principal and return it to the caller
public static SecurityPrincipal CreateSecurityPrincipal(Hashtable SecurityGroups,
Hashtable SecurityRights, Hashtable UserInfo)
{
return new SecurityPrincipal(SecurityGroups,SecurityRights,UserInfo);
}
}
实现IPrincipal接口需要实现Identity属性和IsInRole()方法,同样的这个类型的构造函数也是私有的,防止通过实例化来创建对象。你需要调用静态方法CreateSecurityPrincipal,传递一个hashtable类型的用户信息,一个用户所属的角色信息,还有就是用户在系统中的特权。这个类型的构造函数调用自定义的Identity方法的静态函数CreateUserIdentity,将用户信息传递给CreateUserIdentity方法,然后返回一个UserIdentity。CreateSecurityPrincipal方法返回一个自定义的principal实例。Identity属性返回和这个principal相关联的identity。
// returns the Identity object associated with the principal
public IIdentity Identity
{
get
{
return TheUserIdentity;
}
}
// checks if user belongs to role
public bool IsInRole(string Role)
{
return SecurityGroups.ContainsValue(Role);
}
// checks if user has permission
public bool HasPermission(string Permission)
{
return SecurityRights.ContainsValue(Permission);
}
IsInRole方法检查用户是否属于角色,是通过检查角色是否在hashtable类型的SecurityGroups中,然后返回true 或者false。我们自定义的principal还实现了一个方法HasPermission,它和IsInRole方法类似,但是检查的是提供的权限是否在特权列表中,然后返回true或者false。
这些已经实现了自定义的identity和principal,下面的代码解释了信息是如何从数据库中读取,最后要做的就是去使用它。
public static IPrincipal SetSecurityPrincipal(Hashtable SecurityGroups,
Hashtable SecurityRights, Hashtable UserInfo)
{
// set that we want to use authentication within the current app-domain;
// this means a thread will have a IPrincipal associated which is then
// used by the .NET security classes when checking role based security
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
// we switch to the new security principal only if we didn't do so already;
// protects us from the client calling the method multiple times
if (!(Thread.CurrentPrincipal is SecurityPrincipal))
{
// create a new instance of the security principal which we can do only
// within a class member as we marked the constructor private
SecurityPrincipal TheSecurityPrincipal = new SecurityPrincipal(SecurityGroups,
SecurityRights,UserInfo);
// get a reference to the current security principal so the caller
//can keep hold of it
IPrincipal CurrentSecurityPrincipal = Thread.CurrentPrincipal;
// set the security principal for the executing thread to the newly created one
Thread.CurrentPrincipal = TheSecurityPrincipal;
// return the current security principal;
return CurrentSecurityPrincipal;
}
// return null if we don't switch the security principal
else
return null;
}
为了使用,我们在SecurityPrincipal类型上提供了一个静态方法SetSecurityPrincipal。首先调用AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
这样做看起来是错误的,因为我们想要的不是一个windows principal,而是一个自定义的principal。这么做只是为了保证我们拥有一个绑定到当前线程的principal,然后我们检查绑定到当前线程的principal是否是自定义的principal类型。如果是的话,我们什么都不需要做,因为我们已经为当前线程分配了我们自定义的principal,这确保了调用者在多线程的环境中调用不会产生负面的问题。只是在第一次我们会发现没有绑定到自定义的principal,这时候我们创建自定义的principal,创建自定义的identity,并且绑定到当前线程。如果调用者需要的话,我们返回当前principal给他。
在使用Thread.CurrentPrincipal访问用户信息的时候,会检查用户的角色和特权,这些都可以通过在principal上调用IsInRole或者是访问identity来实现。如果你想检查用户的特权,你可以使用从Thread.CurrentPrincipal中获取的principal的HasPermission方法来实现。
public bool CheckSecurityPermission(string Permission)
{
// if the current IPrincipal is of the same type as our custom
// security principal then go and check the security right
if (Thread.CurrentPrincipal is SecurityPrincipal)
{
SecurityPrincipal Principal = (SecurityPrincipal)
Thread.CurrentPrincipal;
// returns whether the user has the permission or not
return Principal.HasPermission(Permission);
}
// if we have a standard IPrincipal in use then we can not check
// the permission and we always return false
else
return false;
}
如果你正在创建一个新的应用程序域线程,你不想为每一个线程设置自定义的principal,你可以为每一个新创建的线程创建一个默认的principal。设置默认principal一定要在第一次第一次访问principal之前设置Thread.CurrentPrincipal。
// create the custom principal
SecurityPrincipal MyPrincipal = SecurityPrincipal.CreateSecurityPrincipal(
AppDomain.CurrentDomain.SetThreadPrincipal);
// set the custom principal as the app domain policy
AppDomain.CurrentDomain.SetThreadPrincipal(MyPrincipal);
你设置默认principal,只需要在应用程序域设置一次。在应用程序域设置多次会引发PolicyException异常。
示例代码
示例代码演示的是一个windows form程序,首先需要用户登录(在数据库中已经有两个用户,virus和swb,密码和用户名一致)。btnLogon_Click()事件和btnLogin按钮关联,调用DataLayer.CheckUserNameAndPassword().用来验证用户,调用DataLayer.RetrieveUserInformation().来获取用户信息,最后通过调用DataLayer.RetrieveSecurityInformation().来获取用户所属的角色和权限信息,在获取了用户信息、角色信息和权限信息之后,使用SecurityPrincipal.SetSecurityPrincipal()创建一个principal和identity,并且绑定到当前线程。
从示例中看出用户属于是三个角色,全部的权限,和用户信息,可以检查用户是否属于某一个角色,是否具有某一个权限,CheckSecurityRoles() and CheckSecurityPermissions()返回用户是否属于一个角色,是否有一个权限。logoff 按钮的 LogOff_Click()方法恢复原始的principal,并且返回登陆界面,允许另外一个用户登录,继续前面的处理过程。
在示例文件夹中你会发现一个叫做RetrieveSecurity.bak的文件,它是数据库的备份文件。恢复数据库,配置app.config文件中的连接字符串。你可以在数据库中添加用户、角色和权限信息。示例展示了在.NET 的角色为基础的安全模型之后,如何实现数据库驱动的验证和安全模型。
总结
大多数应用都需要通过角色和权限来实现用户验证和安全模型。.NET框架使得这些变得容易,几行代码,就改变了windows账号和安全组的影响。使用自定义的identity和principal可以很容易的扩展角色为基础的安全框架,示例代码展示的就是如何实现数据库驱动的角色权限系统。
参考文献
【1】Role-Based Security Microsoft
【2】Introduction to Role-Based Security in .NET Klaus Salchner
【3】在Identity 增加自己的属性 部门,并且使用access mdb文件实现角色验证 iHqq
感谢上面这些机构和作者的无私奉献。
发表评论
-
NET 应用架构指导 V2 学习笔记(十六) 服务层设计指导
2010-06-04 00:13 552如果你的应用是通 ... -
NET 应用架构指导 V2 学习笔记(十七) 组件设计指导
2010-06-05 00:48 680组件提供了一种将 ... -
NET 应用架构指导 V2 学习笔记(十八) 表现层组件设计指导
2010-06-05 21:09 535本章讲述的是你在设计用户界面组件和表现层逻辑组件的时候应该 ... -
NET 应用架构指导 V2 学习笔记(十九) 表现层组件设计指导
2010-06-06 06:15 6055 决定数据绑定的 ... -
NET 应用架构指导 V2 学习笔记(二十) 业务组件设计指导
2010-06-07 06:58 622前言 业务组件 ... -
微软企业库5.0学习笔记(四十二)异常处理模块
2010-06-14 00:04 846企业库的异常处理 ... -
关于程序员在30岁、35岁之后怎么办的新思考
2010-06-14 10:40 630首先给大家问个好 ... -
NET 应用架构指导 V2 学习笔记(二十四) 跨层关注问题
2010-06-17 20:00 610概况 大部分的 ... -
微软企业库5.0学习笔记(四十三)数据验证模块
2010-06-19 08:07 1009概况 任何接受用户或者是其他系统输入的应用,一定要确保 ... -
关于项目进度慢的思考----如何提高整体开发效率
2010-06-21 23:42 813我们都是软件行业 ... -
微软企业库5.0学习笔记(四十四)实战数据验证模块
2010-06-23 19:22 8561 在业务对象上添加验证 添加对程序集【Microso ... -
微软企业库5.0学习笔记(四十五)实战数据验证模块----高级篇
2010-06-24 19:41 9821、添加自定义的提示信息 验证失败的提示信息可以自定义 ... -
面向对象类设计的五大原则(一)单一职责原则Single Responsibility Principle
2010-06-29 15:45 788引言 面向对象类设计,或者说是面向对象设计,有五大原则 ... -
《深入浅出设计模式-中文版》读书笔记 开篇乱弹(一)
2010-07-01 06:42 667oreilly的《Head.First ... -
《深入浅出设计模式-中文版》读书笔记-继承与组合(三)
2010-07-03 16:53 612经过上一次的改造 ... -
《深入浅出设计模式-中文版》读书笔记-观察者模式(四)
2010-07-06 06:34 646今天要接触的是观 ... -
利用attribute实现简单的ORM
2010-07-09 15:27 689我不知道NH的ORM具 ... -
系统内部模块(子系统)之间的耦合以及模块(子系统)划分
2010-07-14 13:02 817题外话 最近已经在努力学习了,学习基本功,学习设计模式 ... -
《深入浅出设计模式-中文版》读书笔记-工厂模式(五)
2010-07-16 12:46 712今天给大家带来的是:工厂模式。 我们在代码中创建一个对 ... -
Head.First.Object-Oriented.Design.and.Analysis《深入浅出面向对象的分析与设计》读书笔记(一)
2010-07-18 21:47 678题外话 又是一本Head.First系列的书,这个系列 ...
相关推荐
同时,需要注意的是,由于Silverlight的安全限制,跨域访问可能需要配置WCF服务的跨域策略文件(crossdomain.xml)和Silverlight应用程序的客户端access policy文件(clientaccesspolicy.xml),以允许从不同源进行...
在本篇中,我们将深入探讨Silverlight客户端与WCF RIA服务的交互,特别是通过查看提供的"ExampleSilverlightApp"源代码来理解这一过程。Silverlight是微软开发的一个富互联网应用程序(RIA)平台,它允许开发者创建...
本篇将深入探讨一款名为"oa.rar"的压缩包文件,其中包含了"JMail44_pro.exe"、"oa_silverlight"、"oa_wcf"以及"oa_wpf"等关键组件,揭示了新一代OA软件的核心技术特点。 首先,"JMail44_pro.exe"是一款专业的企业级...
【Silverlight基础知识篇】 Silverlight是由Microsoft开发的一种富互联网应用程序(RIA)平台,它主要用于创建交互式的、多媒体丰富的网络应用。Silverlight 2 Beta 1的发布带来了许多新特性和改进,增强了其作为...
在本篇中,我们将深入探讨WCF RIA(Windows Communication Foundation Rich Internet Application)服务与Silverlight客户端6的源代码交互。WCF RIA服务是一种强大的技术,它允许开发者构建跨域分布式应用程序,尤其...
《Silverlight 3 高级编程 (C#篇)》是针对Microsoft Silverlight 3这一技术的深入探讨,主要面向已经掌握基础的C#开发者,旨在帮助他们提升在Silverlight平台上的开发技能。这本书的第二部分继续了第一部分的内容,...
在深入学习Silverlight的过程中,你还会遇到诸如数据服务集成(如WCF RIA Services)、多媒体播放、动画和特效、以及与服务器端的交互(如ASP.NET MVC或Web Forms)等主题。Silverlight的灵活性和强大功能使其成为...
在现代软件开发中,Model-View-ViewModel(MVVM)设计模式已经成为构建用户界面的一种主流方式,尤其在Silverlight应用开发中,MVVM模式的应用尤为广泛。本篇文章将通过分析“silverlight mvvm demo”这个学习示例,...
4. **异步通信**: Silverlight中的WCF通信通常采用异步模式,以避免阻塞UI线程,确保用户界面的响应性。 ### 三、文件上传与下载 1. **Upload**: Silverlight提供了FileOpenPicker控件,允许用户选择本地文件进行...
这篇论文可能涵盖了Silverlight的基础技术,包括XAML(可扩展应用程序标记语言)、数据绑定、依赖属性、动画和特效,以及与其他技术如WCF(Windows Communication Foundation)的集成。 **八、应用Silverlight2_0和...
而数据库访问是这类应用的基础,本篇文章将探讨如何使用Silverlight与MySQL数据库进行数据交互,实现CURD(Create、Read、Update、Delete)操作。 首先,我们需要在开发环境中搭建测试项目。这通常涉及到创建一个新...
Silverlight,作为微软推出的一款跨浏览器插件,曾广泛应用于富互联网应用(RIA)开发,尤其是在Windows Presentation Foundation(WPF)的基础上提供了轻量级的Web应用程序开发框架。本篇文章将围绕“Silverlight4...
在Visual Studio 2010中,选择“新建项目”,然后选择“Silverlight应用程序”,并命名为“SilverlightDB”。在创建过程中,可以选择项目类型,例如SL4 Application。这样,你就有了一个基础的Silverlight项目结构。...
在本篇文章中,我们将深入探讨 Silverlight 4 的核心特性,以及与其相关的 Model-View-ViewModel(MVVM)设计模式在实际开发中的应用。** **1. Silverlight 4 的新特性:** - **增强的浏览器集成**:Silverlight 4 ...
此篇文章介绍了如何在Silverlight项目中使用LINQ进行数据处理,对于希望提升Silverlight应用数据管理能力的开发者而言,是一个不可多得的参考资料。 3. **《WCF与Silverlight的深度集成》**:WCF(Windows ...
Silverlight 2是微软推出的一种富互联网应用程序平台,它在Beta 1版本中引入了多种新特性,包括对多种编程语言的支持(如Visual Basic、Visual C#、IronRuby、IronPython),以及对JSON、Web Service、WCF和Sockets...
ArcGIS API for Silverlight是一种强大的工具,用于在Web浏览器中构建具有地理空间功能的应用程序。本篇将深入探讨如何利用该API进行开发,首先从平台搭建开始,然后逐步构建你的第一个应用程序。 一、平台搭建 1....
本篇文章将深入探讨一个利用SilverLight和BingMap技术构建的车辆监控系统,帮助读者理解如何结合这两种技术实现高效、实时的车辆定位和跟踪功能。 SilverLight是微软推出的一种富互联网应用程序(RIA)框架,主要...
本篇文章将深入探讨如何在Silverlight 4中实现一个图片公告栏的功能,这是一项能够以动态、吸引人的方式展示多张图片的应用。 首先,我们要理解Silverlight 4相较于之前的版本有哪些改进和增强。Silverlight 4提供...