Web APi之认证(Authentication)及授权(Authorization)【一】(十二)

前言

无论是ASP.NET MVC还是Web API框架,在从请求到响应这一过程中对于请求信息的认证以及认证成功过后对于访问页面的授权是极其重要的,用两节来重点来讲述这二者,这一节首先讲述一下关于这二者的一些基本信息,下一节将通过实战以及不同的实现方式来加深对这二者深刻的认识,希望此文对你有所收获。

Identity

Identity代表认证用户的身份,下面我们来看看此接口的定义

public interface IIdentity
{
    // Properties
    string AuthenticationType { get; }

    bool IsAuthenticated { get; }

    string Name {get; }
}

该接口定义了三个只读属性, AuthenticationType  代表认证身份所使用的类型, IsAuthenticated 代表是否已经通过认证, Name 代表身份的名称。对于AuthenticationType认证身份类型,不同的认证身份类型对应不同的Identity,若采用Windows集成认证,则其Identity为WindowsIdentity,反之对于Form表单认证,则其Identity为FormsIdentity,除却这二者之外,我们还能利用GenericIdentity对象来表示一般意义的Identity。

  • WindowsIdentity

在WindowIdentity对象中的属性Groups返回Windows账号所在的用户组,而属性IsGuest则用于判断此账号是否位于Guest用户组中,最后还有一个IsSystem属性很显然表示该账号是否是一个系统账号。在对于匿名登录中,该对象有一个IsAnonymous来表示该账号是否是一个匿名账号。并且其方法中有一个GetAnonymous方法来返回一个匿名对象的WindowsIdentity对象,但是此WindowsIdentity仅仅只是一个空对象,无法确定对应的Windows账号。

  • FormsIdentity

我们来看看此对象的定义

    public class FormsIdentity : ClaimsIdentity
    {

        public FormsIdentity(FormsAuthenticationTicket ticket);

        protected FormsIdentity(FormsIdentity identity);

        public override string AuthenticationType { get; }

        public override IEnumerable<Claim> Claims { get; }

        public override bool IsAuthenticated { get; }

        public override string Name { get; }

        public FormsAuthenticationTicket Ticket { get; }

        public override ClaimsIdentity Clone();
    }

一个FormsIdentity对象是通过加密过的认证票据(Authentication Ticket)或者是安全令牌(Security Token)来创建,被加密的内容或者是Cookie或者是请求的URl,下述就是通过FormsIdentity来对Cookie进行加密。  

var ticket = new FormsAuthenticationTicket(1, "cookie", DateTime.Now, DateTime.Now.AddMinutes(20), true, "userData", FormsAuthentication.FormsCookiePath);

var encriptData = FormsAuthentication.Encrypt(ticket);
  • GenericIdentity

以上两者都有其对应的Identity类型,如果想自定义认证方式只需继承该类即可,它表示一般性的安全身份。该类继承于IIdentity接口。至于如何判断一个匿名身份只需通过用户名即可,若用户名为空则对象的属性IsAuthenticated为true,否则为false。

Principal  

这个对象包含两个基本的要素即基于用户的安全身份以及用户所具有的权限,而授权即所谓的权限都是基于角色而绑定,所以可以将此对象描述为:【身份】+【角色】。

首先我们来看看此接口

public interface IPrincipal
{

    bool IsInRole(string role);

    IIdentity Identity { get; }
}

上述基于IIdentity接口的实现即WindowsIdentity和GenericIdentity,当然也就对应着Principal类型即WindowsPrincipal和GenericPrincipal,除此之外还有RolePrincipal,关于这三者就不再叙述,我们重点来看看下APiController中的IPrincipal属性。

APiController中User

我们看看此User属性

public IPrincipal User { get; }

继续看看此属性的获取

public IPrincipal User
{
    get
    {
        return Thread.CurrentPrincipal;
    }
}

到这里还是不能看出什么,即使你用VS编译器查看也不能查看出什么,此时就得看官方的源码了。如下:

        public HttpRequestContext RequestContext
        {
            get
            {
                return ControllerContext.RequestContext;
            }
            set
            {......}
        }

        public IPrincipal User
        {
            get { return RequestContext.Principal; }
            set { RequestContext.Principal = value; }
        }

到这里我们看出一点眉目了

