上篇文章介绍了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没有魔法——目录

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

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

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

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

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

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

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

  4. ASP.NET没有魔法——ASP.NET Identity的加密与解密

    前面文章介绍了如何使用Identity在ASP.NET MVC中实现用户的注册.登录以及身份验证.这些功能都是与用户信息安全相关的功能,数据安全的重要性永远放在第一位.那么对于注册和登录功能来说要把密 ...

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

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

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

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

  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这个模板 ...

随机推荐

  1. SimpleDateFormat时间格式化存在线程安全问题

    想必大家对SimpleDateFormat并不陌生.SimpleDateFormat 是 Java 中一个非常常用的类,该类用来对日期字符串进行解析和格式化输出,但如果使用不小心会导致非常微妙和难以调 ...

  2. LeetCode 292. Nim Game (取物游戏)

    You are playing the following Nim Game with your friend: There is a heap of stones on the table, eac ...

  3. Stack by pointer

    前言:因为栈的很多操作是基于表的,所以这篇文章里的例程就不再大面积地写注释了,有不理解的地方可以翻看之前的链表笔记,或者直接写在评论区. 咳咳,说到这个栈,很多人乍听之下感觉很陌生.卧槽这是什么玩意. ...

  4. Zernike不变矩

    1.Zernike矩介绍 Zernike矩是基于 Zernike多项式的正交化函数,所利用的正交多项式集是 1个在单位圆内的完备正交集.Zernike矩是复数矩 ,一般把 Zernike矩的模作为特征 ...

  5. 搭建Maven私服那点事

    摘要:本文主要介绍在CentOS7.1下使用nexus3.6.0搭建maven私服,以及maven私服的使用(将自己的Maven项目指定到私服地址.将第三方项目jar上传到私服供其他项目组使用) 一. ...

  6. 安装MongoDB启动时报错‘发生系统错误2’的解决办法

    安装数据库mongodb启动时报"发生系统错误2". 这个问题是如果你之前已经装过一次,并且两次安装目录不同,就绝对会碰到的,因为你之前安装的路径已经在注册表中生成了,并没有随着你 ...

  7. .Net 上传图片之前获取图片的宽高

    Stream st = Request.Files[0].InputStream;                  Byte[] buffer = new Byte[st.Length];      ...

  8. Postman参数化使用以及中文乱码问题解决

    1.参数化详解 准备工作,数据准备 2.使用csv文件时中文乱码可以通过使用txt文本,json文本改变调用json文件改变文件的编码格式解决 3:参数化数据调用的两种方式通过调用读取文件传入环境变量 ...

  9. ldap数据库--ODSEE--ACI

    查看跟DN下的aci ldapsearch -h hostname -p port -D "cn=Directory Manager" -w - -b "BASE_DN& ...

  10. hadoop的webUI查看Live Nodes为1

    开起了两个节点,而且jps查看确实开启了,但是用web端50070查看却一直显示为1 经过排查,将虚拟机直接copy一份,但是之前配置好hadoop环境的namenode格式化(format)生成的文 ...