IdentityServer4显示404-请求太长

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})。 我只看到一些示例发送了一些角色,但没有我需要的那么多

我做错了,返回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结束时:

    //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;
    }
}