一个完整的ASP.NET的请求中会存在身份验证(Authentication)阶段以及授权(Authorization)阶段,英文单词Authentication和Authorization非常相似,所以很多时候会混淆这两个概念。身份验证(Authentication)的目的是知道“你”是谁,而授权(Authorization)则是当“你”访问一个资源时是否符合访问条件,符合就将访问权限授权给你进行访问,否则拒绝访问。

  本文将从以下几点介绍ASP.NET MVC如何使用Identity完成资源访问的限制:
  ● 资源访问的限制方式
  ● ASP.NET中的访问限制
  ● ASP.NET MVC中基的访问限制
  ● ASP.NET MVC中的用户信息
  ● ASP.NET Identity用户身份信息填充
  ● ASP.NET MVC访问限制的实现
  ● ASP.NET MVC基于用户声明的访问限制及自定义限制

资源访问的限制方式

  什么是资源?在Web中通过URI(Uniform Resource Identifier,统一资源标识符)来对HTML文档、图片、图像等内容定位,反过来说在Web中HTML文档、图片、图像等内容就是资源,而资源访问的限制就是对在用户通过URI访问Web资源时,判断该用户是否有权限访问该资源,如果有则继续访问,否则拒绝访问。
  资源访问有以下几种限制方式:
  ● 匿名访问限制:所有人都可以访问资源。
  ● 根据用户名访问限制:指定特定的用户,让其能够或者不能访问资源。
  ● 根据用户角色访问限制:指定特定角色,让拥有该角色的用户能够访问资源。
  ● 根据用户声明(Claim)访问限制:指定特定的声明(Claim),让身份信息中含有该声明的用户能够访问资源。
  ● 使用其它用户信息进行访问限制:根据用户身份的其它信息来判断用户是否能够访问资源。
  从上面几点可以看出资源访问的限制或者说授权,实际上就是通过用户信息来判断用户是否有访问资源的权限,而常用的信息是用户名、用户角色以及用户声明。
  注:对于授权来说,它处于身份验证的后续阶段,所以可以认为在授权阶段时已经存在用户信息,所以可以直接使用用户信息来完成访问限制。

ASP.NET中的访问限制

  ASP.NET中通过HTTPModule的方式实现了FileAuthorizationModule以及UrlAuthorizationModule来对用户访问文件以及其它资源进行权限控制,其中UrlAuthorizationModule可以通过在web.config中添加如下配置来通过用户名或者用户角色限制访问:

  

  在ASP.NET中可以通过Forms验证+UrlAuthorizationModule来实现用户身份验证和访问授权,更多信息可参考文档:https://docs.microsoft.com/en-us/aspnet/web-forms/overview/older-versions-security/membership/user-based-authorization-cs

ASP.NET MVC中的访问限制

  Forms验证+UrlAuthorizationModule的方式是用于基于ASP.NET Web Form的应用程序,而ASP.NET MVC虽然也可以使用Forms验证,但是ASP.NET MVC的授权方式是不一样的,它是通过过滤器的方式实现,下面代码为之前文章中用于限制后台管理页面需要登录的代码:

  

  通过在Controller上使用了一个名为Authorize的特性来实现的,这个特性的定义如下:

  

  它用于当用户访问Controller或Action方法时可以通过用户信息对其访问进行限制。

  在Authorize特性的定义中可以看到名为Roles以及Users的属性,其作用就是设置可以访问该资源的用户或者角色:

  

  使用方法如下所示:

  

