ASP.NET MVC使用Oauth2.0实现身份验证

 随着软件的不断发展,出现了更多的身份验证使用场景,除了典型的服务器与客户端之间的身份验证外还有,如服务与服务之间的(如微服务架构)、服务器与多种客户端的(如PC、移动、Web等),甚至还有需要以服务的形式开放给第三方的,身份验证这一功能已经演化为一个服务,很多大型应用中都有自己的身份验证服务器甚至集群,所以普通的身份验证方式已经不能满足需求。

  在.Net领域中也有一些开源的身份验证服务器组件,如IdentityServer(http://identityserver.io/),但是这些组件对于一些规模较小的项目来说可能会感觉到比较庞大,增加了学习和维护成本,所以本章将对OAuth以及如何使用OAuth实现身份验证模式进行介绍。
  本章的主要内容有:

  ● OAuth2.0简介
   ● 在.Net中使用OAuth实现基于授权码模式的身份验证
   ● 实现基于Access Token的身份验证
   ● 加入Refresh Token支持
   ● 实现通过用户密码模式获取Access Token
   ● 实现客户端模式获取Access Token
   ● 关于.Net中OAuth相关令牌的加密说明

  注:本章内容源码下载:https://files.cnblogs.com/files/selimsong/OAuth2Demo.zip

OAuth2.0简介

  在文章的开始的时候说过现代软件应用的身份验证场景越来越丰富,下图是现代应用程序的一个通信图,它描述了常见的“客户端”是如何与服务器提供的服务通信的。

  

  该图出自IdentityServer:https://identityserver4.readthedocs.io/en/release/intro/big_picture.html
  为了满足这些场景人们制定了一套标准协议,这个协议就是OAuth(Open Authorization,开放授权)协议,OAuth能够让第三方应用程序去访问受限制的HTTP服务。OAuth有两个版本分别是1.0和2.0,但是由于1.0版本过于复杂所以1.0版本被2.0版本替换了,并且两个版本是不兼容的。
  接下来就对OAuth2.0相关的概念进行介绍:

1. OAuth2.0中的角色

  ● Resource Owner:资源拥有者,就是能够访问被限制资源的用户(注:这里的用户是个泛指,它既可以是真实用户也可以是服务程序)。
   ● Resource Server:资源宿主,能够接受和处理,使用访问令牌(access token)访问受保护资源的请求(如提供API的服务器)。
   ● Client:它泛指所有的第三方程序(无论是Web应用、桌面应用还是服务端应用),它通过资源拥有者以及它的授权来访问受保护的资源。
   ● Authorization Server:用来对授权成功的客户端发布令牌以及对令牌的验证授权。并对Client进行管理。

2.OAuth2.0的协议流程

  

  A. 第三方程序向资源拥有者(用户)发送授权请求,这个过程既可以通过客户端直接向用户请求,也可以通过授权服务器作为中介来完成请求。(注:对于授权请求这个概念相当于用户登录,应用程序可以直接显示一个登录页面,也可以跳转到验证服务器的统一登录页面
  B. 用户将授权相关信息“提交”给第三方程序,在OAuth中有4种不同的权限授予方式,每种方式需要的数据不同,如基于用户密码的授权方式就需要用户名和密码。
  C. 第三方程序将用户的授权信息提交到授权服务器,请求一个Access Token。
  D. 授权服务器验证完成用户的授权信息后,将Access Token发放到第三方程序。
  E. 第三方程序携带Access Token访问被保护的资源。
  F. 资源服务器验证Access Token有效后,将资源返回到第三方程序。

3. OAuth中的授权模式(即获取Access Token的方式)

  ● Authorization Code(授权码模式):该模式的核心是客户端通过一个授权码来向授权服务器申请Access Token。是一种基于重定向的授权模式,授权服务器作为用户和第三方应用(Client)的中介,当用户访问第三方应用是,第三方应用跳转到授权服务器引导用户完成身份验证,生成Authorization Code并转交到第三方应用,以便于第三方应用根据这个授权码完成后续的Access Token获取。
   ● Implicit(简化模式):简化模式是一种简化的授权码模式,授权码模式在首次访问第三方应用时跳转到授权服务器进行身份验证返回授权码,而简化模式在跳转到授权服务器后直接返回Access Token,这种模式减少了获取Access Token的请求次数。
   ● Resource Owner Password Credentials(用户密码模式):通过资源拥有者(用户)的用户名和密码来直接获取Access Token的一种方法,这种方法要求第三方应用(Client)是高度可信任的,并且其它授权方式不可用的情况下使用。
   ● Client Credentials(客户端模式):该模式是通过第三方应用(Client)发送一个自己的凭证到授权服务器获得Access Token,这种模式的使用要求该Client已经被授权服务器管理并限制其对被保护资源的访问范围。另外这种模式下Client应该就是一个资源拥有者(用户),如微服务程序。

4. Access Token & Refresh Token

  这个很好理解,第三方应用通过Access Token去获取受保护的资源,但是Access Token是存在有效期的,一旦过期就无法使用,为了避免Access Token过期后无法使用,所以加入了Refresh Token的概念,通过刷新的方式来完成Access Token的更新。

5. Client的注册

  在OAuth2.0中,所有需要访问受限资源的程序都视为第三方应用(Client),为了保证这个Client是安全的、可信任的,所以OAuth需要对Client进行管理。参考:https://tools.ietf.org/html/rfc6749#section-2

6. OAuth的终结点

  这里终结点代表的是HTTP资源,在OAuth授权过程中需要使用到一些终结点的支持,如Authorization code(授权码)的获取,以及Access Token的获取,终结点由授权服务器提供。参考:https://tools.ietf.org/html/rfc6749#section-3

7. Access Token Type

  Access Token的类型是让Client根据具体类型来使用Access Token完成对受保护资源的请求。
  OAuth2.0中有两种类型分别是Bearer和Mac,它们体现方式如下:
   ● Bearer:

  

    ● Mac:

  

  参考:https://tools.ietf.org/html/rfc6750

在.Net中使用OAuth实现基于授权码模式的身份验证

  OAuth2.0是一个开放标准,既然是标准那么就可以有实现,在.Net中微软基于Owin实现了OAuth2.0协议,下面就介绍如何在ASP.NET MVC程序中实现OAuth身份验证。
  注:本例基于ASP.NET MVC默认带身份验证模板完成。

1. 组件安装

  通过NuGet安装Microsoft.Owin.Security.OAuth组件:

  

  注:从该组件的名称可以看出,.Net对OAuth的实现实际上是基于Owin的,所以很多内容均使用Owin中相关的身份验证概念,这些内容可参考本系列与身份验证的文章。

2. 添加OAuth授权服务器

  根据上面OAuth的介绍可知,授权服务器是OAuth其中一个角色,该角色最主要的功能就是Access Token的发放以及授权,另外它还用于支持授权码模式的授权码发放以及Client的管理
  在Startup类型的Configuration方法中加入以下代码,该代码是为Owin中间件添加一个授权服务器(注:该中间件是一个Owin的身份验证中间件可参考《ASP.NET没有魔法——ASP.NET Identity 的“多重”身份验证)。

  

  其中OAuthAuthorizationServerOptions定义如下:

  

  上面的定义可以分为以下几类:
   ● 终结点地址:AuthorizeEndpointPath、TokenEndpointPath等,它定义了访问获取授权码以及获取Token的地址信息。
   ● Token提供器:AuthorizationCodeProvider、AccessTokenProvider、RefreshTokenProvider负责完成对应令牌的创建和处理功能。
   ● Token的“加密”与“解密”:该功能是OAuth与Owin身份验证的结合,通过AccessTokenFormat等ISecureDataFormat接口的实现可以将对应的Token转换成一个  AuthenticationTicket。可参考《ASP.NET没有魔法——ASP.NET Identity的加密与解密》文中TicketDataFormat的用法。
   ● OAuth授权服务:Provider是整个OAuth服务器的核心,它包含了终结点的处理与响应、OAuth中的4种Access Token授权方式刷新令牌获取Access Token的方式以及请求、客户端的相关验证

  

3. 为授权服务器添加终结点

  上面介绍OAuth时介绍了终结点实际上就是用来获取授权码或者Access Token的,在.Net中使用Microsoft.Owin.Security.OAuth组件仅需要通过配置的形式就可以指定授权码及Token获取的终结点访问地址(注:把AllowInsecureHttp配置属性设为true,可以允许不安全的http来访问终结点,该配置仅用于开发环境):

  

  完成后就可以通过浏览器访问这两个地址:

  

  

  可以看到是可以访问,只不过是有错误的(注:请求地址的QueryString的参数参考文档)。

4. Client的管理与验证

   Client在OAuth中指代了所有的第三方需要访问受限制资源的应用程序,授权服务器为了能够识别和验证Client所以需要完成Client的管理以及验证功能。(注:微软在Microsoft.Owin.Security.OAuth组件中仅仅提供了Client验证的接口,所以要自己实现Client数据的管理以及验证逻辑):

  1). 添加Client实体以及对应的仓储(本例以内存的方式实现仓储,实际使用中至少应该保存数据库):

  

  上图是Client最基础的属性(注:如果还需要对Client的访问范围进行限制,那么还应该加入一个Scope的列表,本例不再加入Scope的限制)。

  2). Client的仓储:

  

  3). 实现授权服务器对Client的验证:

  由于授权服务器对客户端验证的接口位于OAuthAuthorizationServerProvider类型中,所以首先要继承该类型,并重载相应的验证方法:

  

  上面代码做了以下几件事:
   ● 尝试从Http请求header或者请求body中获取Client信息,包含Id和密码。
   ● 如果没有Client的Id信息,那么直接判断为不通过验证,如果有Client的密码信息则保存到Owin上下文中,供后续处理使用。
   ● 使用获得的ClientId在Client仓储中查询,判断是否是一个合法的Client,如不是则判断为不通过验证。

  4). 验证完成后设置该Client的重定向Url(注:该方法仍旧是重载OAuthAuthorizationServerProvider类型中的方法):

  

5. 添加授权码提供器

  授权码的生成是授权服务器终结点的一项功能,当使用授权码模式时用户访问Client会被引导跳转到授权服务器完成身份验证(登录),随后又携带授权码跳转回Client,Client使用该授权码获取Access Token。在OAuth的.Net实现中,需要通过在配置中配置一个类型为IAuthenticationTokenProvider的令牌提供器,该提供器用于创建解析令牌,这里的创建实际就是用户完成登录后授权码的生成以及授权码和用户登录身份信息的关联,而解析实际就是根据授权码获得对应用户身份信息并生成Access Token的过程。

  下面就通过实现IAuthenticationTokenProvider的方式实现一个自定义授权码提供器:

  

  从上面代码可以看出这个提供器的核心功能是以Guid的方式生成一个键值(授权码)保存了当前用户的信息,当解析时通过该键值(即授权码)获取用户身份信息。(注:AuthenticationTokenCreateContext对象用于对当前用户身份信息AuthenticationTicket对的的序列化和反序列化)

  完成后将该提供器配置到授权服务器中间件中:

  

6. 为授权服务器添加用户授权提示页面

  当用户访问授权码终结点时理应让用户知道Client需要他的授权,为此在ASP.NET MVC程序中需要添加一个路由与授权码终结点地址匹配的Controller、Action以及View:

  1). Controller及Action(注:该Action需要通过身份验证,如果没有需要跳转到登录页面完成身份验证后才可访问):

  

  2). View:显示授权提示

  

