Identity登录原理 - Claims-based认证和OWIN

ASP.NET Identity登录原理

什么是Claims-based(基于声明)的认证

首先这个玩意不是微软特有的,Claims-based认证和授权在国外被广泛使用,包括微软的ADFS,Google,Facebook等。 国内我就不知道了,没有使用过国内的第三方登录,有集成过QQ登录或者支付宝登录的同学可以解释一下。

Claims-based认证主要解决的问题?

对比我们传统的Windows认证和Forms认证,claims-based认证这种方式将认证和授权与登录代码分开,将认证和授权拆分成另外的web服务。活生生的例子就是我们的qq集成登录,未必qq集成登录采用的是claims-based认证这种模式,但是这种场景,千真万确就非常适合claims-based认证。

Claims-based认证的主要特点:

  • 将认证与授权拆分成独立的服务
  • 服务调用者(一般是网站),不需要关注你如何去认证,你用Windows认证也好,用令牌手机短信也好,与我无关。
  • 如果用户成功登录的话,认证服务(假如是QQ) 会返回给我们一个令牌。
  • 令牌当中包含了服务调用者所需要的信息,用户名,以及角色信息等等。
      总的来说就是,我再也不用管你怎么登录,怎么样去拿你有哪些角色了,我只需要把你跳到那个登录站点上,然后它返回给我令牌信息,我从令牌上获取需要的信息来确定你是谁,你拥有什么角色就可以了。

进一步理解Claims-based 认证
为了让大家进一步理解Claims-based认证,我们从一个普通的登录场景开始说起,拿QQ集成登录来举例。

  1. 用户跑到我们的网站来访问一个需要登录的页面
  2. 我们的网站检测到用户没有登录,返回一个跳转到QQ登录页的响应(302 指向QQ登录页面的地址并加上一个返回的链接页面,通常是returnUrl=)
  3. 用户被跳转到指定QQ的登录页面
  4. 用户在QQ登录页面上输入用户名和密码,QQ会到自己的数据库中查询,一旦登录成功,会返回一个跳转到我们站点的响应(302指向我们的网站页面)
  5. 用户被跳转到我们网站的一个检测登录的页面,我们可以拿到用户的身份信息,建立ClaimsPrinpical和ClaimsIdentity对象,生成cookie等。
  6. 我们再把用户带到指定的页面,也就是returnUrl,那是用户登录前最后一次访问的页面
Identity登录原理 - Claims-based认证和OWIN_第1张图片

简单的来说,就是把登录的代码(验证用户,获取用户信息)拆分成独立的服务或组件

ASP.NET 下的 Claims-based认证实现

说完什么是Claims-based认证之后,我们接下来就可以看看ClaimsIdentity以及ClaimsPrincipal这两个类,他们是.NET下Claims-based认证的主要基石。当然正如我们所想,他们继承了接口IIdentity和IPrincipal。
IIdentity封装用户信息
这个接口很简单,它只包含了三个最基本的用户身份信息。

using System.Runtime.InteropServices;

namespace System.Security.Principal
{
    //
    // 摘要:
    //     定义标识对象的基本功能。
    [ComVisible(true)]
    public interface IIdentity
    {
        //
        // 摘要:
        //     获取所使用的身份验证的类型。
        //
        // 返回结果:
        //     用于标识用户的身份验证的类型。
        string AuthenticationType { get; }
        //
        // 摘要:
        //     获取一个值,该值指示是否验证了用户。
        //
        // 返回结果:
        //     如果用户已经过验证,则为 true;否则为 false。
        bool IsAuthenticated { get; }
        //
        // 摘要:
        //     获取当前用户的名称。
        //
        // 返回结果:
        //     用户名,代码当前即以该用户的名义运行。
        string Name { get; }
    }
}

IPrincipal 代表着一个安全上下文
这个安全上下文对象包含了上面的identity以及一些角色和组的信息,每一个线程都会关联一个Principal的对象,但是这个对象是属性进程或者AppDomain级别的。ASP.NET自带的 RoleProvider就是基于这个对象来实现的。

