【问题标题】:Issue With ClaimsIdentity In .NET Core 2 Middleware Solution.NET Core 2 中间件解决方案中的 ClaimsIdentity 问题
【发布时间】:2017-09-05 22:56:25
【问题描述】:

刚开始我的第一个 .net core 2 Web 应用程序实现。不幸的是,由于业务需求,用户必须通过遗留表单登录进行身份验证,用户名/密码被处理到 oracle db,当用户通过身份验证时,会生成一个会话 ID 并将其附加到启动的应用程序的基本 URL 中。非常古老的学校,但它有效。

您可以想象会话 ID 已过期,因此它必须由我的应用程序验证。很简单,我将从查询字符串中检索到的会话 ID 传递给我的 Oracle API,响应是一个包含用户信息(例如名字、姓氏等)的对象。

此 API 调用成功完成后,我创建一个新的 ClaimsIdentity 和 Principal 并调用 SignInAsync() 方法。

我目前在我的 Startup.cs 中注册的自定义中间件中执行此操作。我会在 Login Controller 方法中以通常的方式处理这个问题,但是由于我的应用程序中没有登录,所以除了在我编写的中间件中我看不到任何其他方式。

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 为假。

我在这里缺少什么?感谢您的建议,这是我以前不必处理的那些奇怪的边缘情况之一……因此需要自定义中间件。

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

【问题讨论】:

    标签: c# asp.net .net asp.net-core claims-based-identity


    【解决方案1】:

    您真的不应该为此使用自己的中间件。内置的身份验证和授权堆栈功能强大,足以应对您的情况。事实上,负责 ASP.NET Core 项目 basically† said in a talk 的身份验证堆栈的 .NET 安全 PM 巴里·多兰斯(Barry Dorrans)说,如果它不适用于您的用例,您应该给他发一封电子邮件,他们会修复它。

    相反,您应该考虑为此编写自己的身份验证处理程序。这样,您就可以获得整个身份验证和授权基础架构,而不会遇到额外的障碍。一切都会好起来的。

    为此,您基本上必须实现并注册一个IAuthenticationHandler

    我建议您查看CookieAuthenticationHandler,因为它的工作与您正在尝试做的工作类似:根据随 HTTP 请求发送的信息重建声明身份。只是您使用的是查询参数和数据库,而不是 cookie 数据。

    根据您希望通用应用程序流程如何工作,您甚至可以考虑将其转变为远程身份验证提供程序,将其与 cookie 身份验证相结合——就像一个简化的 OAuth 流程:您收到一个请求,如果您这样做了没有 cookie,您挑战您的自定义身份验证处理程序,该处理程序重定向到您的旧登录掩码。在那里,您登录,它会将您发送回应用程序的特殊 URL,并附加会话 ID(例如 /signin-session?sessionid=12345)。您的远程身份验证处理程序处理该请求,查询数据库并根据信息构造一个身份并将其传递给 cookie 身份验证处理程序。然后那个人会将身份保存在一个安全的 cookie 中,因此您不再需要针对每个请求查询数据库,也不再需要每个 URL 中的会话 ID。

    †​​ 说句公道话,他说的只是授权部分;但我敢肯定,他也适用于整个堆栈,因为它真的很强大。

    【讨论】:

    • 感谢详细信息。你提出了一个非常有效的观点,当我昨晚进行实验时,我得出的结论是我试图强制中间件适用于它不是为它设计的情况。查看 CookieAuthenticationHandler 的文档并同时查看:docs.microsoft.com/en-us/aspnet/core/security/authentication/… 我基本上已经准备好大部分代码,只需要重构。还有一些其他边缘情况...例如仅在命中特定 url 路径时触发身份验证提供程序,但除此之外,我认为我有一个良好的开端...谢谢!
    猜你喜欢
    • 2020-12-07
    • 1970-01-01
    • 2016-10-24
    • 1970-01-01
    • 2018-07-16
    • 2017-09-01
    • 1970-01-01
    • 2020-05-12
    • 2018-12-20
    相关资源
    最近更新 更多