7. 运行程序

  1). 访问授权码终结点获取授权码:http://localhost:59273/oauth2/authorize?response_type=code&client_id=test1

  由于没有登录,所以先跳转到登录页面。

  

  完成登录后跳转回授权页面:

  

  点击授权按钮后,携带授权码跳转到test1这个client的重定向Url(注:此处test1这个Client设置的Url就是授权服务器本身,所以看上去没有做重定向)

  

  得到授权码后,携带授权码访问Access Token终结点获取Access Token(注:这里使用Chrome浏览器的Postman拓展来实现请求的模拟):

  

  注:上面响应信息中的access_token包含了加密后用户的身份信息,其加密过程可参考基于Cookie的用户信息加密过程。ASP.NET没有魔法——ASP.NET Identity的加密与解密

实现基于Access Token的身份验证

  上面介绍了如何基于授权码模式获得Access Token,接下来将介绍如何使用Access Token来访问受限制的资源(注:本例中的资源服务器与授权服务器位于同一实例中,所以当资源服务器对access token解密时,能够保证与授权服务器用于生成access token所用密钥一致,能够正常解密,这里的Access Token和基于Cookie的身份验证中的身份验证Cookie性质是相同的,都是将用户的身份信息序列化后的加密字符串)

  1. 在Startup类中添加基于Bearer的OAuth身份验证中间件:

  

  2. 添加访问受限制的资源:

  

  3. 访问受限资源:

  未添加授权信息直接跳转到登录页面。

  

  添加Access Token后可正常访问资源:

  

