一个好老好老的老程序员了。
全部博文(915)
分类: Android平台
2017-10-10 20:39:56
身份验证是从用户获取身份验证凭证(例如姓名和密码)以及根据权限验证这些凭据的过程。如果凭据有效,则提交凭据的实体被认为是认证身份。一旦身份被认证,授权过程将确定该身份是否可以访问给定的资源。
将认证和授权集成到与ASP.NET MVC Web应用程序进行通信的Xamarin.Forms应用程序中有许多方法,包括使用ASP.NET核心身份,外部身份验证提供程序(如Microsoft,Google,Facebook或Twitter)以及身份验证中间件。 eShopOnContainers移动应用程序通过使用IdentityServer 4的容器式身份微服务执行身份验证和授权。移动应用程序从IdentityServer请求安全令牌,用于验证用户或访问资源。对于IdentityServer代表用户发出令牌,用户必须登录到IdentityServer。但是,IdentityServer不提供用于验证的用户界面或数据库。因此,在eShopOnContainers参考应用程序中,ASP.NET Core Identity用于此目的。
当应用程序需要知道当前用户的身份时,需要进行身份验证。 ASP.NET Core的用于识别用户的主要机制是ASP.NET核心身份成员系统,它将用户信息存储在由开发人员配置的数据存储中。通常,此数据存储将是EntityFramework存储,尽管可以使用自定义存储或第三方软件包在Azure存储,DocumentDB或其他位置存储身份信息。
对于使用本地用户数据存储的身份验证方案,并通过Cookie(通过ASP.NET MVC Web应用程序通常)在请求之间保留身份信息,ASP.NET核心身份是一种合适的解决方案。 然而,Cookie并不总是持久和传输数据的自然手段。 例如,暴露从移动应用程序访问的RESTful端点的ASP.NET Core Web应用程序通常需要使用承载令牌身份验证,因为在这种情况下不能使用Cookie。 然而,可以容易地检索承载令牌并将其包括在由移动应用程序制作的web请求的授权头文件中。
IdentityServer 4是用于ASP.NET Core的开源OpenID Connect和OAuth 2.0框架,可用于许多身份验证和授权方案,包括为本地ASP.NET核心身份用户颁发安全令牌。
注意:OpenID Connect和OAuth 2.0非常相似,但负责不同。
OpenID Connect是OAuth 2.0协议之上的认证层。 OAuth 2是允许应用程序从安全令牌服务请求访问令牌并使用它们与API进行通信的协议。该委托减少了客户端应用程序和API中的复杂性,因为可以集中验证和授权。
OpenID Connect和OAuth 2.0的组合结合了身份验证和API访问的两个基本安全问题,IdentityServer 4是这些协议的实现。
在使用eShopOnContainers参考应用程序的直接客户端到微服务器通信的应用中,可以使用充当安全令牌服务(STS)的专用认证微服务器来认证用户,如图9-1所示。有关直接客户端与微服务器通信的更多信息,请参阅。
图9-1:通过专用认证微服务进行认证
eShopOnContainers移动应用程序与身份微服务通信,身份微服务使用IdentityServer 4进行身份验证,并对API进行访问控制。因此,移动应用程序会从IdentityServer请求令牌,用于验证用户或访问资源:
· 使用IdentityServer验证用户是通过移动应用程序实现的,请求身份令牌,代表认证过程的结果。最低限度,它包含用户的标识符,以及用户如何和何时进行身份验证的信息。它还可以包含其他身份数据。
· 通过IdentityServer访问资源是通过移动应用程序实现的,请求访问令牌,允许访问API资源。客户端请求访问令牌并将其转发到API。访问令牌包含有关客户端和用户(如果存在)的信息。然后,API使用该信息来授权访问其数据。
注意:客户端必须先注册到IdentityServer才能请求令牌。
为了使ASP.NET Core Web应用程序使用IdentityServer 4,必须将其添加到Web应用程序的Visual Studio解决方案中。 有关详细信息,请参阅IdentityServer文档中的。
一旦IdentityServer包含在Web应用程序的Visual Studio解决方案中,就必须将它添加到Web应用程序的HTTP请求处理流水线中,以便它可以向OpenID Connect和OAuth 2.0端点提供请求。 这在Web应用程序的Startup类中的Configure方法中实现,如下面的代码示例所示:
点击(此处)折叠或打开
在Web应用程序的HTTP请求处理流程中订购事宜。 因此,IdentityServer必须在实现登录屏幕的UI框架之前添加到管道中。
应通过调用services.AddIdentityServer方法在Web应用程序的Startup类中的ConfigureServices方法中配置IdentityServer,如eShopOnContainers参考应用程序的以下代码示例所示:
点击(此处)折叠或打开
调用services.AddIdentityServer方法后,调用其他流畅的API来配置以下内容:
· 用于签名的证书。
· 用户可能要求访问的API和身份资源。
· 将连接请求令牌的客户端。
· ASP.NET核心标识。
? 提示:动态加载IdentityServer 4配置。 IdentityServer 4的API允许从配置对象的内存列表中配置IdentityServer。 在eShopOnContainers参考应用程序中,这些内存中的集合被硬编码到应用程序中。 但是,在生产场景中,可以从配置文件或数据库中动态加载它们。
有关配置IdentityServer以使用ASP.NET核心标识的信息,请参阅IdentityServer文档中的。
配置API资源时,AddInMemoryApiResources方法需要一个IEnumerable 集合。 以下代码示例显示了在eShopOnContainers参考应用程序中提供此集合的GetApis方法:
点击(此处)折叠或打开
此方法指定IdentityServer应保护订单和篮子API。 因此,当调用这些API时,将需要IdentityServer管理的访问令牌。 有关ApiResource类型的更多信息,请参阅IdentityServer 4文档中的。
配置身份资源时,AddInMemoryIdentityResources方法需要一个IEnumerable 集合。 身份资源是诸如用户ID,姓名或电子邮件地址之类的数据。 每个身份资源都有一个唯一的名称,并且可以分配任意的索赔类型,然后将其包含在用户的身份令牌中。 以下代码示例显示了在eShopOnContainers参考应用程序中提供此集合的GetResources方法:
点击(此处)折叠或打开
OpenID Connect规范指定了一些标准身份资源。 最低要求是提供了为用户发布唯一ID的支持。 这是通过公开IdentityResources.OpenId身份资源来实现的。
注意:IdentityResources类支持OpenID Connect规范(openid,email,配置文件,电话和地址)中定义的所有范围。
IdentityServer还支持定义自定义身份资源。 有关详细信息,请参阅IdentityServer文档中的定义自定义身份资源。 有关IdentityResource类型的更多信息,请参阅IdentityServer 4文档中的。
客户端是可以从IdentityServer请求令牌的应用程序。 通常,必须至少为每个客户端定义以下设置:
· 唯一的客户端ID
· 允许与令牌服务的交互(称为授权类型)。
· 身份和访问令牌发送到的位置(称为重定向URI)。
· 允许客户端访问的资源列表(称为范围)。
配置客户端时,AddInMemoryClients方法需要一个IEnumerable 集合。 以下代码示例显示了在eShopOnContainers参考应用程序中提供此集合的GetClients方法中eShopOnContainers移动应用程序的配置:
点击(此处)折叠或打开
此配置指定以下属性的数据:
· ClientId:客户端的唯一ID。
· ClientName:客户端显示名称,用于记录和同意屏幕。
· AllowedGrantTypes:指定客户端如何与IdentityServer进行交互。有关详细信息,请参阅。
· ClientSecrets:指定从令牌端点请求令牌时使用的客户机密码。
· RedirectUris:指定允许的URI返回令牌或授权码。
· RequireConsent:指定是否需要同意屏幕。
· RequirePkce:指定使用授权码的客户端是否必须发送证明密钥。
· PostLogoutRedirectUris:指定注销后重定向到的允许URI。
· AllowedCorsOrigins:指定客户端的来源,以便IdentityServer可以允许来自原点的跨原点呼叫。
· AllowedScopes:指定客户端可访问的资源。默认情况下,客户端无权访问任何资源。
· AllowOfflineAccess:指定客户端是否可以请求刷新令牌。
客户端和IdentityServer之间的认证流程可以通过在Client.AllowedGrantTypes属性中指定授权类型进行配置。 OpenID Connect和OAuth 2.0规范定义了许多认证流程,包括:
· Implicit. 此流程针对基于浏览器的应用程序进行了优化,并且应该用于仅用于用户身份验证,或者用于认证和访问令牌请求。所有令牌都通过浏览器传输,因此不允许使用诸如刷新令牌等高级功能。
· 授权码。该流程提供了与浏览器前端通道相反的方式来检索后端通道上的令牌,同时也支持客户端身份验证。
· Hybrid.此流程是隐式和授权代码授权类型的组合。身份令牌通过浏览器通道传输,并包含签名的协议响应以及其他工件,如授权码。响应成功验证后,应使用后端通道来检索访问和刷新令牌。
? 提示:使用混合身份验证流程。混合身份验证流程减轻了许多适用于浏览器通道的攻击,并且是想要检索访问令牌(也可能刷新令牌)的本机应用程序的推荐流程。
有关认证流程的更多信息,请参阅IdentityServer 4文档中的。
对于IdentityServer代表用户发出令牌,用户必须登录到IdentityServer。 但是,IdentityServer不提供用于验证的用户界面或数据库。 因此,在eShopOnContainers参考应用程序中,ASP.NET Core Identity用于此目的。
eShopOnContainers移动应用程序使用IdentityServer与混合身份验证流程进行身份验证,如图9-2所示。
图9-2:登录过程的高级概述
对进行登录请求:5105 / connect / authorize。 成功认证后,IdentityServer返回包含授权码和身份令牌的认证响应。 然后将授权码发送到:5105 / connect / token,它以访问,身份和刷新令牌进行响应。
eShopOnContainers移动应用程序通过向“基本端点”发送请求:5105 / connect / endsession,并附加参数,从IdentityServer注销。 退出发生后,IdentityServer通过发送注销重定向URI回到移动应用程序进行响应。 图9-3说明了这个过程。
图9-3:注册过程的高级概述
在eShopOnContainers移动应用中,与IdentityServer的通信由IdentityService类执行,该类实现了IIdentityService接口。 该接口指定实现类必须提供CreateAuthorizationRequest,CreateLogoutRequest和GetTokenAsync方法。
当用户点击LoginView上的LOGIN按钮时,LoginViewModel类中的SignInCommand将被执行,后者又执行SignInAsync方法。 以下代码示例显示了此方法:
点击(此处)折叠或打开
此方法调用IdentityService类中的CreateAuthorizationRequest方法,如下面的代码示例所示:
点击(此处)折叠或打开
此方法创建IdentityServer的URI,并附带必需的参数。 授权端点在作为用户设置公开的基础端点的端口5105处的/ connect / authorize。 有关用户设置的更多信息,请参阅配置管理。
注意:通过实施OAuth的代码交换证明码(PKCE)扩展,eShopOnContainers移动应用程序的攻击面减少了。 PKCE保护授权代码在被拦截时被使用。 这通过客户端生成秘密验证器来实现,该验证器在其授权请求中传递其哈希值,并且在兑换授权代码时被呈现为未刷新。 有关PKCE的更多信息,请参阅互联网工程任务组网站上的。
返回的URI存储在LoginViewModel类的LoginUrl属性中。 当IsLogin属性变为true时,LoginView中的WebView变得可见。 WebView数据将其Source属性绑定到LoginViewModel类的LoginUrl属性,因此当LoginUrl属性设置为IdentityServer的授权端点时,会向IdentityServer进行登录请求。 当IdentityServer收到此请求并且用户未通过身份验证时,WebView将被重定向到配置的登录页面,如图9-4所示。
图9-4:WebView显示的登录页面
登录完成后,WebView将被重定向到返回URI。 此WebView导航将导致LoginViewModel类中的NavigateAsync方法被执行,如下面的代码示例所示:
点击(此处)折叠或打开
该方法解析包含在返回URI中的认证响应,并且假设存在有效的授权码,它向IdentityServer的令牌端点发出请求,传递授权码,PKCE密码验证器和其他必需的参数。令牌端点在作为用户设置公开的基本端点的端口5105处的/ connect / token。有关用户设置的更多信息,请参阅配置管理。
? 提示:验证返回URI。虽然eShopOnContainers移动应用程序不验证返回URI,但最佳做法是验证返回URI是否指向已知位置,以防止打开重定向攻击。
如果令牌端点接收到有效的授权码和PKCE密码验证器,则它使用访问令牌,身份令牌和刷新令牌进行响应。然后将访问令牌(允许访问API资源)和身份令牌存储为应用程序设置,并执行页面导航。因此,eShopOnContainers手机应用程序的整体效果是这样的:只要用户能够使用IdentityServer成功验证,就会导航到MainView页面,该页面是TabbedPage,它将CatalogView显示为其选定的选项卡。
有关页面导航的信息,请参阅导航。 有关WebView导航如何导致执行视图模型方法的信息,请参阅。 有关应用程序设置的信息,请参阅配置管理。
注意:eShopOnContainers还允许在应用程序配置为在SettingsView中使用模拟服务时进行模拟登录。 在此模式下,应用程序不与IdentityServer通信,而是允许用户使用任何凭据登录。
当用户点击ProfileView中的LOG OUT按钮时,将执行ProfileViewModel类中的LogoutCommand,然后执行LogoutAsync方法。 此方法执行页面导航到LoginView页面,将LogoutParameter实例设置为true作为参数。 有关在页面导航期间传递参数的更多信息,请参阅。
当创建和导航视图时,将执行视图关联视图模型的InitializeAsync方法,然后执行LoginViewModel类的Logout方法,该方法显示在以下代码示例中:
点击(此处)折叠或打开
此方法调用IdentityService类中的CreateLogoutRequest方法,将从应用程序设置检索的身份令牌作为参数传递。 有关应用程序设置的更多信息,请参阅配置管理。 以下代码示例显示了CreateLogoutRequest方法:
点击(此处)折叠或打开
此方法使用所需的参数创建IdentityServer终端会话端点的URI。终端会话端点在作为用户设置公开的基础端点的端口5105上的/ connect / endsession。有关用户设置的更多信息,请参阅配置管理。
返回的URI存储在LoginViewModel类的LoginUrl属性中。当IsLogin属性为true时,LoginView中的WebView是可见的。 WebView数据将其Source属性绑定到LoginViewModel类的LoginUrl属性,因此当LoginUrl属性设置为IdentityServer的结束会话端点时,会向IdentityServer发出注销请求。当IdentityServer收到此请求时,只要用户已登录,就会退出登录。使用由ASP.NET Core的cookie身份验证中间件管理的cookie跟踪身份验证。因此,退出IdentityServer将删除身份验证cookie,并将注销重定向URI发送回客户端。
在移动应用中,WebView将被重定向到注销重定向URI。此WebView导航将导致LoginViewModel类中的NavigateAsync方法被执行,如下面的代码示例所示:
点击(此处)折叠或打开
此方法从应用程序设置中清除身份令牌和访问令牌,并将IsLogin属性设置为false,这将导致LoginView页面上的WebView变得不可见。 最后,LoginUrl属性设置为IdentityServer的授权端点的URI,并具有必需的参数,以备下次用户启动登录时进行。
有关页面导航的信息,请参阅导航。 有关WebView导航如何导致执行视图模型方法的信息,请参阅。 有关应用程序设置的信息,请参阅配置管理。
注意:eShopOnContainers还允许在应用配置为在SettingsView中使用模拟服务时进行模拟退出。 在此模式下,应用程序不与IdentityServer通信,而是从应用程序设置中清除任何存储的令牌。
认证后,ASP.NET核心Web API通常需要授权访问,这允许服务将API提供给某些经过身份验证的用户,但并非全部。
通过将Authorize属性应用于控制器或操作来限制对ASP.NET Core MVC路由的访问,这将限制对控制器的访问或对已验证用户的操作,如以下代码示例所示:
点击(此处)折叠或打开
如果未经授权的用户尝试访问使用Authorize属性标记的控制器或操作,则MVC框架返回401(未授权的)HTTP状态代码。
注意:可以在Authorize属性上指定参数,以将API限制为特定用户。 有关详细信息,请参阅Microsoft文档中心的授权。
IdentityServer可以集成到授权工作流程中,以便访问令牌提供控制授权。 这种方法如图9-5所示。
图9-5:访问令牌授权eShopOnContainers移动应用程序与身份微服务通信,并请求访问令牌作为身份验证过程的一部分。 访问令牌随后转发到订单和篮子微服务器公开的API作为访问请求的一部分。 访问令牌包含有关客户端和用户的信息。 然后,API使用该信息来授权访问其数据。 有关如何配置IdentityServer以保护API的信息,请参阅配置。
要使用IdentityServer执行授权,其授权中间件必须添加到Web应用程序的HTTP请求管道中。 中间件被添加到Web应用程序的启动类中的ConfigureAuth方法中,该类从Configure方法调用,并在eShopOnContainers参考应用程序的以下代码示例中进行了说明:
点击(此处)折叠或打开
该方法确保只能使用有效的访问令牌来访问API。 中间件验证传入令牌以确保它从受信任的发行者发送,并验证该令牌是有效的,以便与接收它的API一起使用。 因此,浏览订购或购物篮控制器将返回401(未授权的)HTTP状态代码,表示需要访问令牌。
注意:在将MVC与app.UseMvc()或app.UseMvcWithDefaultRoute()相加之前,IdentityServer的授权中间件必须添加到Web应用程序的HTTP请求管道中。
在向订购和购买微服务请求时,在认证过程中从IdentityServer获取的访问令牌必须包含在请求中,如下面的代码示例所示:
点击(此处)折叠或打开
访问令牌存储为应用程序设置,并从平台特定的存储中检索并包含在调用OrderService类中的GetOrderAsync方法中。
类似地,当向IdentityServer保护的API发送数据时,必须包含访问令牌,如以下代码示例所示:
点击(此处)折叠或打开
访问令牌是从特定于平台的存储中检索的,并且包含在对BasketService类中UpdateBasketAsync方法的调用中。
eShopOnContainers手机应用程序中的RequestProvider类使用HttpClient类向eShopOnContainers参考应用程序公开的RESTful API发出请求。 当要求授权的订购和购物篮API请求时,请求中必须包含有效的访问令牌。 这通过将访问令牌添加到HttpClient实例的头部来实现,如下面的代码示例所示:
点击(此处)折叠或打开
HttpClient类的DefaultRequestHeaders属性公开了每个请求发送的头文件,并将访问令牌添加到以字符串承载为前缀的授权标头中。 当请求发送到RESTful API时,将提取并验证授权头的值,以确保它从受信任的颁发者发送,并用于确定用户是否有权限调用接收它的API。
有关eShopOnContainers移动应用程序如何进行Web请求的更多信息,请参阅访问远程数据。
将认证和授权集成到与ASP.NET MVC Web应用程序通信的Xamarin.Forms应用程序中有许多方法。 eShopOnContainers移动应用程序通过使用IdentityServer 4的容器式身份微服务来执行身份验证和授权。IdentityServer是一种用于ASP.NET Core的开源OpenID Connect和OAuth 2.0框架,与ASP.NET Core Identity集成以执行承载令牌身份验证。
移动应用程序从IdentityServer请求安全令牌,用于验证用户或访问资源。 访问资源时,访问令牌必须包含在需要授权的API的请求中。 IdentityServer的中间件验证传入的访问令牌,以确保它们从受信任的发行者发送,并且它们与接收它们的API一起使用是有效的。