This issue appears to be related to authentication cookies and cross-domain communication in a Citrix environment with different Windows domains.
- First, modify your
Program.cs
to properly configure the authentication cookie settings:
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
})
.AddIdentityCookies(options =>
{
// Configure application cookie
options.ApplicationCookie.Configure(cookie =>
{
// Set cookie properties
cookie.Cookie.Name = ".AspNetCore.Identity.Application";
cookie.Cookie.SameSite = SameSiteMode.Lax;
cookie.Cookie.SecurePolicy = CookieSecurePolicy.Always;
// Set sliding expiration
cookie.ExpireTimeSpan = TimeSpan.FromHours(8);
cookie.SlidingExpiration = true;
// Important: Handle forbidden and redirect
cookie.Events = new CookieAuthenticationEvents
{
OnRedirectToLogin = context =>
{
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
return Task.CompletedTask;
},
OnRedirectToAccessDenied = context =>
{
context.Response.StatusCode = StatusCodes.Status403Forbidden;
return Task.CompletedTask;
}
};
});
});
// Add custom claims transformation to reduce cookie size
builder.Services.AddScoped<IClaimsTransformation, MinimalClaimsTransformation>();
- Create a minimal claims transformation to reduce cookie size:
public class MinimalClaimsTransformation : IClaimsTransformation { public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { var identity = (ClaimsIdentity)principal.Identity; // Keep only essential claims var essentialClaims = new[] { ClaimTypes.NameIdentifier, ClaimTypes.Name, ClaimTypes.Email, ClaimTypes.Role }; var claims = identity.Claims .Where(c => essentialClaims.Contains(c.Type)) .ToList(); var newIdentity = new ClaimsIdentity( claims, identity.AuthenticationType, ClaimTypes.Name, ClaimTypes.Role); return Task.FromResult(new ClaimsPrincipal(newIdentity)); } }
- Add IIS configuration in
web.config
:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<security>
<requestFiltering>
<!-- Increase header size limits -->
<requestLimits maxQueryString="8192" maxUrl="8192" maxAllowedContentLength="30000000" />
</requestFiltering>
</security>
<handlers>
<remove name="aspNetCore" />
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModuleV2" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="dotnet"
arguments=".\YourApp.dll"
stdoutLogEnabled="false"
stdoutLogFile=".\logs\stdout"
hostingModel="inprocess">
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Production" />
</environmentVariables>
</aspNetCore>
</system.webServer>
</configuration>
- Modify your
App.razor
to handle authentication state:<CascadingAuthenticationState> <Router AppAssembly="@typeof(App).Assembly"> <Found Context="routeData"> <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)"> <NotAuthorized> @if (context.User.Identity?.IsAuthenticated != true) { <RedirectToLogin /> } else { <p>You are not authorized to access this resource.</p> } </NotAuthorized> <Authorizing> <div class="loading">Loading...</div> </Authorizing> </AuthorizeRouteView> </Found> <NotFound> <PageTitle>Not found</PageTitle> <LayoutView Layout="@typeof(MainLayout)"> <p>Sorry, there's nothing at this address.</p> </LayoutView> </NotFound> </Router> </CascadingAuthenticationState>
- Add these settings to your
appsettings.json
:{ "DetailedErrors": true, "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "Authentication": { "Cookie": { "MaxAge": 480, // 8 hours in minutes "SlidingExpiration": true } } }