加入Refresh Token支持

  上面使用授权码模式生成的Access Token是存在过期时间的(实际上无论什么方式生成的Access Token都存在过期时间),Token过期后又不可能让用户再授权一次,所以需要使用Refresh Token来定期刷新Access Token,.Net中实现Refresh Token的方式与授权码类似,在生成Refresh Token的同时会关联用户的身份信息,后续可以使用这个Refresh Token来生成新的Access Token。

  1. 创建Refresh Token提供器(实现方式与授权码提供器基本一致):

  

   2. 为授权服务器配置Refresh Token提供器:

  

  3. 再次获取到授权码后,根据该授权码获取Access Token,返回信息中将携带Refresh Token:

  

  4. 根据Refresh Token刷新Access Token:

  

实现通过用户密码模式获取Access Token

  上面介绍了授权码模式的实现方式,但这种方式的核心实际上是建立了一个授权码和用户信息的映射(包括刷新令牌方式也是建立了刷新令牌与用户信息的映射),后续的Access Token实际上是使用这个了用户信息生成的。换句话用户信息才是核心,.Net中用户信息的体现从底到高分别是:IIdentity->ClaimsIdentity-> AuthenticationTicket,关于用户的身份信息可参考:《ASP.NET没有魔法——ASP.NET Identity与授权》,在基于授权码的模式时通过在授权服务器的登录功能获得了用户信息,而基于用户名密码模式时没有这个跳转登录环节,所以需要直接通过用户名密码来获取用户信息,其实现如下重载了OAuthAuthorizationServerProvider类型的GrantResourceOwnerCredentials方法:

  

  该方法从Owin环境中获取Identity中的UserManager对象,通过UserManager来验证用户是否存在,如果存在则将使用用户信息来创建一个ClaimsIdentity对象(注:此处是省略的实现,正常实现可根据需求参考Cookie验证方式将Scope或者Role等信息也添加到Identity对象中)。另UserManager是通过以下代码添加到Owin上下文中的,它的Key值是"AspNet.Identity.Owin:" + typeof(ApplicationUserManager).AssemblyQualifiedName。

  

  使用用户名密码获取Access Token:

  

实现客户端模式获取Access Token

  客户端模式和用户名密码模式是类似的,它是通过Client的Id以及密码来进行授权,使用的是Client相关的信息,它的实现方式如下,重载GrantClientCredentials方法,通过客户端验证后的id和密码信息来验证改Client是否合法,对于合法的Client为其创建Identity对象(注:此处可以根据实际需求在Identity中添加相应的属性):

  

  使用Client信息获取Access Token:

  

  以上就是.Net中对于OAuth的实现,另外.Net中没有提供简化模式的接口,但是提供了一个GrantCustomExtension,也就是说授权模式是可拓展的。

关于.Net中OAuth相关令牌的加密说明

  本例中除了授权码以及刷新令牌是2个Guid连接外,访问令牌(包括所有授权模式生成的令牌)以及授权码对应的用户信息、刷新令牌对应的用户信息都是经过加密的,其加解密对象创建过程如下,具体内容可参考《ASP.NET没有魔法——ASP.NET Identity的加密与解密》

  

