在Asp Net Core应用程序中,授权是通过API完成的,一旦响应不正常(200),我想返回登录页面。
我正在尝试从对 API 的请求中捕获 HttpContext。我的 HttpClient 位于静态类中。我实现了一个中间件来捕获所有请求,但通过静态 ApiServices 发送的请求不会被捕获。本地请求意味着诸如来自 www 文件夹的图像或引导程序之类的内容。 看起来中间件无法捕获 ApiServices 创建的 httpclient。 为了复制,我使用以下代码创建了一个新项目:
程序.cs
using Microsoft.AspNetCore.Authorization;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
//app.UseMiddleware<AuthorizationMiddleware>();
app.UseRequestAuthorization();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapRazorPages();
app.Run();
ApiServices.cs
public static class ApiServices
{
static readonly HttpClient httpClient;
static readonly HttpClientHandler handler;
static Uri Uri => new("https://localhost:7182");
public static AuthenticateResponse? AuthenticateResponse { get; private set; }
static ApiServices()
{
handler = new HttpClientHandler()
{
CookieContainer = new CookieContainer(),
ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) =>
{
return true;
}
};
httpClient = new HttpClient(handler)
{
BaseAddress = Uri,
Timeout = TimeSpan.FromSeconds(60)
};
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Host = "api.xxxxxxxx.com";
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
}
public static async Task<bool> LoginAsync(Credentials credentials)
{
AuthenticateResponse = null;
var url = $"/{Routes.AuthenticateRoute}/authenticate";
var response = await httpClient.PutAsJsonAsync(url, credentials);
if (response.IsSuccessStatusCode)
{
AuthenticateResponse = await response.Content.ReadFromJsonAsync<AuthenticateResponse>();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthenticateResponse?.Token);
}
return AuthenticateResponse is not null;
}
中间件看起来像这样:
public class AuthorizationMiddleware(RequestDelegate next)
{
private readonly RequestDelegate _next = next;
public async Task Invoke(HttpContext context)
{
if (context.Response.StatusCode==StatusCodes.Status401Unauthorized)
{
context.Request.Path = "/Home/Index";
context.Request.Query = null;
}
await _next(context);
}
}
public static class AuthorizationMiddlewareMiddlewareExtensions
{
public static IApplicationBuilder UseRequestAuthorization(
this IApplicationBuilder builder)
{
return builder.UseMiddleware<AuthorizationMiddleware>();
}
}
和登录页面:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using TurfManagerHelpers.Models;
using TurfManagerHelpers.Services;
namespace ApiServices_Test.Pages
{
public class IndexModel : PageModel
{
[BindProperty]
public Credentials Credentials { get; set; } = new();
private readonly ILogger<IndexModel> _logger;
public string Message { get; set; } = "";
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public void OnGet(string message = "")
{
Message = message;
}
public async Task<ActionResult> OnPostLoginAsync(Credentials credentials)
{
string? message;
if (!ModelState.IsValid)
{
message = "ModelState is iinvalid!";
return RedirectToAction("Get", new { message });
}
var loginSuccess = await ApiServices.LoginAsync(credentials);
if (loginSuccess)
{
message = "you are logged in!";
}
else
{
message = "Invalid login attempt.";
}
return RedirectToAction("Get", new { message });
}
}
}
非常感谢任何帮助或建议。
中间件受到类似请求的影响
<img class="avatar" src="images/logos/V3/TurfManagerLogo_square.png" alt="Avatar">
或
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
但不是
public static async Task<bool> LoginAsync(Credentials credentials)
{
AuthenticateResponse = new();
var url = $"/{Routes.AuthenticateRoute}/authenticate";
var response = await httpClient.PutAsJsonAsync(url, credentials);
if (response.IsSuccessStatusCode)
{
AuthenticateResponse = await response.Content.ReadFromJsonAsync<AuthenticateResponse>();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", AuthenticateResponse?.Token);
}
return AuthenticateResponse is not null;
}
基本上我想捕捉这之间的请求
var response = await httpClient.PutAsJsonAsync(url, credentials);
还有这个
if (response.IsSuccessStatusCode)
MiddleWares将处理您当前的asp.net core应用程序收到的请求,您使用httpclient发送到另一个.net core应用程序(Web Api)的请求将由该应用程序中的中间件处理,永远不会在您当前应用程序的中间件中处理
从你的描述来看:
在 Asp Net Core 应用程序中,授权是通过 API 完成的 一旦响应不正常(200),我想返回登录页面。
您收到的 JWT 令牌旨在保护您的 webapi 中的资源,而不是您当前的应用程序(Razor Page),并且您无法读取令牌中的声明并将票证分配给 httpcontext,HttpContext.User 将始终为 null ,你还没有真正经过身份验证。
您需要的是远程身份验证
你可以这样配置
builder.Services.AddAuthentication(op =>
{
op.DefaultScheme = "Cookies";
})
// Use Cookie to hold the claims you received from remote server
.AddCookie("Cookies")
.AddOAuth("Scheme1", op =>
{
.......
//set clientId,callbackpath...here
})
这是本文文章
中的完整示例