身份验证和授权

注意

此电子书于 2017 年春季出版,此后尚未更新。 这本书中有很多是有价值的,但一些材料已经过时。

身份验证是从用户获取标识凭据(例如用户名和密码)以及针对颁发机构验证这些凭据的过程。 如果凭据有效,则提交凭据的实体被视为经过身份验证的标识。 对标识进行身份验证后,授权过程将确定该标识是否有权访问给定资源。

可通过多种方法将身份验证和授权集成到 Xamarin.Forms 与 ASP.NET MVC Web 应用程序通信的应用,包括使用 ASP.NET Core Identity、Microsoft、Google、Facebook 或 Twitter 等外部身份验证提供程序以及身份验证中间件。 eShopOnContainers 移动应用使用 IdentityServer 4 的容器化标识微服务执行身份验证和授权。 移动应用从 IdentityServer 请求安全令牌,以便对用户进行身份验证或访问资源。 要使 IdentityServer 代表用户颁发令牌,用户必须登录到 IdentityServer。 但是,IdentityServer 不提供用于身份验证的用户界面或数据库。 因此,在 eShopOnContainers 参考应用程序中,ASP.NET Core 标识用于此目的。

身份验证

当应用程序需要知道当前用户的标识时,需要进行身份验证。 ASP.NET Core 识别用户的主要机制是 ASP.NET Core 标识成员资格系统,它将用户信息存储在开发人员配置的数据存储中。 通常,此数据存储将是 EntityFramework 存储,不过自定义存储或第三方包可用于在 Azure 存储、Azure Cosmos DB 或其他位置存储标识信息。

对于使用本地用户数据存储的身份验证方案,以及通过 Cookie(如 ASP.NET MVC Web 应用程序中的典型情况)在请求之间保留标识信息),ASP.NET 核心标识是一种合适的解决方案。 然而,cookie 并不总是保留和传输数据的自然方式。 例如,公开从移动应用访问的 RESTful 终结点的 ASP.NET Core Web 应用程序通常需要使用持有者令牌身份验证,因为此方案中无法使用 Cookie。 但是,可以轻松检索持有者令牌,并将其包含在从移动应用发出的 Web 请求的授权标头中。

使用 IdentityServer 4 颁发持有者令牌

IdentityServer 4 是适用于 ASP.NET Core 的 开放源代码 OpenID 连接 和 OAuth 2.0 框架,可用于许多身份验证和授权方案,包括为本地 ASP.NET 核心标识用户颁发安全令牌。

注意

OpenID Connect 和 OAuth 2.0 非常相似,只是职责不同。

OpenID Connect 是基于 OAuth 2.0 协议构建的身份验证层。 OAuth 2 是一种允许应用程序从安全令牌服务请求访问令牌并使用它们与 API 通信的协议。 这种委托降低了客户端应用程序和 API 的复杂性,因为可以集中身份验证和授权。

OpenID 连接 和 OAuth 2.0 的组合结合了身份验证和 API 访问的两个基本安全问题,IdentityServer 4 是这些协议的实现。

在使用直接客户端到微服务通信的应用程序(例如 eShopOnContainers 参考应用程序)中,充当安全令牌服务(STS)的专用身份验证微服务可用于对用户进行身份验证,如图 9-1 所示。 有关直接客户端到微服务通信的详细信息,请参阅 客户端与微服务之间的通信。

Authentication by a dedicated authentication microservice

图 9-1: 专用身份验证微服务的身份验证

eShopOnContainers 移动应用与标识微服务通信,该微服务使用 IdentityServer 4 对 API 执行身份验证和访问控制。 因此,移动应用从 IdentityServer 请求令牌,以便对用户进行身份验证或访问资源:

  • 使用 IdentityServer 对用户进行身份验证是通过请求 标识 令牌的移动应用实现的,这表示身份验证过程的结果。 它至少包含用户的标识符,以及用户身份验证方式和时间的信息。 它还可以包含其他标识数据。
  • 使用 IdentityServer 访问资源是通过请求 访问 令牌的移动应用实现的,该令牌允许访问 API 资源。 客户端请求访问令牌并将其转发到 API。 访问令牌包含有关客户端和用户的信息(如果存在)。 然后,API 使用该信息来授权访问其数据。

注意

客户端必须先向 IdentityServer 注册,然后才能请求令牌。

将 IdentityServer 添加到 Web 应用程序

为了让 ASP.NET Core Web 应用程序使用 IdentityServer 4,必须将其添加到 Web 应用程序的 Visual Studio 解决方案中。 有关详细信息,请参阅 IdentityServer 文档中的概述

将 IdentityServer 包含在 Web 应用程序的 Visual Studio 解决方案中后,必须将其添加到 Web 应用程序的 HTTP 请求处理管道中,以便它可以为 OpenID 连接 和 OAuth 2.0 终结点的请求提供服务。 这是通过 Web 应用程序的 Startup 类中的 Configure 方法实现的,如以下代码示例所示:

public void Configure(  
    IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)  
{  
    ...  
    app.UseIdentity();  
    ...  
}

Web 应用程序的 HTTP 请求处理管道中的顺序很重要。 因此,必须在实现登录屏幕的 UI 框架之前将 IdentityServer 添加到管道中。

配置 IdentityServer

应通过调用该方法services.AddIdentityServerConfigureServices Web 应用程序的Startup类中配置 IdentityServer,如 eShopOnContainers 引用应用程序的以下代码示例所示:

public void ConfigureServices(IServiceCollection services)  
{  
    ...  
    services.AddIdentityServer(x => x.IssuerUri = "null")  
        .AddSigningCredential(Certificate.Get())                 
        .AddAspNetIdentity<ApplicationUser>()  
        .AddConfigurationStore(builder =>  
            builder.UseSqlServer(connectionString, options =>  
                options.MigrationsAssembly(migrationsAssembly)))  
        .AddOperationalStore(builder =>  
            builder.UseSqlServer(connectionString, options =>  
                options.MigrationsAssembly(migrationsAssembly)))  
        .Services.AddTransient<IProfileService, ProfileService>();  
}

调用 services.AddIdentityServer 方法后,会调用额外的 Fluent API 来配置以下内容:

  • 用于签名的凭据。
  • 用户可能会请求访问的 API 和标识资源。
  • 将连接到请求令牌的客户端。
  • ASP.NET Core 标识。

提示

动态加载 IdentityServer 4 配置。 IdentityServer 4 的 API 允许从内存中的配置对象列表配置 IdentityServer。 在 eShopOnContainers 参考应用程序中,这些内存中的集合被硬编码到应用程序中。 但是,在生产场景中,可以从配置文件或数据库动态加载它们。

有关将 IdentityServer 配置为使用 ASP.NET Core 标识的信息,请参阅 IdentityServer 文档中的使用 ASP.NET Core 标识

配置 API 资源

配置 API 资源时,AddInMemoryApiResources 方法需要一个 IEnumerable<ApiResource> 集合。 以下代码示例演示了在 eShopOnContainers 参考应用程序中提供此集合的 GetApis 方法:

public static IEnumerable<ApiResource> GetApis()  
{  
    return new List<ApiResource>  
    {  
        new ApiResource("orders", "Orders Service"),  
        new ApiResource("basket", "Basket Service")  
    };  
}

此方法指定 IdentityServer 应保护订单和购物篮 API。 因此,调用这些 API 时,需要 IdentityServer 托管访问令牌。 有关 ApiResource 类型的详细信息,请参阅 IdentityServer 4 文档中的 API 资源

配置标识资源

配置标识资源时,AddInMemoryIdentityResources 方法需要一个 IEnumerable<IdentityResource> 集合。 标识资源是用户 ID、名称或电子邮件地址等数据。 每个标识资源都有一个唯一的名称,可以向其分配任意声明类型,然后该类型将包含在用户的标识令牌中。 以下代码示例演示了在 eShopOnContainers 参考应用程序中提供此集合的 GetResources 方法:

public static IEnumerable<IdentityResource> GetResources()  
{  
    return new List<IdentityResource>  
    {  
        new IdentityResources.OpenId(),  
        new IdentityResources.Profile()  
    };  
}

OpenID Connect 规范指定了一些标准标识资源。 最低要求是支持为用户发出唯一 ID。 这是通过公开 IdentityResources.OpenId 标识资源来实现的。

注意

IdentityResources类支持 OpenID 连接规范(openid、email、profile、telephone 和 address)中定义的所有范围。

IdentityServer 还支持定义自定义标识资源。 有关类型的详细信息 IdentityResource ,请参阅 IdentityServer 4 文档中的标识资源

配置客户端

客户端是可以从 IdentityServer 请求令牌的应用程序。 通常,必须为每个客户端至少定义以下设置:

  • 唯一的客户端 ID。
  • 允许与令牌服务的交互(称为授权类型)。
  • 标识和访问令牌发送到的位置(称为重定向 URI)。
  • 允许客户端访问的资源列表(称为范围)。

配置客户端时,AddInMemoryClients 方法需要一个 IEnumerable<Client> 集合。 下面的代码示例演示 eShopOnContainers 移动应用的配置, GetClients 该方法在 eShopOnContainers 引用应用程序中提供此集合:

public static IEnumerable<Client> GetClients(Dictionary<string,string> clientsUrl)
{
    return new List<Client>
    {
        ...
        new Client
        {
            ClientId = "xamarin",
            ClientName = "eShop Xamarin OpenId Client",
            AllowedGrantTypes = GrantTypes.Hybrid,
            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },
            RedirectUris = { clientsUrl["Xamarin"] },
            RequireConsent = false,
            RequirePkce = true,
            PostLogoutRedirectUris = { $"{clientsUrl["Xamarin"]}/Account/Redirecting" },
            AllowedCorsOrigins = { "http://eshopxamarin" },
            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                IdentityServerConstants.StandardScopes.OfflineAccess,
                "orders",
                "basket"
            },
            AllowOfflineAccess = true,
            AllowAccessTokensViaBrowser = true
        },
        ...
    };
}

此配置指定以下属性的数据:

  • ClientId:客户端的唯一 ID。
  • ClientName:用于日志记录和同意屏幕的客户端显示名称。
  • AllowedGrantTypes:指定客户端希望如何与 IdentityServer 交互。 有关详细信息,请参阅 配置身份验证流
  • ClientSecrets:指定从令牌终结点请求令牌时使用的客户端机密凭据。
  • RedirectUris:指定要向其返回令牌或授权代码的允许 URI。
  • RequireConsent:指定是否需要许可屏幕。
  • RequirePkce:指定使用授权代码的客户端是否必须发送证明密钥。
  • PostLogoutRedirectUris:指定要在注销后重定向到的允许 URI。
  • AllowedCorsOrigins:指定客户端的源,以便 IdentityServer 可以允许来自源的跨源调用。
  • AllowedScopes:指定客户端有权访问的资源。 默认情况下,客户端无权访问任何资源。
  • AllowOfflineAccess:指定客户端是否可以请求刷新令牌。

配置身份验证流

可以通过在 Client.AllowedGrantTypes 属性中指定授权类型来配置客户端和 IdentityServer 之间的身份验证流。 OpenID 连接和 OAuth 2.0 规范定义了许多身份验证流,包括:

  • 隐 式。 此流针对基于浏览器的应用程序进行了优化,应用于仅用户身份验证或身份验证和访问令牌请求。 所有令牌都通过浏览器传输,因此不允许使用刷新令牌等高级功能。
  • 授权代码。 此流提供了在反向通道(与浏览器前向通道相对)上检索令牌的能力,同时还支持客户端身份验证。
  • 混合。 此流是隐式和授权代码授予类型的组合。 标识令牌通过浏览器通道传输,并包含已签名的协议响应以及其他项目,例如授权代码。 成功验证响应后,应使用后退通道检索访问和刷新令牌。

提示

使用混合身份验证流。 混合身份验证流可缓解应用于浏览器通道的许多攻击,并且是希望检索访问令牌(可能还有刷新令牌)的本机应用程序的推荐流。

有关身份验证流的详细信息,请参阅 IdentityServer 4 文档中的授权类型

执行身份验证

要使 IdentityServer 代表用户颁发令牌,用户必须登录到 IdentityServer。 但是,IdentityServer 不提供用于身份验证的用户界面或数据库。 因此,在 eShopOnContainers 参考应用程序中,ASP.NET Core 标识用于此目的。

eShopOnContainers 移动应用使用混合身份验证流向 IdentityServer 进行身份验证,如图 9-2 所示。

High-level overview of the sign-in process

图 9-2: 登录过程的概要概述

向该请求发出 <base endpoint>:5105/connect/authorize登录请求。 成功进行身份验证后,IdentityServer 返回包含授权代码和标识令牌的身份验证响应。 然后,将授权代码发送到 <base endpoint>:5105/connect/token该代码,该代码使用访问、标识和刷新令牌进行响应。

eShopOnContainers 移动应用通过向 IdentityServer 发送请求 <base endpoint>:5105/connect/endsession,使用其他参数注销 IdentityServer。 注销后,IdentityServer 将通过将注销后重定向 URI 发送回移动应用来响应。 图 9-3 说明了此过程。

High-level overview of the sign-out process

图 9-3: 注销过程的概要概述

在 eShopOnContainers 移动应用中,与 IdentityServer 的通信由 IdentityService 实现接口的 IIdentityService 类执行。 此接口指定实现类必须提供 CreateAuthorizationRequestCreateLogoutRequestGetTokenAsync 方法。

登录

当用户点击登录按钮时LoginViewSignInCommand将执行类中的LoginViewModel登录按钮,进而执行该方法SignInAsync。 下面的代码示例演示此方法:

private async Task SignInAsync()  
{  
    ...  
    LoginUrl = _identityService.CreateAuthorizationRequest();  
    IsLogin = true;  
    ...  
}

此方法调用 CreateAuthorizationRequest 类中的 IdentityService 方法,如以下代码示例所示:

public string CreateAuthorizationRequest()
{
    // Create URI to authorization endpoint
    var authorizeRequest = new AuthorizeRequest(GlobalSetting.Instance.IdentityEndpoint);

    // Dictionary with values for the authorize request
    var dic = new Dictionary<string, string>();
    dic.Add("client_id", GlobalSetting.Instance.ClientId);
    dic.Add("client_secret", GlobalSetting.Instance.ClientSecret); 
    dic.Add("response_type", "code id_token");
    dic.Add("scope", "openid profile basket orders locations marketing offline_access");
    dic.Add("redirect_uri", GlobalSetting.Instance.Callback);
    dic.Add("nonce", Guid.NewGuid().ToString("N"));
    dic.Add("code_challenge", CreateCodeChallenge());
    dic.Add("code_challenge_method", "S256");

    // Add CSRF token to protect against cross-site request forgery attacks.
    var currentCSRFToken = Guid.NewGuid().ToString("N");
    dic.Add("state", currentCSRFToken);

    var authorizeUri = authorizeRequest.Create(dic); 
    return authorizeUri;
}

此方法使用所需的参数创建 IdentityServer 授权终结点URI。 授权终结点位于作为用户设置公开的基本终结点的端口 5105 上的 /connect/authorize。 有关用户设置的详细信息,请参阅配置管理

注意

eShopOnContainers 移动应用的攻击面通过实现 OAuth 的代码交换(PKCE)扩展来减少。 PKCE 可防止在截获授权代码时使用。 这是通过客户端生成一个机密验证程序来实现的,该验证程序的哈希在授权请求中传递,并且在兑换授权代码时以未经过哈希处理的方式显示。 有关 PKCE 的详细信息,请参阅 Internet 工程任务组网站上的OAuth 公共客户端的代码交换证明密钥

返回的 URI 存储在 LoginViewModel 类的 LoginUrl 属性中。 IsLogin当属性变为true时,该WebViewLoginView属性将变为可见。 数据 WebView 将其 Source 属性 LoginUrl 绑定到类的属性 LoginViewModel ,因此, LoginUrl 当属性设置为 IdentityServer 的授权终结点时,向 IdentityServer 发出登录请求。 当 IdentityServer 收到此请求并且用户未进行身份验证时, WebView 将重定向到配置的登录页,如图 9-4 所示。

Login page displayed by the WebView

图 9-4: WebView 显示的登录页

登录完成后,WebView 将重定向到返回 URI。 此 WebView 导航将导致执行 LoginViewModel 类中的 NavigateAsync 方法,如以下代码示例所示:

private async Task NavigateAsync(string url)  
{  
    ...  
    var authResponse = new AuthorizeResponse(url);  
    if (!string.IsNullOrWhiteSpace(authResponse.Code))  
    {  
        var userToken = await _identityService.GetTokenAsync(authResponse.Code);  
        string accessToken = userToken.AccessToken;  

        if (!string.IsNullOrWhiteSpace(accessToken))  
        {  
            Settings.AuthAccessToken = accessToken;  
            Settings.AuthIdToken = authResponse.IdentityToken;  

            await NavigationService.NavigateToAsync<MainViewModel>();  
            await NavigationService.RemoveLastFromBackStackAsync();  
        }  
    }  
    ...  
}

此方法分析返回 URI 中包含的身份验证响应,并前提是存在有效的授权代码,它会向 IdentityServer 的 令牌终结点发出请求、传递授权代码、PKCE 机密验证程序和其他必需参数。 令牌终结点位于作为用户设置公开的基本终结点的端口 5105 上的 /connect/token。 有关用户设置的详细信息,请参阅配置管理

提示

验证返回 URI。 尽管 eShopOnContainers 移动应用未验证返回 URI,但最佳做法是验证返回 URI 是否引用已知位置,以防止开放重定向攻击。

如果令牌终结点收到有效的授权代码和 PKCE 机密验证程序,它将使用访问令牌、标识令牌和刷新令牌进行响应。 访问令牌(允许访问 API 资源)和标识令牌随后存储为应用程序设置,并执行页面导航。 因此,eShopOnContainers 移动应用的总体效果是:只要用户能够使用 IdentityServer 成功进行身份验证,他们就会导航到 MainView 页面,该 TabbedPage 页面将显示 CatalogView 为所选选项卡。

有关页面导航的信息,请参阅导航。 有关如何执行导航导致执行视图模型方法的信息 WebView ,请参阅 使用行为调用导航。 有关应用程序设置的信息,请参阅 配置管理

注意

当应用配置为在 SettingsView应用中使用模拟服务时,eShopOnContainers 还允许模拟登录。 在此模式下,应用不会与 IdentityServer 通信,而是允许用户使用任何凭据登录。

注销

当用户点击其中的“注销”按钮时,LogoutCommand将执行类中的ProfileViewModel“注销”按钮,进而执行该方法LogoutAsyncProfileView。 此方法执行到 LoginView 页的页面导航,将设置为 trueLogoutParameter 实例作为参数传递。 有关在页面导航期间传递参数的详细信息,请参阅 “在导航期间传递参数”。

创建并导航到视图时,将执行视图关联视图模型的 InitializeAsync 方法,然后执行 LoginViewModel 类的 Logout 方法,如以下代码示例所示:

private void Logout()  
{  
    var authIdToken = Settings.AuthIdToken;  
    var logoutRequest = _identityService.CreateLogoutRequest(authIdToken);  

    if (!string.IsNullOrEmpty(logoutRequest))  
    {  
        // Logout  
        LoginUrl = logoutRequest;  
    }  
    ...  
}

