IdentityServer4显示404-请求太长
我做错了,返回404“错误请求太长消息”。 我的场景如下:我有一个IdentityServer4充当IdentityProvider,还有一个WebApp使用令牌进行访问。 在IS4中,我为索赔集合中的用户设置了大约200个角色(Request.User.Claims)。 当我打开另一个WebApp时,会弹出错误 有人能告诉我如何正确地将用户角色发送到WebApp中使用吗。所以我可以使用User.IsInRole({some role})。 我只看到一些示例发送了一些角色,但没有我需要的那么多 当你需要更多关于某事的信息时,告诉我你需要知道什么来回答我的问题 我使用以下站点设置IS4: 从PluralSite课程 更新:我做的方式不对。下面的代码是我需要让AuthControllerAPI授权工作,它卡在BealerTokenHandler中,并且“expires\u at”为空。因此,我认为我需要以某种方式将访问令牌授予HttpClient。请参见下面的“我的代码/设置”: IS4启动=>ConfigurationService结束时:IdentityServer4显示404-请求太长,identityserver4,core,identity,user-roles,Identityserver4,Core,Identity,User Roles,我做错了,返回404“错误请求太长消息”。 我的场景如下:我有一个IdentityServer4充当IdentityProvider,还有一个WebApp使用令牌进行访问。 在IS4中,我为索赔集合中的用户设置了大约200个角色(Request.User.Claims)。 当我打开另一个WebApp时,会弹出错误 有人能告诉我如何正确地将用户角色发送到WebApp中使用吗。所以我可以使用User.IsInRole({some role})。 我只看到一些示例发送了一些角色,但没有我需要的那么多
//Set named HttpClient settings for API to get roles of user
services.AddHttpContextAccessor();
services.AddTransient<BearerTokenHandler>();
services.AddHttpClient("AuthClient", client =>
{
client.BaseAddress = new Uri("https://localhost:44318/");
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
}).AddHttpMessageHandler<BearerTokenHandler>();
Bealertokenhandler:
public class BearerTokenHandler : DelegatingHandler
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IHttpClientFactory _httpClientFactory;
public BearerTokenHandler(IHttpContextAccessor httpContextAccessor,
IHttpClientFactory httpClientFactory)
{
_httpContextAccessor = httpContextAccessor ??
throw new ArgumentNullException(nameof(httpContextAccessor));
_httpClientFactory = httpClientFactory ??
throw new ArgumentNullException(nameof(httpClientFactory));
}
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var accessToken = await GetAccessTokenAsync();
if (!string.IsNullOrWhiteSpace(accessToken))
{
request.SetBearerToken(accessToken);
}
return await base.SendAsync(request, cancellationToken);
}
public async Task<string> GetAccessTokenAsync()
{
// get the expires_at value & parse it
var expiresAt = await _httpContextAccessor.HttpContext.GetTokenAsync("expires_at");
var expiresAtAsDateTimeOffset = DateTimeOffset.Parse(expiresAt, CultureInfo.InvariantCulture);
if ((expiresAtAsDateTimeOffset.AddSeconds(-60)).ToUniversalTime() > DateTime.UtcNow)
return await _httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken); // no need to refresh, return the access token
var idpClient = _httpClientFactory.CreateClient("IDPClient");
// get the discovery document
var discoveryReponse = await idpClient.GetDiscoveryDocumentAsync();
// refresh the tokens
var refreshToken = await _httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken);
var refreshResponse = await idpClient.RequestRefreshTokenAsync(new RefreshTokenRequest {
Address = discoveryReponse.TokenEndpoint,
ClientId = "mvc",
ClientSecret = "secret",
RefreshToken = refreshToken
});
// store the tokens
var updatedTokens = new List<AuthenticationToken>();
updatedTokens.Add(new AuthenticationToken {
Name = OpenIdConnectParameterNames.IdToken,
Value = refreshResponse.IdentityToken
});
updatedTokens.Add(new AuthenticationToken {
Name = OpenIdConnectParameterNames.AccessToken,
Value = refreshResponse.AccessToken
});
updatedTokens.Add(new AuthenticationToken {
Name = OpenIdConnectParameterNames.RefreshToken,
Value = refreshResponse.RefreshToken
});
updatedTokens.Add(new AuthenticationToken {
Name = "expires_at",
Value = (DateTime.UtcNow + TimeSpan.FromSeconds(refreshResponse.ExpiresIn)).
ToString("o", CultureInfo.InvariantCulture)
});
// get authenticate result, containing the current principal & properties
var currentAuthenticateResult = await _httpContextAccessor.HttpContext.AuthenticateAsync(CookieAuthenticationDefaults.AuthenticationScheme);
// store the updated tokens
currentAuthenticateResult.Properties.StoreTokens(updatedTokens);
// sign in
await _httpContextAccessor.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, currentAuthenticateResult.Principal, currentAuthenticateResult.Properties);
return refreshResponse.AccessToken;
}
public类BearerTokenHandler:DelegatingHandler
{
专用只读IHttpContextAccessor\u httpContextAccessor;
私有只读IHttpClientFactory\U httpClientFactory;
公共承载器TokenHandler(IHttpContextAccessor httpContextAccessor,
IHttpClientFactory(httpClientFactory)
{
_httpContextAccessor=httpContextAccessor??
抛出新ArgumentNullException(nameof(httpContextAccessor));
_httpClientFactory=httpClientFactory??
抛出新ArgumentNullException(nameof(httpClientFactory));
}
受保护的覆盖异步任务SendAsync(
HttpRequestMessage请求,
取消令牌(取消令牌)
{
var accessToken=wait GetAccessTokenAsync();
如果(!string.IsNullOrWhiteSpace(accessToken))
{
request.SetBearerToken(accessToken);
}
返回wait base.sendaync(请求、取消令牌);
}
公共异步任务GetAccessTokenAsync()
{
//获取expires\u at值并解析它
var expiresAt=await_httpContextAccessor.HttpContext.GetTokenAsync(“expires_at”);
var expiresAtAsDateTimeOffset=DateTimeOffset.Parse(expiresAt,CultureInfo.InvariantCulture);
if((expiresAtAsDateTimeOffset.AddSeconds(-60)).ToUniversalTime()>DateTime.UtcNow)
return wait _httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);//无需刷新,返回访问令牌
var idpClient=_httpClientFactory.CreateClient(“idpClient”);
//获取发现文档
var discoveryReponse=await idpClient.GetDiscoveryDocumentAsync();
//刷新令牌
var refreshttoken=wait_httpContextAccessor.HttpContext.GetTokenAsync(OpenIdConnectParameterNames.refreshttoken);
var refreshResponse=等待idpClient.RequestRefreshTokenAsync(新的RefreshTokenRequest{
地址=discoveryReponse.TokenEndpoint,
ClientId=“mvc”,
ClientSecret=“secret”,
RefreshToken=RefreshToken
});
//储存代币
var updatedTokens=新列表();
updatedTokens.Add(新身份验证令牌{
Name=OpenIdConnectParameterNames.IdToken,
值=refreshResponse.IdentityToken
});
updatedTokens.Add(新身份验证令牌{
Name=OpenIdConnectParameterNames.AccessToken,
值=refreshResponse.AccessToken
});
updatedTokens.Add(新身份验证令牌{
Name=OpenIdConnectParameterNames.RefreshToken,
值=refreshResponse.RefreshToken
});
updatedTokens.Add(新身份验证令牌{
Name=“到期日”,
值=(DateTime.UtcNow+TimeSpan.FromSeconds(refreshResponse.ExpiresIn))。
ToString(“o”,CultureInfo.InvariantCulture)
});
//获取包含当前主体和属性的身份验证结果(&P)
var currentAuthenticateResult=wait_httpContextAccessor.HttpContext.AuthenticateTasync(CookieAuthenticationDefaults.AuthenticationScheme);
//存储更新的令牌
currentAuthenticateResult.Properties.StoreTokens(更新的Tokens);
//登录
wait_httpContextAccessor.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme、currentAuthenticateResult.Principal、currentAuthenticateResult.Properties);
返回refreshResponse.AccessToken;
}
如果您需要向给定用户添加200个角色,那么您肯定是做错了。角色列表不应该包含在令牌中,我猜一个用户永远不会是200个角色的一部分?只有少数?您应该只在令牌中包含实际用于给定用户的角色
这段视频我是一个很好的起点
例如,在客户端应用程序中,如果需要在登录时查找其他信息,则可以使用声明转换,如:
public class BonusLevelClaimTransformation : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
if (!principal.HasClaim(c => c.Type == "bonuslevel"))
{
//Lookup bonus level.....
principal.Identities.First().AddClaim(new Claim("bonuslevel", "12345"));
}
return Task.FromResult(principal);
}
}
公共类BonusLevelClaimTransformation:IClaimsTransformation
{
公共任务TransformAsync(ClaimsPrincipal主体)
{
if(!principal.HasClaim(c=>c.Type==“bonuslevel”))
{
//查找奖金级别。。。。。
principal.identies.First().AddClaim(新索赔(“bonuslevel”,“12345”));
}
返回任务.FromResult(主体);
}
}
或者,您可以在客户端中使用策略(而不是基于角色)授权概念,并创建一个处理程序,为您查找其他权限,如:
options.AddPolicy("ViewReports", policy =>
policy.Requirements.Add(new CanViewReportsRequirement(startHour: 9,
endHour: 18)));
public class CanViewReportsRequirement : IAuthorizationRequirement
{
public int StartHour { get; }
public int EndHour { get; }
public CanViewReportsRequirement(int startHour, int endHour)
{
StartHour = startHour;
EndHour = endHour;
}
}
//You can have one more handler connected to the requirement above
public class CheckIfAccountantHandler : AuthorizationHandler<CanViewReportsRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
CanViewReportsRequirement requirement)
{
bool result = CallCheckIfAccountantService();
if(result)
context.Succeed(requirement);
return Task.CompletedTask;
}
}
options.AddPolicy(“查看报告”,策略=>
策略.要求.添加(新的CanViewReports要求)(起始日期:9,
结束
public class BonusLevelClaimTransformation : IClaimsTransformation
{
public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
if (!principal.HasClaim(c => c.Type == "bonuslevel"))
{
//Lookup bonus level.....
principal.Identities.First().AddClaim(new Claim("bonuslevel", "12345"));
}
return Task.FromResult(principal);
}
}
options.AddPolicy("ViewReports", policy =>
policy.Requirements.Add(new CanViewReportsRequirement(startHour: 9,
endHour: 18)));
public class CanViewReportsRequirement : IAuthorizationRequirement
{
public int StartHour { get; }
public int EndHour { get; }
public CanViewReportsRequirement(int startHour, int endHour)
{
StartHour = startHour;
EndHour = endHour;
}
}
//You can have one more handler connected to the requirement above
public class CheckIfAccountantHandler : AuthorizationHandler<CanViewReportsRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
CanViewReportsRequirement requirement)
{
bool result = CallCheckIfAccountantService();
if(result)
context.Succeed(requirement);
return Task.CompletedTask;
}
}