我有一个中间件,它在用户登录后使用AzureAd
向用户添加自定义角色,它运行良好,但我有个问题,例如,在我登录后,有人也在我之后登录,这个用户仍然拥有我为我添加的相同角色。我的问题是:为什么blazor按照这种方式即使在注销后也会为不同的用户保存这些角色?我想了解
这是中间件
public class RoleHandler
{
private readonly RequestDelegate _next;
private List<string> Roles { get; set; }
public RoleHandler(RequestDelegate Next)
{
_next = Next;
}
public async Task InvokeAsync(HttpContext context, IGenericHttpClient<Role> httpClient)
{
if (Roles == null || Roles.Count == 0)
{
Roles = await GetRole(context, httpClient);
}
else
{
foreach (var role in Roles)
{
//Add roles to this user, in this case user can be admin or developer ...
context.User.Identities.FirstOrDefault().AddClaim(new Claim(ClaimTypes.Role, role));
}
}
await _next(context);
}
public async Task<List<string>> GetRole(HttpContext context, IGenericHttpClient<Role> httpClient)
{
List<string> rolesList = new();
//Get role from api like [guid, admin]
var appUserRoles = await httpClient.GetJsonAsync("/api/roles/search?id=XXX");
//Get role from user as guid
var RolesString = context.User.Claims
.Select(c => c.Value).ToList();
foreach (var appRole in appUserRoles)
{
foreach (var role in RolesString)
{
if (appRole.RoleString == role)
{
rolesList.Add(appRole.Name);
}
}
}
return rolesList;
}
}
在启动时配置服务
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<ILoggerManager, LoggerManager>();
var initialScopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
services.AddScoped(typeof(IGenericHttpClient<>), typeof(GenericHttpClient<>));
services.AddControllersWithViews()
.AddMicrosoftIdentityUI();
services.AddAuthorization(options =>
{
// By default, all incoming requests will be authorized according to the default policy
options.FallbackPolicy = options.DefaultPolicy;
});
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddRazorPages();
services.AddServerSideBlazor()
.AddMicrosoftIdentityConsentHandler();
}
GenericHttpClient
public class GenericHttpClient<T> : IGenericHttpClient<T> where T : class
{
private readonly IHttpClientFactory _clientFactory;
private HttpClient _client;
private readonly IConfiguration _configuration;
public GenericHttpClient(IHttpClientFactory clientFactory,
IConfiguration configuration)
{
_clientFactory = clientFactory;
_configuration = configuration;
_client = _clientFactory.CreateClient();
_client.BaseAddress = new Uri("https://localhost");
}
public async ValueTask<List<T>> GetJsonAsync(string url)
{
using HttpResponseMessage response = await _client.GetAsync(url);
ValidateResponse(response);
var content = await ValidateContent(response).ReadAsStringAsync();
return JsonSerializer.Deserialize<List<T>>(content, new JsonSerializerOptions() { PropertyNameCaseInsensitive=true});
}
// ......
}
}
在Startup.cs
文件中注册HttpClient服务时,应该使用AddScoped
。
相关文章:
1.AddTransient、AddScoped和AddSingleton服务差异
2.不能使用Singleton的作用域服务——ASP.NET Core DI作用域的教训