ASP.NET Core Blazor Server 其他安全方案

将令牌传递到 Blazor Server 应用

可以使用本节中介绍的方法将 Blazor Server 应用中 Razor 组件外部可用的令牌传递给组件。

与对常规 Razor Pages 或 MVC 应用进行身份验证一样,对 Blazor Server 应用进行身份验证。 预配令牌并将其保存到身份验证 cookie。 例如:

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;

...

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
    options.ResponseType = OpenIdConnectResponseType.Code;
    options.SaveTokens = true;

    options.Scope.Add("offline_access");
});

可选择使用 options.Scope.Add("{SCOPE}"); 添加其他作用域,其中占位符 {SCOPE} 是要添加的其他作用域。

定义可在 Blazor 应用中使用的作用域令牌提供程序服务,以解析依赖项注入 (DI) 中的令牌:

public class TokenProvider
{
    public string AccessToken { get; set; }
    public string RefreshToken { get; set; }
}

Startup.ConfigureServices 中,为以下对象添加服务:

  • IHttpClientFactory
  • TokenProvider
services.AddHttpClient();
services.AddScoped<TokenProvider>();

定义一个类,以在初始应用状态下使用访问令牌和刷新令牌传递它:

public class InitialApplicationState
{
    public string AccessToken { get; set; }
    public string RefreshToken { get; set; }
}

Pages/_Host.cshtml 文件中,创建 InitialApplicationState 实例,并将其作为参数传递给应用:

@using Microsoft.AspNetCore.Authentication

...

@{
    var tokens = new InitialApplicationState
    {
        AccessToken = await HttpContext.GetTokenAsync("access_token"),
        RefreshToken = await HttpContext.GetTokenAsync("refresh_token")
    };
}

<component type="typeof(App)" param-InitialState="tokens" 
    render-mode="ServerPrerendered" />

App 组件 (App.razor) 中,解析服务并使用参数中的数据对其进行初始化:

@inject TokenProvider TokenProvider

...

@code {
    [Parameter]
    public InitialApplicationState InitialState { get; set; }

    protected override Task OnInitializedAsync()
    {
        TokenProvider.AccessToken = InitialState.AccessToken;
        TokenProvider.RefreshToken = InitialState.RefreshToken;

        return base.OnInitializedAsync();
    }
}

Microsoft.AspNet.WebApi.Client NuGet 包添加对应用的包引用。

在发出安全 API 请求的服务中,注入令牌提供程序并检索 API 请求的令牌:

using System;
using System.Net.Http;
using System.Threading.Tasks;

public class WeatherForecastService
{
    private readonly HttpClient http;
    private readonly TokenProvider tokenProvider;

    public WeatherForecastService(IHttpClientFactory clientFactory, 
        TokenProvider tokenProvider)
    {
        http = clientFactory.CreateClient();
        this.tokenProvider = tokenProvider;
    }

    public async Task<WeatherForecast[]> GetForecastAsync()
    {
        var token = tokenProvider.AccessToken;
        var request = new HttpRequestMessage(HttpMethod.Get, 
            "https://localhost:5003/WeatherForecast");
        request.Headers.Add("Authorization", $"Bearer {token}");
        var response = await http.SendAsync(request);
        response.EnsureSuccessStatusCode();

        return await response.Content.ReadAsAsync<WeatherForecast[]>();
    }
}

设置身份验证方案

对于使用多个身份验证中间件并因此具有多个身份验证方案的应用,可以在 Startup.Configure 的终结点配置中显式设置 Blazor 使用的方案。 下面的示例设置 Azure Active Directory 方案:

endpoints.MapBlazorHub().RequireAuthorization(
    new AuthorizeAttribute 
    {
        AuthenticationSchemes = AzureADDefaults.AuthenticationScheme
    });

将令牌传递到 Blazor Server 应用

可以使用本节中介绍的方法将 Blazor Server 应用中 Razor 组件外部可用的令牌传递给组件。

与对常规 Razor Pages 或 MVC 应用进行身份验证一样,对 Blazor Server 应用进行身份验证。 预配令牌并将其保存到身份验证 cookie。 例如:

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;

...

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
    options.ResponseType = OpenIdConnectResponseType.Code;
    options.SaveTokens = true;

    options.Scope.Add("offline_access");
});