CalimsIdentity和ClaimsPrincipal
在System.Security.Claims命名空间下去,我们可以发现这两个对象。下面我们来做一个小例子,这个小例子会告诉我们这两个对象是如何进行认证和授权的。我们要做的demo很简单,建一个空的mvc站点,然后加上一个HomeController,和两个Action。并且给这个HomeController打上Authroize的标签,但是注意我们没有任何登录的代码,只有这个什么也没有的Controller和两个什么也没有的Action。

using System.Web.Mvc;

namespace WebApplication.Controllers
{
    [Authorize]
    public class HomeController : Controller
    {
        [Authorize(Roles ="Users")]
        public ActionResult Index()
        {
            ViewBag.Title = "Home Page";

            return View();
        }

        [Authorize(Roles = "Managers")]
        public ActionResult Manager()
        {
            return View();
        }
    }
}

当然,结果也是可想而知的,我们得到了401页面,因为我们没有登录。

Identity登录原理 - Claims-based认证和OWIN_第2张图片

下面我们就来实现登录,这里的登录非常简单,我们手动去创建这个ClaimsIdentity和ClaimsPrincipal对象,然后将Principal对象指给当前的HttpContext.Current.User。

protected void Application_AuthenticateRequest()
{
    var claims = new List();
    claims.Add(new Claim(ClaimTypes.Name, "Bobby"));
    claims.Add(new Claim(ClaimTypes.Role, "Users"));
    var identity = new ClaimsIdentity(claims, "MyClaimsLogin");

    ClaimsPrincipal principal = new ClaimsPrincipal(identity);
    HttpContext.Current.User = principal;
}

我们在Global.asax中添加了Application_AuthenticateRequest方法,也就是每次MVC要对用户进行认证的时候都会进到我们这个方法里面,然后我们就这样神奇的把用户给登录了。

Identity登录原理 - Claims-based认证和OWIN_第3张图片

Identity登录原理 - Claims-based认证和OWIN_第4张图片

当然,我们没有Home/Manager的访问权限,因为我们上面只给了用户Users的Role。

using System.Web.Mvc;

namespace WebApplication.Controllers
{
    [Authorize]
    public class HomeController : Controller
    {
        [Authorize(Roles ="Users")]
        public ActionResult Index()
        {
            var name = User.Identity.Name;
            var isAuthenticated = User.Identity.IsAuthenticated;
            ViewBag.Title = "Home Page";

            return View();
        }

        [Authorize(Roles = "Managers")]
        public ActionResult Manager()
        {
            return View();
        }
    }
}

现在大家知道ClaimsIdentity和ClaimsPrincipal是如何使用了么?这里要注意一下的是,我们没有设置IsAutheiticated为true,在.NET4.5以前,对于GenericIdentity只要设置它的Name的时候IsAutheiticated就自动设置为true了,而对于ClaimsIdentity是在它有了第一个Claim的时候。在.NET4.5以后,我们就可以灵活控制了,默认ClaimsIdentity的IsAutheiticated是false,只有当我们构造函数中指定Authentication Type,它才为true。
  最后结论,我们讲了ClaimsIdentity什么的,讲了这么多和今天的主题有嘛关系?我们上面说ASPNET Identity登录有三句话,第一句话可以略过,第二句话就是我们上面讲的。

到底什么是OWIN

首先我们来简单介绍一下OWin,它是由微软ASP.NET小组成员组织成立的一个开源项目。目标是解耦服务器和应用,这里面的服务器主要是指web 服务器,比如说IIS等,全称是Open Web Interface for .Net。OWin可以说是一套定义,默认它是没有什么具体的实现的,那么在它的定义里面是如何实现服务器与应用程序的解耦的呢? 我们又该如何理解服务器与应用程序的解耦呢?

参考资料

  • MVC5 - ASP.NET Identity登录原理 - Claims-based认证和OWIN

你可能感兴趣的:(Identity登录原理 - Claims-based认证和OWIN)