ASP.NET 开发必备知识点(2):那些年追过的ASP.NET权限管理
一、前言
在前一篇文章已经为大家介绍了OWIN和Katana,有了对他们的了解之后,才能更好地去学习Asp.net Identity,因为Asp.net Identity的实现集成了Owin。其实在Asp.net 2.0的时候,微软已经对用户权限管理进行了实现,其实现为Membership。由于之前的实现有很多限制,所以微软在Asp.net 4.5推出了Asp.net Identity。接下来,本篇文章将详细介绍下Asp.net Identity的实现。
二、Asp.net中用户权限管理发展历程
在前面我们已经说过,在Asp.net 2.0的时候,Asp.net中就已经实现了用户权限管理,所以,Asp.net 用户权限管理有其发展历程。下图就是Asp.net中权限管理的发展历程:

ASP.NET Membership
Asp.net Membership是在2005年的Asp.net 2.0引入的。Membership机制引入了表单验证(Form Authentication),以及一个用于存储用户名、密码和其他用户信息的SQL Server数据库。但它同样存在一些限制:
- 数据库只能使用SQL Server,难以对SQL Server Compact、SQL Azure、NoSQL支持。并且你想为用户表添加额外字段的话,此时你只能创建一个User的附加表。对于开发者来说,不能很好地自定义用户信息。
- 由于Asp.net Membership是基于表单进行验证的,因此无法支持OWIN。
ASP.NET Simple Membership
Asp.net Simple Membership是对Asp.net Membership的一次改进,它使得你可以更容易自定义用户信息。尽管如此,由于它依然是基于Asp.net Membership之上的,所以它仍然存在以下几点限制:
- 对非关系数据库支持不好。
- 不支持OWIN
- 对于已存在的Asp.net Membership Provider支持的不是很好,不利于扩展。
ASP.NET Universal Providers
Asp.net Universal Providers解决了前两者的一些问题,例如他支持存储用户在Azure SQL和SQL Server Compact数据库中。并且它基于EF code First实现的,所以它支持EF支持的所有数据库。但由于它依然是基于Asp.net Membreship基础架构实现的,所以仍然有些问题不能很好解决。所以它只解决了前两者的部分问题,其本身还存在一些限制:
- 对非关系数据库支持不好
- 不支持OWIN
三、Asp.net Identity 详细介绍
随着互联网的快速发展,从而非关系数据库也层出不穷,但之前的三者权限管理都对非关系数据库支持的不是很好,所以微软必须要实现一种新的权限管理机制,所以在。NET Framework中推出了Asp.net Identity。该套机制解决了之前的所有问题。Asp.net 具有如下特点:
- 可用于ASP.NET所有框架上,包括Asp.net MVC、Asp.net Web Forms、Web Pages、Asp.net Web API和SignalR。
- 可用于各种应用程序,包括Web应用、移动应用,Windows Store应用和混合架构应用。
- 用户信息的自定义
- 存储易于扩展:默认使用EF Code First存储在SQL Server数据库中,但可以很好地扩展到SharePoint、Azure SQL和NoSQL 数据库中。
- 支持单元测试
- 提供了Role Provider,使创建和管理变得简单
- 支持面向Claims的身份验证(即:支持基于声明的身份验证),前面的三者都是基于表单的身份验证。
- 支持社交账号的登录,支持Facebook,Microsoft账户、Twitter,Google、QQ等社交账户。
- 支持Windows Azure Active Directory账号登录功能
- 支持OWIN。
- 通过Nuget发布,这样能让Asp.net 团队更好地修复Bug和迭代新功能,并在第一个时间进行发布。将其与System.Web.dll程序集解耦。
四、Asp.net Identity内部实现机制
从上面对Asp.net Identity的介绍可以发现,它确实解决了之前的所有问题,那它是如何做到的呢?要知道其实现机制并不难,因为Asp.net Identity已经开源,我们可以到其站点下载其源码研究即可,其开源地址为:http://aspnetidentity.codeplex.com/。这里简单的分析它注册和登录的功能的内部实现。
首先使用VS2013创建一个Asp.net MVC站点,此时网站的用户授权和认证模块的代码的实现VS已经帮我们添加好了,我们只需要找到对应的注册和登录功能对其进行分析,从而明白Asp.net Identity是如何帮完成这两个功能的。
首先,我们找到Accout控制器中注册功能的实现代码:
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false); // 有关如何启用帐户确认和密码重置的详细信息,请访问 http://go.microsoft.com/fwlink/?LinkID=320771
// 发送包含此链接的电子邮件
// string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
// var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// await UserManager.SendEmailAsync(user.Id, "确认你的帐户", "请通过单击 <a href=\"" + callbackUrl + "\">這裏</a>来确认你的帐户"); return RedirectToAction("Index", "Home");
}
AddErrors(result);
} // 如果我们进行到这一步时某个地方出错,则重新显示表单
return View(model);
}
从上面代码的方法名可以看出,完成用户注册的主要实现在于UserManager.CreateAsync方法上,这个方法实现真是在Asp.net Identity帮我们实现,接下来到我们下载的源码来查看该方法的实现。具体的源码实现如下所示:
public virtual async Task<IdentityResult> CreateAsync(TUser user, string password)
{
ThrowIfDisposed();
var passwordStore = GetPasswordStore();
if (user == null)
{
throw new ArgumentNullException("user");
}
if (password == null)
{
throw new ArgumentNullException("password");
}
// UpdatePassword对密码进行Hash加密
var result = await UpdatePassword(passwordStore, user, password).WithCurrentCulture();
if (!result.Succeeded)
{
return result;
}
// 注册功能的实现
return await CreateAsync(user).WithCurrentCulture();
} public virtual async Task<IdentityResult> CreateAsync(TUser user)
{
ThrowIfDisposed();
await UpdateSecurityStampInternal(user).WithCurrentCulture();
var result = await UserValidator.ValidateAsync(user).WithCurrentCulture();
if (!result.Succeeded)
{
return result;
}
if (UserLockoutEnabledByDefault && SupportsUserLockout)
{
await GetUserLockoutStore().SetLockoutEnabledAsync(user, true).WithCurrentCulture();
} // 调用IUserStore的CreateAsync完成用户注册
await Store.CreateAsync(user).WithCurrentCulture();
return IdentityResult.Success;
} // UserStore中CreateAsync的实现
public virtual async Task CreateAsync(TUser user)
{
ThrowIfDisposed();
if (user == null)
{
throw new ArgumentNullException("user");
} // 将实体添加进DbSet<User>集合中
_userStore.Create(user);
// 调用SaveChanges将用户保存到数据库中
await SaveChanges().WithCurrentCulture();
}
看到这里是不是豁然开朗了很多的,其实Asp.net Identity内部注册功能的实现,我们完全可以自己来实现。其实现简单的说就是:
1. 对用户提交的数据进行验证
2. 对密码进行加密保存
3. 调用Microsoft.AspNet.Identity.EntityFramework命名空间下的UserStore类的CreateAsync方法将用户进行持久化。
4. UserStore类中的CreateAsync方法的实现也就是DbSet<User>.Add(entity)和SaveChanges()方法将对象持久化。
到这里还有一个问题,其实上面代码调用的是IUserStore接口中的CreateAsync方法,但具体的IUserStore对象是怎么注入进去的呢?
你带着这个疑惑去Asp.net MVC站点中去寻找其注入代码。此时,你可以发现在Startup.Auth.cs和Start.cs文件中有如下实现:
// Startup.cs 文件
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
} // Start.Auth.cs文件
public void ConfigureAuth(IAppBuilder app)
{
// 配置数据库上下文、用户管理器和登录管理器,以便为每个请求使用单个实例
// .........
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// ........
} // IdentityConfig.cs文件
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// ........
}
看到上面标注红色的代码了吗,这里就是将UserStore注入的地方。看到这里,你是不是没有任何疑惑了。对于登录功能的实现大家同样可以按照这样的方法去探索。本来想一起分析下的,后面想想,还是留给大家去探索吧。
五、从Asp.net Identity内部实现学会项目分层架构
其实,在我们平时工作,只要学会如何使用Asp.net Identity机制来完成对应功能。那我们为什么还要研究其源码实现呢?我觉得有两点:
- 研究源码实现,可以让你对其实现原理有一个深刻的理解,对于分析出现的问题有极大的好处。因为只有你了解其实现原理,写功能模块才能更加自信,处理出现的问题才会比别人快。
- 除了第一点之外,研究源码还有一个重要的作用就是学习源码作者的项目分层和代码分离。在现实生活中,有很多朋友抱怨出现瓶颈了,无法提高,因为平常工作中一般都是去写堆功能的代码,觉得对能力没什么提高。此时你完全可以去研究微软开源的代码,通过研究源码来学习大牛们是如何将项目做到低耦合高内聚的,学习大牛们是如何做到代码分离的。然后再讲学习到的内容应用于工作,相信这样的一个过程下来,你不想提高都不行了。渐渐地你会觉得自己也可以完成一个开源框架。
上面介绍了研究源码的两大作用,那我们从Asp.net Identity内部实现中又学到了什么呢?
通过第四部分的代码分析,Asp.net Identity中注册功能的实现主要分为的4点中,我们可以学到如下几点:
- 关注点的分离。Asp.net Identity注册功能中,将用户输入以及密码加密等代码实现都分离到具体的类中进行实现,而不是将其放在UserManager这个类中。这充分体现关注点分离原则
- 针对接口编程原则。Asp.net Identity内部实现中,都是针对于接口编程,每个类中依赖都是接口,并没有依赖与具体类。从而降低代码之间的耦合。
- 实现了依赖注入。Asp.net Identity具体实现是通过在调用端通过依赖注入的方式进行注入。
- 项目分层架构。Asp.net Identity注册功能。AccountController首先调用UserManager的CreateAsync,而UserManager的CreateAsync又调用了IUserStore中的CreateAsync方法来通过调用EF的DbContext来完成数据的持久化。从这个调用过程和类之间的关系可以看出,这真是领域驱动设计的分层体现。领域驱动设计中设计4层,分别是UI层、应用层、领域层和基础设施层。其中UI层对应的就是AccountController类,应用层对应的就是UserManager类、领域层就是具体的User实体、基础设施层对应的就是IUserStore(准确地说,基础设施层中的仓储对应着IUserStore)。上面对应的项目分层,其实每个层中代码的实现都可以按照这个模式去实现。这点在ABP Web框架中得到了很好的实现:https://github.com/aspnetboilerplate/aspnetboilerplate。
所以,如果你觉得你现在的工作得到提高的话,完全不需要去什么群里咨询其他的推荐什么书籍什么,从现在开始就开始研究源码吧。如果不知道研究什么源码的话,完全可以从微软的一些开源代码开始,例如就从Asp.net Identity源码开始,不要担心研究完之后,还是怕不能提高,只要你理解和领悟了,你不想提高都难。另外再推荐大家研究下ABP的实现,我最近就在研究它,希望理解透彻之后,再写一个小的Web框架来巩固自己的研究。到时候也会把自己的一些研究心得分享到这里。
六、总结
到这里,本篇文章的介绍就结束了,希望这篇文章可以帮助朋友对微软的用户权限管理框架有进一步的了解,以及希望哪些想提高的朋友,从现在开始就来和我一起来研究微软的开源框架和ABP框架吧。记得研究之后,分享到这里与大家共享哦。
ASP.NET 开发必备知识点(2):那些年追过的ASP.NET权限管理的更多相关文章
- ASP.NET 开发必备知识点(1):如何让Asp.net网站运行在自定义的Web服务器上
一.前言 大家都知道,在之前,我们Asp.net 的网站都只能部署在IIS上,并且IIS也只存在于Windows上,这样Asp.net开发的网站就难以做到跨平台.由于微软的各项技术的开源,所以微软自然 ...
- ASP.NET MVC开发:Web项目开发必备知识点
最近加班加点完成一个Web项目,使用Asp.net MVC开发.很久以前接触的Asp.net开发还是Aspx形式,什么Razor引擎,什么MVC还是这次开发才明白,可以算是新手. 对新手而言,那进行A ...
- 基于asp.net(C#)MVC+前端bootstrap+ztree+lodash+jquery技术-Angel工作室通用权限管理
一.Angel工作室简单通用权限系统简介 AngelRM(Asp.net MVC Web api)是基于asp.net(C#)MVC+前端bootstrap+ztree+lodash+jquery技术 ...
- ASP.NET MVC 必备知识点杂谈
一 工程结构4个程序集 Microsoft.Web.Mvc --一些可以使用的,不确定的程序包System.Web.Mvc --主程序库下面两个列入3.5的Net框架了System.Web.Abs ...
- Asp.net开发必备51种代码
1.//弹出对话框.点击转向指定页面 Response.Write("<script>window.alert('该会员没有提交申请,请重新提交!')</script> ...
- 开发必备知识点--django项目启动时,url加载之前,执行某个.py文件
django项目启动时,自定义执行某个py文件 在任意的app下的apps.py中的Config类下自定义ready()方法,并且调用autodiscover_modules. app01/apps. ...
- UWP开发必备:常用数据列表控件汇总比较
今天是想通过实例将UWP开发常用的数据列表做汇总比较,作为以后项目开发参考.UWP开发必备知识点总结请参照[UWP开发必备以及常用知识点总结]. 本次主要讨论以下控件: GridView:用于显示数据 ...
- ASP.NET MVC C#知识点提要
ASP.NET MVC C#知识点提要 本篇博文主要对asp.net mvc开发需要撑握的C#语言知识点进行简单回顾,尤其是C# 3.0才有的一些C#语言特性.对于正在学asp.net mvc的童鞋, ...
- Hybrid App 应用开发中 9 个必备知识点复习(WebView / 调试 等)
前言 我们大前端团队内部 ?每周一练 的知识复习计划继续加油,本篇文章是 <Hybrid APP 混合应用专题> 主题的第二期和第三期的合集. 这一期共整理了 10 个问题,和相应的参考答 ...
随机推荐
- js汉语转拼音(全拼、首字母、拼音首字母)
新建js文件first_alphabet.js // JavaScript Document // 汉字拼音首字母列表 本列表包含了20902个汉字,用于配合 ToChineseSpell //函数使 ...
- X64操作系统组件Jmail无法正常服务问题
故障现象: 近日,在VMware虚拟化部署迁移中,之前物理服务器中部署网站ASP组件Jmail服务一切正常,迁移完成后发现Jmail无法正常工作,其余组件能正常工作. 环境:Windows Serve ...
- django+nginx+xshell简易日志查询,接上<关于《rsyslog+mysql+loganalyzer搭建日志服务器<个人笔记>》的反思>
纠正一下之前在<关于<rsyslog+mysql+loganalyzer搭建日志服务器<个人笔记>>的反思>中说到的PHP+MySQL太慢,这里只是说我技术不好,没 ...
- SQLYog快捷键大全
Ctrl+M 创建一个新的连接 Ctrl+N 使用当前设置新建连接 Ctrl+F4 断开当前连接 对象浏览器 F5 刷新对象浏览器(默认) Ctrl+B 设置焦点于对象浏览器 SQ ...
- 利用windows服务+timer或者windows任务计划程序+控制台进行进行每日邮件推送
1.邮件发送代码 using System.Text; using System.Net; using System.Net.Mail; using System.Reflection; using ...
- IOS常见错误之一连线错误
在IOS编程中,UI方面,对于新手,接触时,不免喜欢拖控件,觉得省去了一些麻烦,其实在操作控件的过程中也有很多问题需要注意 本人今天就说下遇到的一个问题. setValue:forUndefinedK ...
- mvc理解篇
java是面向对象的语言. mvc是一种设计模式,就像论文排版,设置好论文的框架,字体,大小,颜色等,然后把论文内容往里填.mvc的出现让代码的层次更加的清晰,业务通过数据流实现. mvc框架的优点如 ...
- Windows结构化异常
不错的总结: http://hi.baidu.com/wangxvfeng101/item/518f6efdab4e5616ff35820e http://www.vckbase.com/index. ...
- 使用AOP框架所需引入的Jar包
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w ...
- js复制内容加版权声明代码
$("body").on('copy', function (e) { if (typeof window.getSelection == "undefined" ...