我使用identityserver4进行身份验证,其布局如下:identityserver4->Web Api->Blazor WASM客户端(独立(。一切都经过了验证,运行良好。我从经过身份验证的用户声明一直到wasm客户端。我现在正试图添加更多直接来自数据库的索赔。我本可以将声明添加到identityserver令牌中,但令牌太大(>2kb(,然后identityserver停止工作。显然,这是一个已知的问题。
因此,我想建立授权,并试图保持来自identityserver的jwt令牌较小。
在program.cs文件中,我有一个类似于so 的http客户端
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
builder.Services.AddOidcAuthentication(options=>//在此处配置您的身份验证提供程序选项。//有关详细信息,请参阅https://aka.ms/blazor-standalone-auth//builder.Configuration.Bind("本地",options.ProviderOptions(;…提供商选项
options.ProviderOptions.ResponseType = "code";
options.UserOptions.RoleClaim = "role";
}).AddAccountClaimsPrincipalFactory<CustomAccountClaimsPrincipalFactory>();
await builder.Build().RunAsync();
在文件CustomAccountClaimsPrincipalFactory中,我有这个
public class CustomAccountClaimsPrincipalFactory
: AccountClaimsPrincipalFactory<RemoteUserAccount>
{
private const string Planet = "planet";
[Inject]
public HttpClient Http { get; set; }
public CustomAccountClaimsPrincipalFactory(IAccessTokenProviderAccessor accessor)
: base(accessor) {
}
public async override ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account,
RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);
if (user.Identity.IsAuthenticated)
{
var identity = (ClaimsIdentity)user.Identity;
var claims = identity.Claims.Where(a => a.Type == Planet);
if (!claims.Any())
{
identity.AddClaim(new Claim(Planet, "mars"));
}
//get user roles
//var url = $"/Identity/users/112b7de8-614f-40dc-a9e2-fa6e9d2bf85a/roles";
var dResources = await Http.GetFromJsonAsync<List<somemodel>>("/endpoint");
foreach (var item in dResources)
{
identity.AddClaim(new Claim(item.Name, item.DisplayName));
}
}
return user;
}
}
这不起作用,因为调用httpclient时httpclient不是biolt,并且http客户端使用与构建基本http客户端相同的构建器。
我该怎么做?
您可以创建IProfileService
并根据需要进行自定义:
var builder = services.AddIdentityServer(options =>
...
.AddProfileService<IdentityProfileService>();
public class IdentityProfileService : IProfileService
{
private readonly IUserClaimsPrincipalFactory<ApplicationUser> _claimsFactory;
private readonly UserManager<ApplicationUser> _userManager;
public IdentityProfileService(IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory, UserManager<ApplicationUser> userManager)
{
_claimsFactory = claimsFactory;
_userManager = userManager;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
if (user == null)
{
throw new ArgumentException("");
}
var principal = await _claimsFactory.CreateAsync(user);
var claims = principal.Claims.ToList();
//Add more claims like this
//claims.Add(new System.Security.Claims.Claim("MyProfileID", user.Id));
context.IssuedClaims = claims;
}
public async Task IsActiveAsync(IsActiveContext context)
{
var sub = context.Subject.GetSubjectId();
var user = await _userManager.FindByIdAsync(sub);
context.IsActive = user != null;
}
}
保持访问令牌较小,并且只包括通过JwtBearer身份验证步骤所需的声明。
然后,在接收访问令牌的API中,您可以简单地创建一个授权策略,查找用户的附加声明并评估他是否有访问权限。
您可以在简单的策略定义或更高级的授权处理程序中做到这一点,如下面的代码:
public class CheckIfAccountantHandler : AuthorizationHandler<CanViewReportsRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
CanViewReportsRequirement requirement)
{
bool result = CallTheCheckIfAccountantService();
if(result)
context.Succeed(requirement);
return Task.CompletedTask;
}
}
样品要求可以定义为:
public class CanViewReportsRequirement : IAuthorizationRequirement
{
public int StartHour { get; }
public int EndHour { get; }
public CanViewReportsRequirement(int startHour, int endHour)
{
StartHour = startHour;
EndHour = endHour;
}
}
重要的是要降低应用程序的复杂性,不要试图让它变得更难。只是为了让系统更容易推理!