可选择使用 options.Scope.Add("{SCOPE}"); 添加其他作用域,其中占位符 {SCOPE} 是要添加的其他作用域。

定义可在 Blazor 应用中使用的作用域令牌提供程序服务,以解析依赖项注入 (DI) 中的令牌:

public class TokenProvider
{
    public string AccessToken { get; set; }
    public string RefreshToken { get; set; }
}

Startup.ConfigureServices 中,为以下对象添加服务:

  • IHttpClientFactory
  • TokenProvider
services.AddHttpClient();
services.AddScoped<TokenProvider>();

定义一个类,以在初始应用状态下使用访问令牌和刷新令牌传递它:

public class InitialApplicationState
{
    public string AccessToken { get; set; }
    public string RefreshToken { get; set; }
}

_Host.cshtml 文件中,创建 InitialApplicationState 实例,并将其作为参数传递给应用:

@using Microsoft.AspNetCore.Authentication

...

@{
    var tokens = new InitialApplicationState
    {
        AccessToken = await HttpContext.GetTokenAsync("access_token"),
        RefreshToken = await HttpContext.GetTokenAsync("refresh_token")
    };
}

<component type="typeof(App)" param-InitialState="tokens" 
    render-mode="ServerPrerendered" />

App 组件 (App.razor) 中,解析服务并使用参数中的数据对其进行初始化:

@inject TokenProvider TokenProvider

...

@code {
    [Parameter]
    public InitialApplicationState InitialState { get; set; }

    protected override Task OnInitializedAsync()
    {
        TokenProvider.AccessToken = InitialState.AccessToken;
        TokenProvider.RefreshToken = InitialState.RefreshToken;

        return base.OnInitializedAsync();
    }
}

Microsoft.AspNet.WebApi.Client NuGet 包添加对应用的包引用。

在发出安全 API 请求的服务中,注入令牌提供程序并检索 API 请求的令牌:

using System;
using System.Net.Http;
using System.Threading.Tasks;

public class WeatherForecastService
{
    private readonly HttpClient http;
    private readonly TokenProvider tokenProvider;

    public WeatherForecastService(IHttpClientFactory clientFactory, 
        TokenProvider tokenProvider)
    {
        http = clientFactory.CreateClient();
        this.tokenProvider = tokenProvider;
    }

    public async Task<WeatherForecast[]> GetForecastAsync()
    {
        var token = tokenProvider.AccessToken;
        var request = new HttpRequestMessage(HttpMethod.Get, 
            "https://localhost:5003/WeatherForecast");
        request.Headers.Add("Authorization", $"Bearer {token}");
        var response = await http.SendAsync(request);
        response.EnsureSuccessStatusCode();

        return await response.Content.ReadAsAsync<WeatherForecast[]>();
    }
}

设置身份验证方案

对于使用多个身份验证中间件并因此具有多个身份验证方案的应用,可以在 Startup.Configure 的终结点配置中显式设置 Blazor 使用的方案。 下面的示例设置 Azure Active Directory 方案:

endpoints.MapBlazorHub().RequireAuthorization(
    new AuthorizeAttribute 
    {
        AuthenticationSchemes = AzureADDefaults.AuthenticationScheme
    });

将令牌传递到 Blazor Server 应用

可以使用本节中介绍的方法将 Blazor Server 应用中 Razor 组件外部可用的令牌传递给组件。

与对常规 Razor Pages 或 MVC 应用进行身份验证一样,对 Blazor Server 应用进行身份验证。 预配令牌并将其保存到身份验证 cookie。 例如:

using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;

...

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
{
    options.ResponseType = OpenIdConnectResponseType.Code;
    options.SaveTokens = true;

    options.Scope.Add("offline_access");
});

可选择使用 options.Scope.Add("{SCOPE}"); 添加其他作用域,其中占位符 {SCOPE} 是要添加的其他作用域。

可选择使用 options.Resource = "{RESOURCE}"; 指定资源,其中占位符 {RESOURCE} 即为资源。 例如:

options.Resource = "https://graph.microsoft.com";

定义一个类,以在初始应用状态下使用访问令牌和刷新令牌传递它:

public class InitialApplicationState
{
    public string AccessToken { get; set; }
    public string RefreshToken { get; set; }
}

定义可在 Blazor 应用中使用的作用域令牌提供程序服务,以解析依赖项注入 (DI) 中的令牌:

public class TokenProvider
{
    public string AccessToken { get; set; }
    public string RefreshToken { get; set; }
}

Startup.ConfigureServices 中,为以下对象添加服务:

  • IHttpClientFactory
  • TokenProvider
services.AddHttpClient();
services.AddScoped<TokenProvider>();

_Host.cshtml 文件中,创建 InitialApplicationState 实例,并将其作为参数传递给应用:

@using Microsoft.AspNetCore.Authentication

...

@{
    var tokens = new InitialApplicationState
    {
        AccessToken = await HttpContext.GetTokenAsync("access_token"),
        RefreshToken = await HttpContext.GetTokenAsync("refresh_token")
    };
}

<app>
    <component type="typeof(App)" param-InitialState="tokens" 
        render-mode="ServerPrerendered" />
</app>

App 组件 (App.razor) 中,解析服务并使用参数中的数据对其进行初始化:

@inject TokenProvider TokenProvider

...

@code {
    [Parameter]
    public InitialApplicationState InitialState { get; set; }

    protected override Task OnInitializedAsync()
    {
        TokenProvider.AccessToken = InitialState.AccessToken;
        TokenProvider.RefreshToken = InitialState.RefreshToken;

        return base.OnInitializedAsync();
    }
}

Microsoft.AspNet.WebApi.Client NuGet 包添加对应用的包引用。

在发出安全 API 请求的服务中,注入令牌提供程序并检索 API 请求的令牌:

using System;
using System.Net.Http;
using System.Threading.Tasks;

public class WeatherForecastService
{
    private readonly HttpClient http;
    private readonly TokenProvider tokenProvider;

    public WeatherForecastService(IHttpClientFactory clientFactory, 
        TokenProvider tokenProvider)
    {
        http = clientFactory.CreateClient();
        this.tokenProvider = tokenProvider;
    }

    public async Task<WeatherForecast[]> GetForecastAsync()
    {
        var token = tokenProvider.AccessToken;
        var request = new HttpRequestMessage(HttpMethod.Get, 
            "https://localhost:5003/WeatherForecast");
        request.Headers.Add("Authorization", $"Bearer {token}");
        var response = await http.SendAsync(request);
        response.EnsureSuccessStatusCode();

        return await response.Content.ReadAsAsync<WeatherForecast[]>();
    }
}

设置身份验证方案

对于使用多个身份验证中间件并因此具有多个身份验证方案的应用,可以在 Startup.Configure 的终结点配置中显式设置 Blazor 使用的方案。 下面的示例设置 Azure Active Directory 方案:

endpoints.MapBlazorHub().RequireAuthorization(
    new AuthorizeAttribute 
    {
        AuthenticationSchemes = AzureADDefaults.AuthenticationScheme
    });

使用 OpenID Connect (OIDC) v2.0 终结点

在 5.0 之前的 ASP.NET Core 版本中,身份验证库和 Blazor 模板使用 OpenID Connect (OIDC) v1.0 终结点。 若要在 5.0 以前的版本中使用 v2.0 终结点,请在 OpenIdConnectOptions 中配置 OpenIdConnectOptions.Authority 选项:

services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, 
    options =>
    {
        options.Authority += "/v2.0";
    }

也可以在应用设置 (appsettings.json) 文件中进行设置:

{
  "AzureAd": {
    "Authority": "https://login.microsoftonline.com/common/oauth2/v2.0/",
    ...
  }
}

如果将段添加到授权不适合应用的 OIDC 提供程序(例如,使用非 AAD 提供程序),则直接设置 Authority 属性。 使用 Authority 键在 OpenIdConnectOptions 或应用设置文件中设置属性。

代码更改

应用 ID URI

  • 使用 v2.0 终结点时,API 会定义一个 App ID URI,来表示 API 的唯一标识符。
  • 所有作用域都将应用 ID URI 用作前缀,v2.0 终结点以应用 ID URI 为受众发出访问令牌。
  • 使用 V2.0 终结点时,服务器 API 中配置的客户端 ID 会从 API 应用程序 ID(客户端 ID)更改为应用 ID URI。

appsettings.json:

{
  "AzureAd": {
    ...
    "ClientId": "https://{TENANT}.onmicrosoft.com/{APP NAME}"
    ...
  }
}

可以在 OIDC 提供程序应用注册说明中找到要使用的应用 ID URI。