此方法调用 IdentityService 类中的 CreateLogoutRequest 方法,将从应用程序设置中检索到的标识令牌作为参数传递。 有关应用程序设置的详细信息,请参阅 配置管理。 下面的代码示例说明 CreateLogoutRequest 方法:

public string CreateLogoutRequest(string token)  
{  
    ...  
    return string.Format("{0}?id_token_hint={1}&post_logout_redirect_uri={2}",   
        GlobalSetting.Instance.LogoutEndpoint,  
        token,  
        GlobalSetting.Instance.LogoutCallback);  
}

此方法使用所需的参数创建 IdentityServer 结束会话终结点URI。 结束会话终结点位于作为用户设置公开的基本终结点的端口 5105 上的 /connect/endsession。 有关用户设置的详细信息,请参阅配置管理

返回的 URI 存储在 LoginViewModel 类的 LoginUrl 属性中。 虽然属性IsLogin是,但WebView该属性是可见的LoginViewtrue。 数据 WebView 将其 Source 属性 LoginUrl 绑定到类的属性 LoginViewModel ,因此, LoginUrl 当属性设置为 IdentityServer 的结束会话终结点时,向 IdentityServer 发出注销请求。 如果 IdentityServer 收到此请求,前提是用户已登录,则会发生注销。 身份验证使用由 ASP.NET Core 中的 cookie 身份验证中间件管理的 cookie 进行跟踪。 因此,注销 IdentityServer 会删除身份验证 Cookie,并将注销后重定向 URI 发送回客户端。

在移动应用中, WebView 将重定向到注销后重定向 URI。 此 WebView 导航将导致执行 LoginViewModel 类中的 NavigateAsync 方法,如以下代码示例所示:

private async Task NavigateAsync(string url)  
{  
    ...  
    Settings.AuthAccessToken = string.Empty;  
    Settings.AuthIdToken = string.Empty;  
    IsLogin = false;  
    LoginUrl = _identityService.CreateAuthorizationRequest();  
    ...  
}

此方法从应用程序设置中清除标识令牌和访问令牌,并将属性设置为IsLogin该属性false,导致WebViewLoginView页面上的标识令牌变得不可见。 最后,使用所需参数将 LoginUrl 属性设置为 IdentityServer 授权终结点的 URI,为用户下次启动登录做好准备。

有关页面导航的信息,请参阅导航。 有关如何执行导航导致执行视图模型方法的信息 WebView ,请参阅 使用行为调用导航。 有关应用程序设置的信息,请参阅 配置管理

注意

当应用配置为在 设置View 中使用模拟服务时,eShopOnContainers 还允许模拟注销。 在此模式下,应用不与 IdentityServer 通信,而是从应用程序设置中清除所有存储的令牌。

授权

身份验证后,ASP.NET Core Web API 通常需要授权访问,这允许服务向某些经过身份验证的用户提供 API,但并非全部可用。

通过向控制器或操作应用 Authorize 属性,限制对 ASP.NET 核心 MVC 路由的访问,从而限制对已验证用户的控制器或操作的访问,如以下代码示例所示:

[Authorize]  
public class BasketController : Controller  
{  
    ...  
}

如果未经授权的用户尝试访问用 Authorize 该属性标记的控制器或操作,MVC 框架将返回 401 (未授权) HTTP 状态代码。

注意

可以在特性上 Authorize 指定参数,以将 API 限制为特定用户。 有关详细信息,请参阅授权

IdentityServer 可以集成到授权工作流中,以便由它提供的访问令牌来控制授权。 图 9-5 中显示了此方法。

Authorization by access token

图 9-5: 按访问令牌进行授权

eShopOnContainers 移动应用与标识微服务通信,并在身份验证过程中请求访问令牌。 然后,访问令牌作为访问请求的一部分转发到订购和购物篮微服务公开的 API。 访问令牌包含有关客户端和用户的信息。 然后,API 使用该信息来授权访问其数据。 有关如何配置 IdentityServer 以保护 API 的信息,请参阅 配置 API 资源