小结

  本章内容介绍了OAuth2.0协议相关的内容,并通过一个ASP.NET MVC程序基于微软的Microsoft.Owin.Security.OAuth组件实现了该协议中的大部分功能。使用OAuth来实现身份验证可以让我们的应用程序从Web拓展至任意的平台上运行,但这样的实现仍旧是存在一些问题的,在下一篇文章中将对这些问题进一步的讨论和介绍。

PS.这一章内容比较多,如有问题可以在评论区留言,另外最近事情比较多,所以更新慢了,感谢大家的支持。

参考:

  https://stackoverflow.com/questions/39909419/jwt-vs-oauth-authentication
  http://www.cnblogs.com/linianhui/p/oauth2-authorization.html
  http://www.c-sharpcorner.com/UploadFile/4b0136/openid-connect-availability-in-owin-security-components/
  https://docs.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server
  https://security.stackexchange.com/questions/94995/oauth-2-vs-openid-connect-to-secure-api
  http://bitoftech.net/2014/07/16/enable-oauth-refresh-tokens-angularjs-app-using-asp-net-web-api-2-owin/


原文:http://www.cnblogs.com/selimsong/p/8037717.html 


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/322560.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot API 接口文档 Swagger 入门

转载自 芋道 Spring Boot API 接口文档 Swagger 入门 摘要: 原创出处 http://www.iocoder.cn/Spring-Boot/Swagger/ 「芋道源码」欢迎转载,保留摘要,谢谢! 本文在提供完整代码示例,可见 https://github.com/YunaiV/SpringBoot-Lab…

ICanPay 统一支付网关

https://github.com/hiihellox10/ICanPay 统一支付网关。对原代码优化。支持NET46和NETSTANDARD2_0。支持支付宝,微信,银联支付渠道通过Web,App,Wap,QRCode方式支付。简化订单的创建、查询、退款跟接收网关返回的支付通…

使用 dotnet core 和 Azure PaaS服务进行devOps开发(Web API 实例)

