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

  上篇文章介绍了ASP.NET中身份验证的机制与流程,本文将使用代码的来介绍如何实现第三方账户验证与双因子验证。

  本章主要内容有:
  ● 实现基于微软账户的第三方身份验证
  ● 实现双因子身份验证
  ● 验证码机制

实现基于微软账户的第三方身份验证

  在微软提供的ASP.NET MVC模板代码中,默认添加了微软、Google、twitter以及Facebook的账户登录代码(虽然被注释了),另外针对国内的一些社交账户提供了相应的组件,所有组件都可以通过Nuget包管理器安装:

  

  从上图中看到有优酷、微信、QQ、微博等组件,其中一些是微软提供的,一些是其它开发者提供的。而本文将使用微软账户为例来介绍如何实现一个第三方登录。
  注:本章主要代码参考ASP.NET MVC模板代码,所以在文章中只列出关键代码,其余代码与模板中的完全一致。

组件安装及Key申请

  在开发之前首先需要通过Nuget安装Microsoft.Owin.Security.MicrosoftAccount:

  

  另外就是需要去微软的开发者中心使用微软账户创建一个自己的应用信息https://apps.dev.microsoft.com/,并保存应用的ID以及密钥用于对身份验证中间件进行配置:

  

  创建过程如下:
  1. 点击添加应用按钮,进入应用程序注册页面,填写应用名称并点击Create按钮(注:由于我已经有一个名称为My Blog的App,所以下面的Test App的创建流程仅仅是用于演示,后续的身份验证实际上是使用之前创建的My Blog):

  

  2. 在后续页面中点击生成新密码来生成密钥(注:该密码只显示一次,需要在弹出框中复制并保存下来):

  

  3. 添加平台:点击添加平台按钮,添加一个Web平台,并在平台的重定向Url中填入本地调试的地址信息(注:一定需要启动HTTPS并且地址后需要添加signin-microsoft,VS可以在项目的属性中开启SSL,并设置SSL的URL):

  

  

 

   4. 保存更改。

添加中间件

  在上一篇文章中介绍了,第三方账户身份验证除了特定账户身份验证中间件外,还需要添加一个消极模式的外部Cookie身份验证中间件,所以首先需要在项目的Startup文件中添加一下代码:

  

  然后再在该中间件后加入微软身份验证中间件(注:中间件顺序会影响处理流程,微软身份验证中间件必须在外部Cookie中间件后),并设置上面创建的应用ID及密钥:

  

添加Controller及页面的功能支持

  现在可以说应用中已经支持微软的账户身份验证了,但是在应用中还未提供微软身份验证的入口,以及登陆后用户信息的补全等功能。
  1. 在页面上添加验证入口,在Login页面上加入以下代码,通过AuthenticationManager来获取所有的第三方身份验证方式,并生成对应链接:

  

  

 2. 在AccountController中添加ExternalLogin Action方法(注:该方法主要目的是调用AuthenticationManager的Challenge方法来触发微软身份验证中间件的ResponseChallenge方法来完成页面的跳转):

   

  其中ChallengeResult是一个自定义的ASP.NET MVC Reuslt类型:

  

  3. 加入第三方验证后的回调方法ExternalLoginCallback,该回调方法是获取第三方身份验证后的用户信息,然后在本地数据库中查找该用户,如果存在那么登录成功,否则需要对该用户信息进行补全。

  

  4. 添加第三方账户信息补全页面及Action方法,其中action方法接收到补全的用户信息后完成用户注册功能,但要注意的是第三方账户没有密码,仅仅是在AspNetUserLogins表中添加了第三方验证的信息:

   

  运行结果:
  1.访问登录页面出现Microsoft的按钮(注:必须使用HTTPS地址才能正常的使用微软身份验证):

  

  2. 点击微软身份验证按钮后,跳转到微软账户登录页面:

  

  

  3. 完成登录后,由于是第一次登录,所以会跳转到信息补全页面:

  

  输入邮箱后将登录成功:

  

  数据库中的信息:

  

  上图中可以看到无密码,然后在Login表中有一条数据:

  

