I think my error is caused by some configuration. I must configure my Blazor application to work with Nginx reverse proxy.
tow years ago, I use below code to let my blazor application work with Nginx reverse proxy.
#if RELEASE
//这里的作用是:跳转到微信的登入页面时,原始网址是https而不是http
app.Use(async (context, next) =>
{
context.Request.Scheme = "https";
await next.Invoke();
});
#endif
app.UseAbpRequestLocalization();
It always work very well. Now I follow your link and changed above code as below.
#if RELEASE
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
#endif
app.UseAbpRequestLocalization();
Full code is just like this:
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
#if RELEASE
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
#endif
app.UseAbpRequestLocalization();
if (!env.IsDevelopment())
{
app.UseErrorPage();
app.UseHsts();
app.UseHttpsRedirection();
}
app.UseCorrelationId();
app.UseStaticFiles();
app.UseRouting();
app.UseAbpSecurityHeaders();
app.UseCors();
app.UseAuthentication();
app.UseAbpOpenIddictValidation();
if (MultiTenancyConsts.IsEnabled)
{
app.UseMultiTenancy();
}
app.UseUnitOfWork();
app.UseDynamicClaims();
app.UseAuthorization();
app.UseAuditing();
app.UseAbpSerilogEnrichers();
app.UseConfiguredEndpoints();
}
After I do above changed. I got error while access OpenDict application.
error "invalid_request"
error_description "This server only accepts HTTPS requests."
error_uri "https://documentation.openiddict.com/errors/ID2083"
But I still get error in Blazor application.
[12:33:13 WRN] Could not find IdentityClientConfiguration for Gitlab. Either define a configuration for Gitlab or set a default configuration.
[12:33:13 INF] Start processing HTTP request GET https://erp2api.abc.cn:222/api/gitlab/project/id?repositoryId=85&api-version=1.0
[12:33:13 INF] Sending HTTP request GET https://erp2api.abc.cn:222/api/gitlab/project/id?repositoryId=85&api-version=1.0
[12:33:14 INF] Received HTTP response headers after 168.3319ms - 200
[12:33:14 INF] End processing HTTP request after 168.6008ms - 200
I created a test controller as below.
[HttpGet]
[Route("test")]
public IActionResult Get()
{
// 获取所有请求头
var headers = HttpContext.Request.Headers;
StringBuilder headerInfo = new StringBuilder();
foreach (var header in headers)
{
headerInfo.AppendLine($"Header: {header.Key} = {string.Join(", ", header.Value)}");
}
// 获取所有Cookies
var cookies = Request.Cookies;
foreach (var cookie in cookies)
{
headerInfo.AppendLine($"Cookie: {cookie.Key} = {cookie.Value}");
}
return Content(headerInfo.ToString(), "text/plain");
}
Because I deploy http api as a site. I access my test controller and get below output in browser. It means that the Nginx work well with Cookie: .AspNetCore.Antiforgery.BUGx2_C-Cws
Header: Accept = text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Header: Connection = close
Header: Host = ###.###.cn:###
Header: User-Agent = Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:126.0) Gecko/20100101 Firefox/126.0
Header: Accept-Encoding = gzip, deflate, br, zstd
Header: Accept-Language = zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Header: Cookie = rl_user_id=%22RudderEncrypt%3AU2FsdGVkX18rU95B0qvJbBYLEm4rS3x0H3iFnH%2B5ltjXlQ180T0yRiw4oBfoAETl%22; .AspNetCore.Antiforgery.BUGx2_C-Cws=CfDJ8Aanjc0JmFlIqopqBiRGj8AQdnzUs-h3sav43a81Yt8byDG32lCcJKyM4MCle3XgT_Dp_AJ3WH7L4QL3urlaQoAXn0ZaPVG4j7gPb8xFfAP4kK746Qb5S30g84d4UTv1_MZxIrzkJCpknqmY0KsnaWg; XSRF-TOKEN=CfDJ8Aanjc0JmFlIqopqBiRGj8A8lww8ceglibBW-nSy2hH2ojj_p98hxY2jyLvl3iUyPk6oJX1pUbWaapDHCId9kFP2Uotvf5VM1SDtapecsOuB9vtCSrYLr4nHMsLN0lfnI5QDNTpb2AcjNLora1jFMFE
Header: Upgrade-Insecure-Requests = 1
Header: X-Forwarded-For = 61.174.128.225
Header: X-Forwarded-Proto = https
Header: sec-fetch-dest = document
Header: sec-fetch-mode = navigate
Header: sec-fetch-site = none
Header: sec-fetch-user = ?1
Header: priority = u=1
Cookie: rl_user_id = "RudderEncrypt:U2FsdGVkX18rU95B0qvJbBYLEm4rS3x0H3iFnH+5ltjXlQ180T0yRiw4oBfoAETl"
Cookie: .AspNetCore.Antiforgery.BUGx2_C-Cws = CfDJ8Aanjc0JmFlIqopqBiRGj8AQdnzUs-h3sav43a81Yt8byDG32lCcJKyM4MCle3XgT_Dp_AJ3WH7L4QL3urlaQoAXn0ZaPVG4j7gPb8xFfAP4kK746Qb5S30g84d4UTv1_MZxIrzkJCpknqmY0KsnaWg
Cookie: XSRF-TOKEN = CfDJ8Aanjc0JmFlIqopqBiRGj8A8lww8ceglibBW-nSy2hH2ojj_p98hxY2jyLvl3iUyPk6oJX1pUbWaapDHCId9kFP2Uotvf5VM1SDtapecsOuB9vtCSrYLr4nHMsLN0lfnI5QDNTpb2AcjNLora1jFMFE
May I change the name of cookie for Antiforgery?
Perhaps the name of cookie contains special character. So nginx block it?
I am very practices with HTTPS reverse proxy. And I added below lines to xxxModule.cs to supprot HTTPS.
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
var app = context.GetApplicationBuilder();
var env = context.GetEnvironment();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
#if RELEASE
//这里的作用是:跳转到微信的登入页面时,原始网址是https而不是http
app.Use(async (context, next) =>
{
context.Request.Scheme = "https";
await next.Invoke();
});
#endif
app.UseAbpRequestLocalization();
if (!env.IsDevelopment())
{
app.UseErrorPage();
}
app.UseCorrelationId();
app.UseStaticFiles();
app.UseRouting();
app.UseAbpSecurityHeaders();
app.UseCors();
app.UseAuthentication();
app.UseAbpOpenIddictValidation();
if (MultiTenancyConsts.IsEnabled)
{
app.UseMultiTenancy();
}
app.UseUnitOfWork();
app.UseDynamicClaims();
app.UseAuthorization();
app.UseAuditing();
app.UseAbpSerilogEnrichers();
app.UseConfiguredEndpoints();
}
#
my blazor application is behined a Nginx veverse proxy.
In fact, all blazer pages get the same exception, include ABP built in CMS module.
[03:30:33 INF] Executing endpoint '/_Host'
[03:30:33 INF] Route matched with {page = "/_Host", action = "", controller = "", area = ""}. Executing page /_Host
[03:30:33 INF] Skipping the execution of current filter as its not the most effective filter implementing the policy Microsoft.AspNetCore.Mvc.ViewFeatures.IAntiforgeryPolicy
[03:30:33 INF] Antiforgery token validation failed. The required antiforgery header value "RequestVerificationToken" is not present.
Microsoft.AspNetCore.Antiforgery.AntiforgeryValidationException: The required antiforgery header value "RequestVerificationToken" is not present.
at Microsoft.AspNetCore.Antiforgery.DefaultAntiforgery.ValidateRequestAsync(HttpContext httpContext)
at Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.ValidateAntiforgeryTokenAuthorizationFilter.OnAuthorizationAsync(AuthorizationFilterContext context)
[03:30:33 INF] Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.AutoValidateAntiforgeryTokenAuthorizationFilter'.
[03:30:33 INF] Executing StatusCodeResult, setting HTTP status code 400
@page "/line"
@using Yee.Erp2.Gitlab.Blazor.Shared
@foreach (ProjectConnector connector in connectors)
{
<h3>@connector</h3>
<ProjectFlow FirstProject="@connector.Project" NextProjectPath="@connector.DownstreamPath" SubPipelineTriggered="StarPipeline" />
}
@code {
List<ProjectConnector> connectors = new List<ProjectConnector>();
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
this.connectors.Add(new ProjectConnector()
{
DownstreamPath = "framework/third/topsdk"
});
}
async void StarPipeline( ProjectDto current, string path)
{
this.connectors.Add(new ProjectConnector()
{
Project = current,
DownstreamPath = path
});
this.StateHasChanged();
}
}
@using System.Text
@using System.Text.RegularExpressions
@inject IProjectAppService ProjectService
<Row>
@foreach (ProjectDto project in projects)
{
<Column ColumnSize="ColumnSize.Is1">
<Card>
<CardHeader>
<Badge Color="Color.Primary" Pill>master</Badge>
<Badge Color="Color.Success">
<Tooltip Text="Confirmed">
<Icon Name="IconName.ArrowRight" aria-label="Confirmed" />
</Tooltip>
</Badge>
</CardHeader>
<CardBody>
@project.Name
</CardBody>
<CardFooter>
<a href="@string.Concat("https://gitlab.mycompany.com/", project.PathWithNamespace)" target="_blank">
打开
</a>
</CardFooter>
</Card>
</Column>
}
</Row>
@code {
[Parameter]
public ProjectDto? FirstProject { get; set; }
[Parameter]
public string? NextProjectPath { get; set; }
public delegate void PathChangedHandler(ProjectDto current, string path);
[Parameter]
public PathChangedHandler SubPipelineTriggered { get; set; }
List<ProjectDto> projects = new List<ProjectDto>();
protected override async Task OnInitializedAsync()
{
await base.OnInitializedAsync();
if (this.FirstProject != null)
{
this.projects.Add(FirstProject);
}
ProjectDto current = await this.ProjectService.GetProjectAsync(NextProjectPath);
projects.Add(current);
while (current != null)
{
List<ProjectDto> next = await this.GetNext(current.Id);
if (next.Count > 0)
{
projects.Add(next.First());
if (next.Count > 1)
{
if (SubPipelineTriggered != null)
{
for (int i = 1; i < next.Count; i++)
{
await InvokeAsync(() => this.SubPipelineTriggered.Invoke(current, next[i].PathWithNamespace));
}
}
}
await InvokeAsync(() => this.StateHasChanged());
current = next.FirstOrDefault();
}
else
{
current = null;
}
}
}
async Task<List<ProjectDto>> GetNext(int projectId)
{
string encodedContent = await this.ProjectService.GetGitlabCiYmlAsync(projectId);
var decodedBytes = Convert.FromBase64String(encodedContent);
var decodedContent = Encoding.UTF8.GetString(decodedBytes);
List<ProjectDto> list = await this.Analyze(decodedContent);
return list;
}
async Task<List<ProjectDto>> Analyze(string yamlContent)
{
List<string> projectPaths = new List<string>();
// 使用正则表达式查找所有匹配项
MatchCollection matches = Regex.Matches(yamlContent, @"^\s*project:\s*(\S.*)$", RegexOptions.Multiline);
foreach (System.Text.RegularExpressions.Match match in matches)
{
projectPaths.Add(match.Groups[1].Value);
}
List<ProjectDto> result = new List<ProjectDto>();
// 输出所有找到的项目路径
foreach (string projectPath in projectPaths)
{
// Console.WriteLine("Extracted project path: " + projectPath);
ProjectDto current = await this.ProjectService.GetProjectAsync(projectPath);
if (current != null)
{
result.Add(current);
}
}
return result;
}
}