ASP.NET MVC中的用户信息

  通过前面的介绍可以知道用户的授权是根据用户信息来的,无论是基于角色的、用户的、声明的甚至是自定义的,都需要依赖用户信息进行权限判断,那么ASP.NET MVC中到底包含什么用户信息?
  1. HttpContextBase与IPrincipal:
  首先可以知道的是在ASP.NET中有一个最核心的HTTP上下文对象HttpContextBase,它保存了整个Http请求到响应过程的所有相关数据,其定义如下:

  

  其中就包含了一个名为User的IPrincipal类型:

  

  该类型中的Identity属性就包含了用户的信息:

  

  从接口中可以看到它仅仅包含了用户名、身份验证反射以及是否验证通过三个属性。

  注:IPrincipal的实现有多种而本例中使用的是ClaimPrincipal。

  

  2. ClaimsIdentity与AuthenticationTicket:
  通过前面的文章分析得知Identity基于Cookie的身份验证方式实际上是对一个AuthenticationTicket对象序列化加密、反序列化解密的过程,而这个AuthenticationTicket就携带了所有用户的信息,在AuthenticationTicket的定义中可以看到两个重要的对象,其中AuthenticationProperties保存了身份验证的会话信息,如过期时间、是否允许刷新等。而另一个ClaimsIdentity属性就是以声明(Claim)的方式实现的用户信息。

  

  ClaimsIdentity的部分定义如下:

  

  其中除了实现IIdentity接口的属性外,还有一个重要的属性是Claims,它用于以声明的方式来保存用户信息,那么Identity是如何完成用户数据填充的?

ASP.NET Identity用户身份信息填充

  用户的获取填充主要是在用户登录(注册用户后会自动登录)的时候完成的,因为在后续的请求中Identity仅需通过解析加密后的用户信息字符串即可获得用户信息(注:会存在重新生成刷新该信息的情况,如身份信息的滑动过期等)。

  通过前面文章的分析知道了在Identity中用户的登录是通过SignInManager对象完成的以下是用户登录的代码及注册代码:

  

  以下是注册代码,实际上是创建完成用户后执行了登录操作:

  

  注:通过对源码分析,SignInManager.PasswordSignInAsync方法实际上最后也是调用SignInAsync方法完成的登录。

  那么SignInAsync到底做了什么?

  

  从代码中可以看到,该方法调用了一个名为CreateUserIdentityAsync的方法,根据其方法名、参数以及返回值类型来看就已经可以确定该方法就是通过用户对象生成上面提到的用于以声明的方式保存用户信息的方法。从它的实现中可以看出它实际上是通过UserManager生成的:

  

  而UserManager又是通过ClaimsIdentityFactory完成的:

  

  ClaimsIdentityFactory.CreateAsync方法的实现:

  

  注:实际上身份信息的刷新也是通过UserManager完成的:

  

  方法的实现仍然是UserManager的CreateIdentityAsync方法:

  

  从实现中可以看出如果UserManager支持角色、声明等功能,它会从数据库中加载对应的信息以声明(Claim)的形式保存在ClaimsIdentity对象中。
  在数据库中添加以下数据(为了演示功能直接在数据库中添加角色、声明信息并于用户数据进行关联,如果要开发此功能可基于UserManager完成):
  角色信息:

  

  用户声明(Claim):

  

  角色与用户信息关联:

  

  注:由于此处Identity EF与MySQL,对象与表映射存在问题,所以多了一些ID列,暂时不管这个问题,关于Identity与MySQL用法可以参考这篇文档:https://docs.microsoft.com/en-us/aspnet/identity/overview/getting-started/aspnet-identity-using-mysql-storage-with-an-entityframework-mysql-provider
  运行程序并登录后,在用户信息(ClaimsIdentity)中可找到添加的角色和声明信息:

  

