我有一个基于通过OpenID Connect
提供程序进行身份验证的AuthorizeView
组件,但我想根据在OIDC authentication
之后的相关数据库中找到的关于用户的一些信息添加一个额外的层。我想知道下面所示的逻辑,
1:实现这一点最明智的方式是什么?
2:如果是,如何在现有的授权视图中构建自己的授权视图?
<AuthorizeView>
<Authorized>
<ExtraLayerAuthorized>
<p>Authorized through OIDC and extra layer</p>
</ExtraLayerAuthorized>
<NotExtraLayerAuthorized>
<p>Authorized through OIDC, but NOT extra layer</p>
</NotExtraLayerAuthorized>
</Authorized>
<NotAuthorized>
<p>No authorization</p>
</NotAuthorized>
</AuthorizeView>`
请注意是服务器还是WASM。
一个很好的方法就是在标准AuthenticationStateProvider的现有ClaimsPrincipal
上添加一个额外的ClaimsIdentity
。
以下是如何在服务器中执行此操作。有关其作用的解释,请参见注释。
public class MyAuthenticationStxateProvider : ServerAuthenticationStateProvider
{
public async override Task<AuthenticationState> GetAuthenticationStateAsync()
{
// Call the base to get the AuthState and the user provided in the Security Headers by the server
var authstate = await base.GetAuthenticationStateAsync();
var user = authstate.User;
if (user?.Identity?.IsAuthenticated ?? false)
{
// Do whatever you want here to retrieve the additional user information you want to
// include in the ClaimsPrincipal - probably some form of Identity Service
// Construct a ClaimsIdentity instance to attach to the ClaimsPrincipal
// I just added a role as an example
var myIdentity = new ClaimsIdentity(new[] { new Claim(ClaimTypes.Role, "User") });
// Add it to the existing ClaimsPrincipal
user.AddIdentity(myIdentity);
}
// construct a new state with the updated ClaimsPrincipal
// - or an empty one of you didn't get a user in the first place
// All the Authorization components and classes will now use this ClaimsPrincipal
return new AuthenticationState(user ?? new ClaimsPrincipal());
}
}
设置为使用Auth0作为身份验证提供程序。
"AllowedHosts": "*",
"Auth0": {
"Domain": "xxxxx.eu.auth0.com",
"ClientId": "xxxxxxxxxxxxxxxxxxxxxx",
}
服务注册看起来像这样:
builder.Services.AddRazorPages();
builder.Services.AddServerSideBlazor();
builder.Services.AddSingleton<WeatherForecastService>();
builder.Services
.AddAuth0WebAppAuthentication(options => {
options.Domain = builder.Configuration["Auth0:Domain"];
options.ClientId = builder.Configuration["Auth0:ClientId"];
});
builder.Services.AddAuthorization();
builder.Services.AddScoped<AuthenticationStateProvider, MyAuthenticationStateProvider>();
Login.cshtml.cs
public class LoginModel : PageModel
{
public async Task OnGet(string redirectUri)
{
await HttpContext.ChallengeAsync("Auth0", new
AuthenticationProperties
{ RedirectUri = redirectUri });
}
}
注销.cs.html.cs
public class LogoutModel : PageModel
{
public async Task<IActionResult> OnGetAsync()
{
await HttpContext.SignOutAsync();
return Redirect("/");
}
}
然后这个页面演示了当我们有一个有效的用户时登录和注销以及添加第二个身份。
@page "/"
@inject NavigationManager NavManager
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?" />
<div>
<button class="btn btn-danger" @onclick=this.LogOut>Log Out</button>
<button class="btn btn-primary" @onclick=this.LogIn>Log In</button>
</div>
<h2>Claims</h2>
<dl>
@foreach (var claim in user.Claims)
{
<dt>@claim.Type</dt>
<dd>@claim.Value</dd>
}
</dl>
@code {
private ClaimsPrincipal user = new ClaimsPrincipal();
[CascadingParameter] private Task<AuthenticationState> authStateProvider { get; set; } = default!;
protected override async Task OnInitializedAsync()
{
var authState = await authStateProvider;
user = authState.User;
}
private void LogIn()
{
var returnUrl = NavManager.Uri;
NavManager.NavigateTo($"login?redirectUri={returnUrl}", forceLoad: true);
}
private void LogOut()
{
var returnUrl = NavManager.Uri;
NavManager.NavigateTo($"logout?redirectUri={returnUrl}", forceLoad: true);
}
}