如何在 Blazor 服务器应用程序中注入 ClaimsPrincipal
How to inject a ClaimsPrincipal in a Blazor Server application
以下是一些有助于理解问题的工件:
- 示例代码 - Github repo
- 已部署的应用程序 - 不再可用
更新:我已经关注了这个 YouTube 视频,我现在认为这是 正确 访问有关已验证用户信息的方式Blazor Server 应用程序的依赖服务:https://www.youtube.com/watch?v=Eh4xPgP5PsM.
我已经更新了 Github 代码以反映该解决方案。
我在 ASP.NET MVC Core 应用程序中使用依赖注入注册了以下 类。
public class UserContext
{
ClaimsPrincipal _principal;
public UserContext(ClaimsPrincipal principal) => _principal = principal;
public bool IsAuthenticated => _principal.Identity.IsAuthenticated;
}
public class WrapperService
{
UserContext _userContext;
public WrapperService(UserContext context) => _userContext = context;
public bool UserHasSpecialAccess()
{
return _userContext.IsAuthenticated;
}
}
IoC 依赖注册配置在Startup.cs
services.AddScoped<ClaimsPrincipal>(x =>
{
var context = x.GetRequiredService<IHttpContextAccessor>();
return context.HttpContext.User;
});
services.AddScoped<UserContext>();
services.AddScoped<WrapperService>();
我最近在 MVC 应用程序中启用了 Blazor,并希望在我的 Blazor 组件中使用我的 DI 注册服务。
我在 Blazor 组件中注入了服务,以便像这样使用它:
@inject WrapperService _Wrapper
但是,当我尝试使用来自服务器端处理程序的服务时,请求失败并出现异常,抱怨无法构建服务 - 由于 IHttpContext 在对服务器的后续调用中不存在。
<button @onclick="HandleClick">Check Access</button>
async Task HandleClick()
{
var hasPermission = _Wrapper.UserHasSpecialAccess(); // fails
}
我想我理解为什么在 Blazor Server 应用程序中使用 IHttpContextAccessor
而不是 working/recommended。我的问题是,如果没有它,我如何才能访问我在服务中需要的声明?
对我来说奇怪的是,当我在我的开发环境中 运行 它在 IIS Express 下时,这一切都有效,但是当我部署并尝试从 Azure AppService 中 运行 它时失败.
使用 CascadingAuthenticationState 访问声明主体
如果您需要使用自己的逻辑,则需要实现自己的身份验证状态提供程序。
如果您想使用 ClaimsPrincipal 服务,您可以执行以下操作:
ClaimsPrincipalUserService.cs
ClaimsPrincipal claimsPrincipal;
void SetClaimsPrincipal(ClaimsPrincipal cp)
{
claimsPrincipal = cp;
// any logic + notifications which need to be raised when
// ClaimsPrincipal has changes
}
在启动范围内注入此服务。
布局中
MainLayout.razor
@inject ClaimsPrincipalUserService cpus;
[CascadingParameter]
public Task<AuthenticationState> State {get;set;}
protected override async Task OnInitializedAsync()
{
var state = await State;
var user = state.User; // Get claims principal.
cpus.SetClaimsPrincipal(user);
}
您可以将 AuthenticationStateProvider 注入到您的服务构造函数中,然后使用
var principal = await _authenticationStateProvider.GetAuthenticationStateAsync();
AuthenticationStateProvider 是一个 Scoped 服务,所以你的也必须是。
这对我有用,为 AuthenticationStateProvider 编写派生的 class。
public class AppAuthenticationStateProvider : AuthenticationStateProvider
{
private ClaimsPrincipal principal;
// Constructor, only needed when injections required
public AppAuthenticationStateProvider(/* INJECTIONS HERE */)
: base()
{
principal ??= new();
}
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
return Task.FromResult(new AuthenticationState(principal));
}
// Method called from login form view
public async Task LogIn(/* USER AND PASSWORD */)
{
// Create session
principal = new ClaimsPrincipal(...);
var task = Task.FromResult(new AuthenticationState(principal));
NotifyAuthenticationStateChanged(task);
}
// Method called from logout form view
public async Task LogOut()
{
// Close session
principal = new();
var task = Task.FromResult(new AuthenticationState(principal));
NotifyAuthenticationStateChanged(task);
}
然后,在 program/startup 添加这些行:
// Example for .Net 6
builder.Services.AddScoped<AuthenticationStateProvider, AppAuthenticationStateProvider>();
builder.Services.AddScoped<ClaimsPrincipal>(s =>
{
var stateprovider = s.GetRequiredService<AuthenticationStateProvider>();
var state = stateprovider.GetAuthenticationStateAsync().Result;
return state.User;
});
就是这样。现在你可以在任何地方注入 ClaimsPrincipal。
以下是一些有助于理解问题的工件:
- 示例代码 - Github repo
- 已部署的应用程序 - 不再可用
更新:我已经关注了这个 YouTube 视频,我现在认为这是 正确 访问有关已验证用户信息的方式Blazor Server 应用程序的依赖服务:https://www.youtube.com/watch?v=Eh4xPgP5PsM.
我已经更新了 Github 代码以反映该解决方案。
我在 ASP.NET MVC Core 应用程序中使用依赖注入注册了以下 类。
public class UserContext
{
ClaimsPrincipal _principal;
public UserContext(ClaimsPrincipal principal) => _principal = principal;
public bool IsAuthenticated => _principal.Identity.IsAuthenticated;
}
public class WrapperService
{
UserContext _userContext;
public WrapperService(UserContext context) => _userContext = context;
public bool UserHasSpecialAccess()
{
return _userContext.IsAuthenticated;
}
}
IoC 依赖注册配置在Startup.cs
services.AddScoped<ClaimsPrincipal>(x =>
{
var context = x.GetRequiredService<IHttpContextAccessor>();
return context.HttpContext.User;
});
services.AddScoped<UserContext>();
services.AddScoped<WrapperService>();
我最近在 MVC 应用程序中启用了 Blazor,并希望在我的 Blazor 组件中使用我的 DI 注册服务。
我在 Blazor 组件中注入了服务,以便像这样使用它:
@inject WrapperService _Wrapper
但是,当我尝试使用来自服务器端处理程序的服务时,请求失败并出现异常,抱怨无法构建服务 - 由于 IHttpContext 在对服务器的后续调用中不存在。
<button @onclick="HandleClick">Check Access</button>
async Task HandleClick()
{
var hasPermission = _Wrapper.UserHasSpecialAccess(); // fails
}
我想我理解为什么在 Blazor Server 应用程序中使用 IHttpContextAccessor
而不是 working/recommended。我的问题是,如果没有它,我如何才能访问我在服务中需要的声明?
对我来说奇怪的是,当我在我的开发环境中 运行 它在 IIS Express 下时,这一切都有效,但是当我部署并尝试从 Azure AppService 中 运行 它时失败.
使用 CascadingAuthenticationState 访问声明主体
如果您需要使用自己的逻辑,则需要实现自己的身份验证状态提供程序。
如果您想使用 ClaimsPrincipal 服务,您可以执行以下操作:
ClaimsPrincipalUserService.cs
ClaimsPrincipal claimsPrincipal;
void SetClaimsPrincipal(ClaimsPrincipal cp)
{
claimsPrincipal = cp;
// any logic + notifications which need to be raised when
// ClaimsPrincipal has changes
}
在启动范围内注入此服务。
布局中
MainLayout.razor
@inject ClaimsPrincipalUserService cpus;
[CascadingParameter]
public Task<AuthenticationState> State {get;set;}
protected override async Task OnInitializedAsync()
{
var state = await State;
var user = state.User; // Get claims principal.
cpus.SetClaimsPrincipal(user);
}
您可以将 AuthenticationStateProvider 注入到您的服务构造函数中,然后使用
var principal = await _authenticationStateProvider.GetAuthenticationStateAsync();
AuthenticationStateProvider 是一个 Scoped 服务,所以你的也必须是。
这对我有用,为 AuthenticationStateProvider 编写派生的 class。
public class AppAuthenticationStateProvider : AuthenticationStateProvider
{
private ClaimsPrincipal principal;
// Constructor, only needed when injections required
public AppAuthenticationStateProvider(/* INJECTIONS HERE */)
: base()
{
principal ??= new();
}
public override Task<AuthenticationState> GetAuthenticationStateAsync()
{
return Task.FromResult(new AuthenticationState(principal));
}
// Method called from login form view
public async Task LogIn(/* USER AND PASSWORD */)
{
// Create session
principal = new ClaimsPrincipal(...);
var task = Task.FromResult(new AuthenticationState(principal));
NotifyAuthenticationStateChanged(task);
}
// Method called from logout form view
public async Task LogOut()
{
// Close session
principal = new();
var task = Task.FromResult(new AuthenticationState(principal));
NotifyAuthenticationStateChanged(task);
}
然后,在 program/startup 添加这些行:
// Example for .Net 6
builder.Services.AddScoped<AuthenticationStateProvider, AppAuthenticationStateProvider>();
builder.Services.AddScoped<ClaimsPrincipal>(s =>
{
var stateprovider = s.GetRequiredService<AuthenticationStateProvider>();
var state = stateprovider.GetAuthenticationStateAsync().Result;
return state.User;
});
就是这样。现在你可以在任何地方注入 ClaimsPrincipal。