ASP.NET MVC访问限制的实现

  上面介绍了用户信息的填充,那么访问的限制实际上就是对用户信息比较而已,下面是Authorize特性的核心方法:

  

  其中核心的三个判断为:
  ● user.Identity.IsAuthenticated:必须通过身份验证。
  ● (this._usersSplit.Length <= 0 || this._usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase)):特性没有指定用户或者当前用户存在于指定的用户列表中。
  ● (this._rolesSplit.Length <= 0 || this._rolesSplit.Any(new Func<string, bool>(user.IsInRole)):特性没有指定角色或者当前用户拥有指定的角色。
  以上三个条件必须全部符合才能够访问。

ASP.NET MVC基于用户声明的访问限制及自定义访问限制

  ASP.NET MVC中虽然用户信息是基于声明的方式保存的,但是却没有实际的实现,所以需要自己动手实现一个(注:也可以参考ASP.NET Core中的实现https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims)。
  实现一个自定义的授权特性(注:之前分析过HttpContext中的User是一个IPrincipal类型,实际上MVC使用的是与ClaimsIdentity对应的ClaimsPrincipal)代码如下,该过滤器只是在原有的授权方式基础上添加了声明的检查:

  

  使用方式如下:

  

  登录后访问上面action得到下面结果,验证通过:

  

  注:需要注意的是以上介绍的授权方式,无论是通过角色、用户名还是声明,它都需要以硬编码的形式写在代码中,换句话说就是在开发时必须确定该功能或者Controller/Action访问需求。但是一些时候也会出现访问需求不确定的情况,访问权限的配置会在运行时通过配置文件或者数据库来动态配置,这样的话自定义的授权过滤器就需要依赖一些业务组件来实现自定义的授权流程。

小结

  本章介绍了授权与身份验证的关系以及在ASP.NET中的实现,并详细介绍了ASP.NET MVC中的Identity是如何使用身份验证数据来完成授权的。常见的授权方式一般是基于用户名、角色以及声明,但是它们使用的场景边界是不那么明确的,就是说用什么都行实际情况需要根据需求来看,一般权限控制较简单的使用基于角色的授权即可。但无论基于什么来对用户授权,这些信息都属于用户信息,所以在拓展用户的授权时首先要考虑的是用户的特征信息,其次是用户身份验证时如何获取填充这些信息,最后才是考虑如何使用这些信息来进行授权。

参考:  

  https://msdn.microsoft.com/en-us/library/wce3kxhd.aspx
  https://stackoverflow.com/questions/21645323/what-is-the-claims-in-asp-net-identity
  https://www.codeproject.com/Articles/98950/ASP-NET-authentication-and-authorization

本文链接:http://www.cnblogs.com/selimsong/p/7828326.html

ASP.NET没有魔法——目录

ASP.NET没有魔法——ASP.NET Identity与授权的更多相关文章

  1. ASP.NET没有魔法——ASP.NET 身份验证与Identity

    前面的文章中为My Blog加入了文章的管理功能(ASP.NET没有魔法——ASP.NET MVC使用Area开发一个管理模块),但是管理功能应该只能由“作者”来访问,那么要如何控制用户的访问权限?也 ...

  2. ASP.NET没有魔法——ASP.NET Identity 的“多重”身份验证

    ASP.NET Identity除了提供基于Cookie的身份验证外,还提供了一些高级功能,如多次输入错误账户信息后会锁定用户禁止登录.集成第三方验证.账户的二次验证等,并且ASP.NET MVC的默 ...

  3. ASP.NET没有魔法——ASP.NET MVC 过滤器(Filter)

    上一篇文章介绍了使用Authorize特性实现了ASP.NET MVC中针对Controller或者Action的授权功能,实际上这个特性是MVC功能的一部分,被称为过滤器(Filter),它是一种面 ...

  4. ASP.NET没有魔法——ASP.NET MVC使用Oauth2.0实现身份验证

    随着软件的不断发展,出现了更多的身份验证使用场景,除了典型的服务器与客户端之间的身份验证外还有,如服务与服务之间的(如微服务架构).服务器与多种客户端的(如PC.移动.Web等),甚至还有需要以服务的 ...

  5. ASP.NET没有魔法——ASP.NET OAuth、jwt、OpenID Connect

    上一篇文章介绍了OAuth2.0以及如何使用.Net来实现基于OAuth的身份验证,本文是对上一篇文章的补充,主要是介绍OAuth与Jwt以及OpenID Connect之间的关系与区别. 本文主要内 ...

  6. ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(下篇)

    上一篇<ASP.NET没有魔法——ASP.NET MVC 模型绑定解析(上篇)>文章介绍了ASP.NET MVC模型绑定的相关组件和概念,本章将介绍Controller在执行时是如何通过这 ...

  7. ASP.NET没有魔法——ASP.NET MVC 与数据库大集合

    ASP.NET没有魔法——ASP.NET与数据库 ASP.NET没有魔法——ASP.NET MVC 与数据库之MySQL ASP.NET没有魔法——ASP.NET MVC 与数据库之ORM ASP.N ...

  8. ASP.NET没有魔法——ASP.NET MVC 路由的匹配与处理

    ASP.NET MVC的路由是MVC应用的一个核心也是MVC应用处理的入口,作为一个开发者,在正常情况下仅仅需要做的就是根据需求去定义实体.业务逻辑,然后在MVC的Controller中去调用.Vie ...

  9. ASP.NET没有魔法——ASP.NET MVC IoC

    之前的文章介绍了MVC如何通过ControllerFactory及ControllerActivator创建Controller,而Controller又是如何通过ControllerBase这个模板 ...

  10. ASP.NET没有魔法——ASP.NET MVC Razor与View渲染

    对于Web应用来说,它的界面是由浏览器根据HTML代码及其引用的相关资源进行渲染后展示给用户的结果,换句话说Web应用的界面呈现工作是由浏览器完成的,Web应用的原理是通过Http协议从服务器上获取到 ...

随机推荐

  1. 小程序的get和post请求头的区别

    小程序在使用wx.request()接口 时 header 请求头默认是这样的 wx.request({ url: 'test.php', //仅为示例,并非真实的接口地址 data: { x: '' ...

  2. 让asp.net网站支持多语言,使用资源文件

    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="test.aspx.cs&quo ...

  3. C# winform小票打印

    (1)自定义纸张设置 控制面板->打印机和传真->右键->服务器属性->创建新的格式 (2)自定义纸张使用 this.printDocument1.DefaultPageSet ...

  4. intellij idea 插件开发--快速定位到mybatis mapper文件中的sql

    intellij idea 提供了openApi,通过openApi我们可以自己开发插件,提高工作效率.这边直接贴个链接,可以搭个入门的demo:http://www.jianshu.com/p/24 ...

  5. JS实现时钟特效

    <!DOCTYPE html><html><head lang="en"><meta charset="UTF-8"& ...

  6. Java集合源码分析(一)ArrayList

    前言 在前面的学习集合中只是介绍了集合的相关用法,我们想要更深入的去了解集合那就要通过我们去分析它的源码来了解它.希望对集合有一个更进一步的理解! 既然是看源码那我们要怎么看一个类的源码呢?这里我推荐 ...

  7. FastDFS分布式文件系统

    FastDFS分布式文件系统 阅读目录 相关文章 1 分布式文件系统介绍 2 系统架构介绍 3 FastDFS性能方案 4 Linux基本命令操作 5 安装VirtualBox虚拟机并配置Ubuntu ...

  8. 微信小程序倒计时

    今天做程序要做个限时抢购的功能如图: 先上代码: 源码 index.wxml    可根据自己实际需求改改 <view class="div-content-warp"> ...

  9. Windows 10 快捷键汇总表格

    Windows 10 快捷键汇总表格 Windows 10 快捷键汇总 Win键 + Tab 激活任务视图 Win键 + A 激活操作中心 Win键 + C 通过语音激活Cortana Win键 + ...

  10. hibernate5使用注解遇到的问题

    问题描述 出现MappingException:Unknown entity,看到这个我以为在cfg配置文件中没有配置,实际上我是配置了的,那么问题出在那里呢,既然找不到实体,那么会不会是注解类出现了 ...