配置 IdentityServer 以执行授权

若要使用 IdentityServer 执行授权,必须将其授权中间件添加到 Web 应用程序的 HTTP 请求管道中。 中间件将 ConfigureAuth 添加到 Web 应用程序的 Startup 类中,该方法从 Configure 该方法调用,并在 eShopOnContainers 引用应用程序的以下代码示例中演示:

protected virtual void ConfigureAuth(IApplicationBuilder app)  
{  
    var identityUrl = Configuration.GetValue<string>("IdentityUrl");  
    app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions  
    {  
        Authority = identityUrl.ToString(),  
        ScopeName = "basket",  
        RequireHttpsMetadata = false  
    });  
} 

此方法可确保只能使用有效的访问令牌访问 API。 中间件会验证传入令牌,以确保它从受信任的颁发者发送,并验证令牌是否有效,以便与接收令牌的 API 一起使用。 因此,浏览到订购或购物篮控制器将返回 401(未授权)HTTP 状态代码,指示需要访问令牌。

注意

在使用 app.UseMvc()app.UseMvcWithDefaultRoute() 添加 MVC 之前,必须将 IdentityServer 的授权中间件添加到 Web 应用程序的 HTTP 请求管道。

向 API 发出访问请求

向订购和篮子微服务发出请求时,必须在请求中包含从 IdentityServer 获取的访问令牌,如以下代码示例所示:

var authToken = Settings.AuthAccessToken;  
Order = await _ordersService.GetOrderAsync(Convert.ToInt32(order.OrderNumber), authToken);

访问令牌存储为应用程序设置,从特定于平台的存储中检索,并包含在对类中方法的OrderService调用GetOrderAsync中。

同样,在向受 IdentityServer 保护的 API 发送数据时也必须包含访问令牌,如以下代码示例所示:

var authToken = Settings.AuthAccessToken;  
await _basketService.UpdateBasketAsync(new CustomerBasket  
{  
    BuyerId = userInfo.UserId,   
    Items = BasketItems.ToList()  
}, authToken);

从特定于平台的存储中检索访问令牌,并包含在对类中方法的BasketService调用UpdateBasketAsync中。

在 eShopOnContainers 移动应用中,该 RequestProvider 类使用 HttpClient 该类向 eShopOnContainers 引用应用程序公开的 RESTful API 发出请求。 向需要授权的订购和购物篮 API 发出请求时,请求必须包含有效的访问令牌。 这可以通过将访问令牌添加到实例的 HttpClient 标头来实现,如以下代码示例所示:

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

HttpClient 类的 DefaultRequestHeaders 属性公开随每个请求发送的标头,访问令牌被添加到以字符串 Bearer 为前缀的 Authorization 标头中。 将请求发送到 RESTful API 时,将提取并验证标头的值 Authorization ,以确保它从受信任的颁发者发送,并用于确定用户是否有权调用接收它的 API。

有关 eShopOnContainers 移动应用如何发出 Web 请求的详细信息,请参阅 访问远程数据

总结

可通过多种方法将身份验证和授权集成到 Xamarin.Forms 与 ASP.NET MVC Web 应用程序通信的应用。 eShopOnContainers 移动应用使用 IdentityServer 4 的容器化标识微服务执行身份验证和授权。 IdentityServer 是一个适用于 ASP.NET Core 的开源 OpenID Connect 和 OAuth 2.0 框架,它与 ASP.NET Core 标识集成以执行持有者令牌身份验证。

移动应用从 IdentityServer 请求安全令牌,以便对用户进行身份验证或访问资源。 访问资源时,访问令牌必须包含在对需要授权的 API 的请求中。 IdentityServer 的中间件会验证传入访问令牌,以确保从受信任的颁发者发送这些令牌,以及它们是否可用于接收令牌的 API。