IPrincipal的属性User显然为当前请求的用户并且与HttpRequestContext中的属性Principal具有相同的引用。  

那么问题来了,HttpRequestContext又是来源于哪里呢?  

我们知道寄宿模式有两种,一者是Web Host,另一者是Self Host,所以根据寄宿模式的不同则请求上下文就不同,我们来看看Web Host中的请求上下文。

  • Web Host
    internal class WebHostHttpRequestContext : HttpRequestContext
    {
        private readonly HttpContextBase _contextBase;
        private readonly HttpRequestBase _requestBase;
        private readonly HttpRequestMessage _request;

        public override IPrincipal Principal
        {
            get
            {
                return _contextBase.User;
            }
            set
            {
                _contextBase.User = value;
                Thread.CurrentPrincipal = value;
            }
        }
   }

从这里我们可以得出一个结论:

Web Host模式下的Principal与当前请求上下文中的User具有相同的引用,与此同时,当我们将属性Principal进行修改时,则当前线程的Principal也会一同进行修改。  

  • Self Host  

我们看看在此寄宿模式下的对于Principal的实现

    internal class SelfHostHttpRequestContext : HttpRequestContext
    {
        private readonly RequestContext _requestContext;
        private readonly HttpRequestMessage _request;

         public override IPrincipal Principal
        {
            get
            {
                return Thread.CurrentPrincipal;
            }
            set
            {
                Thread.CurrentPrincipal = value;
            }
        }

    }

在此模式我们可以得出结论:

Self Host模式下的Principal默认是返回当前线程使用的Principal。  

接下来我们来看看认证(Authentication)以及授权(Authorization)。

AuthenticationFilter 

AuthenticationFilter是第一个执行过滤器Filter,因为任何发送到服务器请求Action方法首先得认证其身份,而认证成功后的授权即Authorization当然也就在此过滤器之后了,它被MVC5和Web API 2.0所支持。下面用一张图片来说明这二者在管道中的位置及关系

  

接下来我们首先来看看第一个过滤器AuthenticationFilter的接口IAuthenticationFilter的定义:

    public interface IAuthenticationFilter : IFilter
    {

        Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken);

        Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken);
    }

该接口定义了两个方法,一个是 AuthenticateAsync ,它主要认证用户的凭证。另一个则是 ChallengeAsync ,它主要针对于在认证失败的情况下,向客户端发送一个质询(Chanllenge)。

 

以上两者关于认证的方法都分别对应定义在Http协议的RFC2612以及RFC2617中,并且两者都是基于以下两点:

  • 如果客户端没有发送任何凭证到服务器,那么将返回一个401(unauthorized)响应到客户端,在返回到客户端的响应中包括一个WWW-Authenticate头,在这个头中包含一个或多个质询,并且每个质询将指定被服务器识别的认证组合。

  • 在从服务器响应返回一个401到客户端后,客户端将在认证头里发送所有的凭证。  

下面我们详细查看每个方法的内容:

AuthenticateAsync

此方法中的参数类型为HttpAuthenticationContext,表示为认证上下文,我们看看此类的实现

    public class HttpAuthenticationContext
    {

        public HttpAuthenticationContext(HttpActionContext actionContext, IPrincipal principal)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException("actionContext");
            }

            ActionContext = actionContext;
            Principal = principal;
        }

        public HttpActionContext ActionContext { get; private set; }

        public IPrincipal Principal { get; set; }

        public IHttpActionResult ErrorResult { get; set; }

        public HttpRequestMessage Request
        {
            get
            {
                Contract.Assert(ActionContext != null);
                return ActionContext.Request;
            }
        }
    }

在构造函数中通过Action上下文和认证的用户的Principal属性进行初始化,而属性ErrorResult则返回一个HttpActionResult对象,它是在认证失败的情况直接将错误消息返回给客户端。我们应该能想到请求到Action方法上的AuthenticationFilter可能不止一个,此时Web API会通过FilterScope进行排序而形成一个AuthenticationFilter管道,紧接着认证上下文会通过当前的Action请求上下文以及通过APiController的User属性返回的Principal而被创建,最终认证上下文会作为AuthenticationFilter中的AuthenticateAsync方法的参数并进行调用。  

当执行为AuthenticateAsync方法被成功执行并返回一个具体的HttpActionResult,此时后续操作将终止,接下来进入第二个方法即【发送认证质询】阶段。

