feat(auth): add YARP auth forwarding and dashboard search filtering

- Add YARP proxy middleware to attach Bearer token from bff_session
  cookie to all YARP-proxied requests (users, roles, audit pages)
- Dashboard search: bind input with oninput and filter shops by
  name/slug/category client-side via FilteredShops property

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ho Ngoc Hai
2026-03-25 16:47:28 +07:00
parent 6fbc475fdd
commit 43d334ca7d
2 changed files with 33 additions and 5 deletions

View File

@@ -21,7 +21,7 @@
<div class="admin-topbar__right">
<div class="admin-search">
<i data-lucide="search"></i>
<input type="text" placeholder="@L["Dashboard_Search"]" @bind="SearchQuery" />
<input type="text" placeholder="@L["Dashboard_Search"]" @bind="SearchQuery" @bind:event="oninput" />
</div>
<button class="admin-icon-btn" title="Thông báo">
<i data-lucide="bell"></i>
@@ -113,7 +113,7 @@
}
else
{
@foreach (var shop in _shops)
@foreach (var shop in FilteredShops)
{
var stats = _shopStats.FirstOrDefault(s => s.ShopId == shop.Id);
<a href="/admin/shop/@shop.Id/overview" class="admin-store-card" style="text-decoration:none;color:inherit;cursor:pointer;">
@@ -275,6 +275,16 @@
private List<PosDataService.ShopInfo> _shops = new();
private List<PosDataService.ShopStatsInfo> _shopStats = new();
private List<PosDataService.ServiceHealthInfo> _serviceHealth = new();
// EN: Filter shops by search query (name, slug, category)
// VI: Lọc shops theo từ khóa tìm kiếm (tên, slug, ngành hàng)
private List<PosDataService.ShopInfo> FilteredShops => string.IsNullOrWhiteSpace(SearchQuery)
? _shops
: _shops.Where(s =>
(s.Name?.Contains(SearchQuery, StringComparison.OrdinalIgnoreCase) == true) ||
(s.Slug?.Contains(SearchQuery, StringComparison.OrdinalIgnoreCase) == true) ||
(s.Category?.Contains(SearchQuery, StringComparison.OrdinalIgnoreCase) == true))
.ToList();
private bool _healthLoading = false;
private DateTime? _healthCheckedAt;

View File

@@ -178,9 +178,27 @@ app.MapStaticAssets();
// VI: Map endpoint health check
app.MapHealthChecks("/health");
// EN: Map YARP Reverse Proxy routes to microservices
// VI: Map các routes YARP Reverse Proxy đến microservices
app.MapReverseProxy();
// EN: Map YARP Reverse Proxy routes to microservices.
// Middleware attaches Bearer token from bff_session cookie for all proxied requests
// (mirrors AuthForwardingHandler but for YARP routes: users, roles, audit, etc.)
// VI: Map các routes YARP Reverse Proxy đến microservices.
// Middleware đính kèm Bearer token từ bff_session cookie cho tất cả request qua proxy
// (tương tự AuthForwardingHandler nhưng cho YARP routes: users, roles, audit, v.v.)
app.MapReverseProxy(proxyPipeline =>
{
proxyPipeline.Use(async (context, next) =>
{
if (!context.Request.Headers.ContainsKey("Authorization"))
{
if (context.Request.Cookies.TryGetValue("bff_session", out var token)
&& !string.IsNullOrEmpty(token))
{
context.Request.Headers["Authorization"] = $"Bearer {token}";
}
}
await next();
});
});
// EN: Localization Support - Serve index.html with dynamic base tag for specific cultures
// VI: Hỗ trợ đa ngôn ngữ - Phục vụ index.html với base tag động cho các ngôn ngữ cụ thể