实现双因子身份验证

  Identity的双因子身份验证实际上是Identity的一个内置功能,为什么说是内置呢?因为只需要实现信息的发送(如邮件、短信等),然后再对Identity中的SignInManager进行简单的配置然后添加一些用于发送、填写验证码的页面就可以完成。所以首先需要完成的就是实现信息发送功能。
  注:这里信息发送功能使用将信息写到硬盘的方式模拟。
  1. 实现信息的发送:
  在ASP.NET MVC默认的模板中就为我们创建了如下代码:

   

  默认的邮件及短信发送器,只不过它没有实现,仅仅是返回了一个空值,现在使用写硬盘的方式将信息写到硬盘上:

   

  2. 完成UserManager的双因子验证配置:

  

  三个关键点:1. TokenProvider,它用来生成验证码。2. 信息格式。3. 信息发送服务。

  3. 在身份验证管道中加入双因子验证中间件:

  

  两个中间件前者用于处理二次验证,后者用于记住登录状态,下次访问系统时自动登录。

  4. 添加验证码发送方式选择以及验证码填写页面及相应的Action方法(代码略)。
  5. 在数据库中将演示用的用户信息改为启用二次验证(注:模板代码中有用于管理个人信息的功能,此处省略了实现,直接通过修改数据数据的方式开启用户的双因子验证、添加电话号码等):

  

  6. 运行结果:
  登录后需要选择验证码发送方式:

  

  选择后点击提交按钮,页面调整到验证页面的同时,指定的文件中生成了需要的验证码:

  

  

  填写验证码后点击提交按钮,则登录成功:

  

  

  注:双因子验证也可以应用到第三方账户的登录方式上,双因子验证只与用户有关与身份验证方式无关。

验证码机制

  对于双因子验证来说,它实际上就是在普通验证或第三方账户验证的基础上增加了验证码的发送和验证两个环节,那么对于验证码这个主体Identity是如何来维护的呢?
  在上面的介绍中,有一个环节就是需要通过对UserManager进行配置以支持双因子验证的消息发送、消息生成等等:

  

  根据这个代码看来XXXTokenProvider是专门用来维护验证码的,而XXXService是用来发送的,所以这里将对TokenProvider进行说明,了解验证码是如何维护的:

  

  上图是TokenProvider相关的一个简单类图,从类图中可以看出TokenProvider实际上是实现了一个名为IUserTokenProvider的接口,该接口中有4个方法,它们的作用分别是:
  ● GenerateAsync:根据UserManager以及User信息来生成一个令牌(Token)。
  ● IsValidProviderForUserAsync:判断这个Token提供器对这个用户是否是有效的(如果使用短信验证,但是该用户没有设置手机号,那么就是无效的)。
  ● NotifyAsync:当Token生成后调用该方法通知用户,如短信或邮件通知。
  ● ValidateAsync:用于验证Token是否有效。

  而TotpSecutityStampBasedTokenProvider是一个实现了IUserTokenProvider接口的,通过用户安全戳生成验证码的生成器:

  

  从代码中可以看到该算法是基于rfc6238(TOTP: Time-Based One-Time Password Algorithm,基于时间的一次性密码算法) https://tools.ietf.org/html/rfc6238,然后通过用户的安全戳以及GetUserModifierAsync方法生成特定的信息熵来完成密码加密,关于信息熵可参考:https://www.zhihu.com/question/22178202,上面将生成后的令牌执行ToString("D6")是将其转换为一个6位数字的字符串。
  而Token的验证方式和生成差不多都是通过用户安全戳和信息熵来验证提交的验证码(它实际上是一种hash算法):

  

  以上已经解释了最初验证码的生成和验证的问题,所以对于EmailTokenProvider和PhoneNumberTokenProvider只是对熵的生成、对Provider的有效性(是否存在Email或电话号码)、通知方式进行了修改,下面是PhoneNumberTokenProvider相关代码:

  

  

  

小结  

  本章主要是使用代码的形式实现了ASP.NET中的第三方验证和双因子验证,文中的代码都来自ASP.NET MVC的模板,所以文中仅仅是对关键的代码进行了介绍,一些细节的内容可参考完整代码。其中第三方验证使用的是微软账户,如果有环境支持可以尝试国内的微信、QQ等身份验证。
  另外在文章最后对验证码的生成和校验代码进行了分析,知道了它是基于Hash算法的信息加密、验证的机制来实现的。
ASP.NET MVC基于Identity提供了非常完善、强大的用户管理和身份验证功能,除了以上介绍的以外还有账户锁定、注册邮箱或短信验证功能,基本上已经涵盖了现在开发常用的功能,但这些功能被一个模板实现了,所以ASP.NET强大吗?

参考:

  https://www.zhihu.com/question/22178202
  https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/external-authentication-services
  https://www.benday.com/2014/02/25/walkthrough-asp-net-mvc-identity-with-microsoft-account-authentication/

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

ASP.NET没有魔法——目录

posted @ 2017-12-01 15:30  7m鱼  阅读(2614)  评论(16编辑  收藏