引子这一篇文章将用一个完整的实例,给大家介绍如何基于dotnet core(微软.NET的最新版本,支持跨平台,跨设备的应用开发,详情请参考 https://www.microsoft.com/net 开发一个Web API Service,并且利用Azure的…

如何基于Canal 和 Kafka,实现 MySQL 的 Binlog 近实时同步

转载自 如何基于Canal 和 Kafka,实现 MySQL 的 Binlog 近实时同步 近段时间,业务系统架构基本完备,数据层面的建设比较薄弱,因为笔者目前工作重心在于搭建一个小型的数据平台。优先级比较高的一个任务就是需要近实时同步业务系统…

采用Opserver来监控你的ASP.NET项目系列(二、监控SQL Server与Asp.Net项目)

前言之前有过2篇关于如何监控ASP.NET core项目的文章,有兴趣的也可以看看.ASP.NET Core之跨平台的实时性能监控ASP.NET Core之跨平台的实时性能监控(2.健康检查)今天我们主要来介绍一下,如何使用Opserver监控我们的SQL Server 和ASP.NET项目的异常监控监控效果如下:SQL Server的…

Spring Boot 参数校验 Validation 入门

转载自 芋道 Spring Boot 参数校验 Validation 入门 本文在提供完整代码示例,可见 https://github.com/YunaiV/SpringBoot-Labs 的 lab-22 目录。 原创不易,给点个 Star 嘿,一起冲鸭! 1. 概述 在想标题的时候,到底应该…

Orchard Core一分钟搭建ASP.NET Core CMS

Orchard Core 是Orchard CMS的ASP.NET Core版本。Orchard Core是全新一代的ASP.NET Core CMS。官方文档介绍:http://orchardcore.readthedocs.io/en/latest/GitHub: https://github.com/OrchardCMS/OrchardCore下面快速开始搭建CMS新建项目打开VS2017 新建一个CMSWe…

面试:你说你精通Java并发,给我讲讲Java并发之J.U.C

转载自 面试:你说你精通Java并发,给我讲讲Java并发之J.U.C J.U.C J.U.C即java.util.concurrent包,为我们提供了很多高性能的并发类,可以说是java并发的核心。 J.U.C和CAS和Unsafe和AQS Concurrent包下所有类底层都是依靠CAS操…

.Net Core配置与自动更新

.Net Core 将之前Web.Config中的配置迁移到了appsettings.json文件中,并使用ConfigurationBuilder来读取这个配置文件。并可设置在配置文件变化以后,自动重新加载,这样可不用重启你的程序。12345var builder new ConfigurationBuilder().Set…

初级Java开发与架构之间的差距不仅仅是开发时间

转载自 初级Java开发与架构之间的差距不仅仅是开发时间 一、基础篇 JVM JVM内存结构 堆、栈、方法区、直接内存、堆和栈区别 Java内存模型 内存可见性、重排序、顺序一致性、volatile、锁、final 垃圾回收 内存分配策略、垃圾收集器(G1)、GC算法…

ASP.NET Core Web API下事件驱动型架构的实现(一):一个简单的实现

很长一段时间以来,我都在思考如何在ASP.NET Core的框架下,实现一套完整的事件驱动型架构。这个问题看上去有点大,其实主要目标是为了实现一个基于ASP.NET Core的微服务,它能够非常简单地订阅来自于某个渠道的事件消息,…

面试了 N 个候选人后,我总结出这份 Java 面试准备技巧

转载自 面试了 N 个候选人后,我总结出这份 Java 面试准备技巧 目录: 框架是重点,但别让人感觉你只会山寨别人的代码 别只看单机版的框架,分布式也需要了解 对于数据库,别只知道增删改查,得了解性能优化…

Scratc3.0作品转化成exe文件

Scratch 3的作品(sb3格式的文件)怎么生成可执行exe文件 Scratch 3.0和Scratch 2.0软件相比,界面和内部实现机制有了较大变化。 与以前2.0版本不同,Scratch3.0版本改用H5和JS语言编写;软件界面有较大变化,将…

来腾讯云开发者实验室 学习.NET Core 2.0

腾讯云开发者实验室为开发者提供了一个零门槛的在线实验平台,开发者实验室提供的能力:零门槛扫码即可免费领取实验机器,支持使用自有机器参与,实验完成后支持保留实验成果;在线 WEB IDE 支持 shell 命令操作,支持机器文…

Redis面试题(2020最新版)

转载自 Redis面试题(2020最新版) 概述 什么是Redis Redis(Remote Dictionary Server) 是一个使用 C 语言编写的,开源的(BSD许可)高性能非关系型(NoSQL)的键值对数据库。 Redis 可以存储键和五…

Orleans介绍

一、介绍Orleans是一个框架,提供了一个直接的方法来构建分布式高规模计算应用程序默认可扩展 -》 Orleans处理构建分布式系统的复杂性,使您的应用程序能够扩展到数百台服务器。低延迟 -》 Orleans允许你在内存中保持你需要的状态,所以你的应用…

Orleans安装

一、Nuget包Orleans NuGet软件包从v1.5.0开始在大多数情况下,您需要使用4个关键的NuGet包:1,Microsoft Orleans Build-time Code GenerationPM> Install-Package Microsoft.Orleans.OrleansCodeGenerator.Build为Grain接口和实现项目提供支…

Ch5702-Count The Repetitions【字符串,倍增,dp】

正题 题目大意 要求s2n2∗ms_2^{{n_2}*m}s2n2​∗m​是串s1n1s_1^{n_1}s1n1​​的字串,求最大的mmm 解题思路 首先求一个m′m'm′使得s2ms_2^ms2m​能够被s1n1s_1^{n_1}s1n1​​生成,然后可以从而求出mmm 倍增优化,设fi,jf_{i,j}f…

如何加快github的clone速度

有时候在github上下载一个项目需要很长的时间,甚至只有几k每秒,项目大了之后甚至直接下载失败。 这里有两种方法: 1、在GitHub域名后面加上.cnpmjs.org 正常的下载速度只有几十k每秒,但是在镜像上clone则能很大程度的节省时间,加…

Orleans入门

一、GrainsGrains是Orleans编程模型的关键原语。 Grains是Orleans应用程序的构建块,它们是隔离,分配和持久性的原子单元。 Grains是表示应用程序实体的对象。 就像在经典的面向对象编程(Object Oriented Programming)中一样&#…