ChallengeAsync  

绝大多数认证基本上都是采用【质询-应答】方式,服务器向端客户端发出质询要求来提供凭证,若客户端在执行AuthenticateAsync方法后,认证未成功,此时服务器端将通过ChallengeAsync方法发送认证质询。

接下来我们来看看此方法的具体实现

    public class HttpAuthenticationChallengeContext
    {
        private IHttpActionResult _result;

        public HttpAuthenticationChallengeContext(HttpActionContext actionContext, IHttpActionResult result)
        {
            if (actionContext == null)
            {
                throw new ArgumentNullException("actionContext");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            ActionContext = actionContext;
            Result = result;
        }

        public HttpActionContext ActionContext { get; private set; }

        public IHttpActionResult Result
        {
            get
            {
                return _result;
            }
            set
            {
                if (value == null)
                {
                    throw new ArgumentNullException("value");
                }

                _result = value;
            }
        }

        public HttpRequestMessage Request
        {
            get
            {
                Contract.Assert(ActionContext != null);
                return ActionContext.Request;
            }
        }
    }

很显然,当调用AuthenticateAsync方法完成认证工作后,此时ErrorResult将返回一个具体的HttpActionResult,然会将Action上下文以及具体的HttpActionResult传递到构造函数中进行初始化HttpAuthenticationChallgeContext,最后依次调用ChallengeAsync方法,当此方法都被执行后,此类中的Result属性也就返回一个具体的HttpActionResult对象,此对象将创建相应的HttpResponseMessage对象,并回传到消息处理管道中并作出响应从而发出认证质询。  

总结 

(1)在Web API中使用AuthenticationFilter进行认证主要是以下三步

  • Web API会为每个需要被调用Action方法创建所有可能的AuthenticationFilter列表,若有多个则通过FilterScope来进行排序,最终形成AuthenticationFilter管道。

  •  Web API将为AuthenticationFilter管道中的每一个过滤器依次调用AuthenticateAsync方法,在此方法中每个AuthenticationFilter将验证来自客户端的Http请求凭证,即使在认证过程中触发到了错误,此时进程也不会终止。

  • 若认证成功,Web API将调用每个AuthenticationFilter的ChallengeAsync方法,接下来每一个AuthenticationFilter将通过此方法做出质询响应。

(2)通过上述描述我们用三张示意图来对照着看

 

认证方案

我们知道Http协议中的认证方案有两种,一种是Basic基础认证,一种是Digest摘要认证

Basic基础认证

此认证是在客户端将用户名和密码以冒号的形式并用Base64明文编码的方式进行发送,但是不太安全,因为未被加密,在此基础上采用Https信息通道加密则是不错的认证方案。

Digest摘要认证

此认证可谓是Basic基础认证的升级版,默认是采用MD5加密的方式,在一定程度上算是比较安全的,其执行流程和Basic基础认证一样,只是生成的算法不同而已。

未完待续:接下来将通过认证方案手动通过不同的方式来实现认证。。。。。。

  

时间: 2024-08-01 21:50:33

Web APi之认证(Authentication)及授权(Authorization)【一】(十二)的相关文章

.net中的认证(authentication)与授权(authorization)

注:这篇文章主要给新手看的,老手们可能会觉得没啥营养,就请绕过吧.   "认证"与"授权"是几乎所有系统中都会涉及的概念,通俗点讲:   认证(authentication) 就是 "判断用户有没有登录?",好比windows系统,没登录就无法使用(不管你是用Administrator或Guest用户,总之要先正确登录后,才能进入系统). 授权(authorization) 就是"用户登录后的身份/角色识别",好比"

FluorineFx.NET的认证(Authentication )与授权(Authorization)Flex与.NET互操作 九_Flex

应用程序可根据用户信息授予和拒绝执行.FluorineFx.NET的认证和授权使用.Net Framework基于角色的安全性的支持. 比如说我们需要自定义一个认证与授权的方案,指定那些远程服务上的那些方法将要被认证或授权以及授权用户角色组等,我们就需要自定义一个 LoginCommand并实现ILoginCommand接口或者继承于 FluorineFx.Security.GenericLoginCommand(此类实现了ILoginCommand接口)基类.接口定义如下:  1 namesp

Web APi之认证(Authentication)两种实现方式后续【三】(十五)

前言 之前一直在找工作中,过程也是令人着实的心塞,最后还是稳定了下来,博客也停止更新快一个月了,学如逆水行舟,不进则退,之前学的东西没怎么用,也忘记了一点,不过至少由于是切身研究,本质以及原理上的脉络还是知其所以然,所以也无关紧要,停止学习以及分享是一件很痛苦的事情,心情很忐忑也很担忧,那么多牛逼的人都在无时无刻的学习更何况是略懂皮毛的我呢?好了,废话说了不少,我们接下来进入主题. 话题 看到博客也有对于我最近有关Web APi中认证这篇文章的评论和疑问,[其中就有一个是何时清除用户的信息呢],

Web APi之认证(Authentication)两种实现方式【二】(十三)

前言 上一节我们详细讲解了认证及其基本信息,这一节我们通过两种不同方式来实现认证,并且分析如何合理的利用这两种方式,文中涉及到的基础知识,请参看上一篇文中,就不再叙述废话. 序言 对于所谓的认证说到底就是安全问题,在Web API中有多种方式来实现安全,[accepted]方式来处理基于IIS的安全(通过上节提到的WindowsIdentity依赖于HttpContext和IIS认证)或者在Web API里通过使用Web API中的消息处理机制,但是如果我们想应用程序运行在IIS之外此时Wind

Web APi入门之Self-Host寄宿及路由原理(二)

前言 刚开始表面上感觉Web API内容似乎没什么,也就是返回JSON数据,事实上远非我所想,不去研究不知道,其中的水还是比较深,那又如何,一步一个脚印来学习都将迎刃而解. Self-Host 我们知道Web API它可以快速为HTTP客户端提供API来创建Web服务,为何如此这样说呢?因为我们可以将其作为主机也就是一个服务器来用完全不需要IIS,这就是我们下面要讲的第一个内容Self-Host,实现对Web API寄宿的方式有多种并且都是独立于ASP.NET框架之外,如下Self-Host寄宿

ASP.NET Web API自身对CORS的支持: CORS授权检验的实施

通过<EnableCorsAttribute特性背后的故事>我们知道:由CorsPolicyProvider提供的CorsPolicy表示目标Action采用的资源授权策略,ASP.NET Web API最终需要利用它对具体的跨域资源请求实施授权检验并生成相应的CORS响应报头.在ASP.NET Web API的应用编程接口中,资源授权检验的结果通过类型CorsResult来表示. 一.CorsResult CorsResult定义在命名空间"System.Web.Cors"

【转】ASP.NET WEB API系列教程

from: 西瓜小强 http://www.cnblogs.com/risk/category/406988.html    ASP.NET Web API教程(六) 安全与身份认证 摘要: 在实际的项目应用中,很多时候都需要保证数据的安全和可靠,如何来保证数据的安全呢?做法有很多,最常见的就是进行身份验证.验证通过,根据验证过的身份给与对应访问权限.同在Web Api中如何实现身份认证呢?接下来的内容就详细的分享 Web API身份认证.首先扩展自定义身份验证添加类 CustomA...阅读全

Web API应用架构在Winform混合框架中的应用(1)

在<Web API应用架构设计分析(1)>和<Web API应用架构设计分析(2)>中对WebAPI的架构进行了一定的剖析,在当今移动优先的口号下,传统平台都纷纷开发了属于自己的Web API平台,方便各种终端系统的接入,很多企业的需求都是以Web API优先的理念来设计整个企业应用体系的.Web API作为整个纽带的核心,在整个核心层需要考虑到统一性.稳定性.以及安全性等方面因素.本文主要介绍,Web API应用架构,在Winform整合中的角色,以及如何实现在Winform混合

ASP.NET Web API路由系统:路由系统的几个核心类型

虽然ASP.NET Web API框架采用与ASP.NET MVC框架类似的管道式设计,但是ASP.NET Web API管道的核心部分(定义在程序集System.Web.Http.dll中)已经移除了对System.Web.dll程序集的依赖,实现在ASP.NET Web API框架中的URL路由系统亦是如此.也就是说,ASP.NET Web API核心框架的URL路由系统与ASP.NET本身的路由系统是相对独立的.但是当我们采用基于Web Host的方式(定义在程序集System.Web.H