簡體   English   中英

在AES Core 2中間件解決方案中使用ClaimsIdentity的問題

[英]Issue With ClaimsIdentity In .NET Core 2 Middleware Solution

剛開始我的第一個.net核心2 Web應用程序實現。 不幸的是,由於業務需求,用戶必須通過遺留表單登錄進行身份驗證,用戶名/密碼將被處理到oracle db,並且當用戶通過身份驗證時,會生成會話ID並將其附加到啟動的應用程序的基本URL。 很老的學校,但它的工作原理。

您可以想象會話ID到期,因此必須由我的應用程序驗證。 很簡單,我將從查詢字符串檢索的會話ID傳遞給我的Oracle API,響應是一個包含用戶信息的對象,如firstname,lastname等。

在此API調用成功完成后,我創建一個新的ClaimsIdentity和Principal並調用SignInAsync()方法。

我目前在我在Startup.cs中注冊的自定義中間件中執行此操作。 我會在登錄控制器方法中以常規方式處理這個問題,但由於我的應用程序中沒有登錄,我看不到任何其他方式,但在我編寫的中間件中。

public class AuthenticationHandler
{
    private readonly RequestDelegate _next;
    private HttpService _httpService;

    public AuthenticationHandler(RequestDelegate next, HttpService httpService)
    {
        _httpService = httpService;
        _next = next;
    }

    public async Task Invoke(HttpContext context, [FromServices] HttpService httpService)
    {
        if (context.Request.Query.Count == 1)
        {
            var sessionId = context.Request.Query.FirstOrDefault().Value;
            var session = await _httpService.ValidateSession(sessionId);

            if (!string.IsNullOrEmpty(session?.UserId))
            {
                var claims = new List<Claim>()
                {
                    new Claim(CustomClaimTypes.UserId, session.UserId),
                    new Claim(CustomClaimTypes.BuId, session.BuId),
                    new Claim(CustomClaimTypes.SecurityLevel, session.SecurityLevel)
                };

                var identity = new ClaimsIdentity(claims, "TNReadyEVP");
                var principal = new ClaimsPrincipal(identity);

                await Microsoft.AspNetCore.Authentication.AuthenticationHttpContextExtensions.SignInAsync(context, principal);

                var isIn = principal.Identity.IsAuthenticated;
                var isAuthed = (context.User.Identity as ClaimsIdentity).IsAuthenticated;
                await _next.Invoke(context);
            }
            else
            {
                Terminate(context);
            }
        }

        return;
    }

    private async void Terminate(HttpContext context)
    {
        context.Response.StatusCode = 401;
        await context.Response.WriteAsync("Invalid User");
        return;
    }
}

public static class MiddlewareExtensions
{
    public static IApplicationBuilder ValidateSession(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<AuthenticationHandler>();
    }
}

到目前為止這么好,我相信這是正確的解決方案。 但是,當我嘗試通過我的應用程序中的小API獲取聲明時,如下所示,聲明為空,User.Identity.Authenticated為false。

我在這里錯過了什么? 感謝您的建議,這是我之前沒有處理過的那些奇怪的邊緣情況之一......因此需要定制中間件。

    [HttpGet("claims")]
    public async Task<IEnumerable<Claim>> Get()
    {
        var claims = (User as ClaimsPrincipal).Claims;
        return await Task.FromResult(claims);
    }

你真的不應該使用自己的中間件。 內置的身份驗證和授權堆棧功能強大,足以處理您的情況。 事實上,負責ASP.NET核心項目的auth堆棧的.NET安全PM Barry Dorrans 基本上†在一次談話中說 ,如果它不適合你的用例,你應該給他發一封電子郵件,他們會修理它。

相反,您應該考慮為此目的編寫自己的身份驗證處理程序。 這樣,您就可以獲得整個身份驗證和授權基礎架構,而無需額外的障礙。 一切都會奏效。

為此,您基本上必須實現並注冊IAuthenticationHandler

我建議您查看CookieAuthenticationHandler因為它與您嘗試執行的操作類似:從HTTP請求發送的信息中重建聲明標識。 只是您正在使用查詢參數和數據庫而不是cookie數據。

根據您希望一般應用程序流的工作方式,您甚至可以考慮將其轉換為遠程身份驗證提供程序,將其與cookie身份驗證相結合 - 就像一個愚蠢的OAuth流程:您收到請求,如果您沒有cookie,您挑戰自定義身份驗證處理程序,該處理程序重定向到您的舊登錄掩碼。 在那里,您登錄並將其發送回您的應用程序的特殊URL,其中附加了會話ID(例如/signin-session?sessionid=12345 )。 您的遠程身份驗證處理程序處理該請求,查詢數據庫並根據信息構造標識並將其傳遞給cookie身份驗證處理程序。 然后,那個人將身份保存在安全cookie中,因此您不再需要在每個請求上查詢數據庫,並且您也不再需要每個URL中的會話ID。

†公平地說,他只談到那里的授權部分; 但我確信他也意味着整個堆棧,因為它真的很強大。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM