具有Windows身份验证的ASP.NET Core身份 [英] ASP.NET Core Identity with Windows Authentication

查看:76
本文介绍了具有Windows身份验证的ASP.NET Core身份的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用.NET Core 3.0 Preview6.
我们有一个启用了Windows身份验证的Intranet应用程序,这意味着只有有效的AD用户才能使用该应用程序.
但是,我们希望使用ASP.NET Identity运行自己的身份验证后端,因为它可以即开即用"地工作.我刚刚使用用户的Windows登录名在AspNetUsers表中添加了一列.

I'm using .NET Core 3.0 Preview6.
We have an Intranet application with enabled Windows authentication which means that only valid AD users are allowed to use the application.
However, we like to run our own authentication backend with ASP.NET Identity, because it works "out-of-the-box". I just added a column to AspNetUsers table with the user's Windows login.

我要完成的是Windows用户使用其Windows登录名自动登录到该应用程序.
我已经创建了自定义身份验证中间件,请参见下面的代码:

What I'd like to accomplish is that Windows users are automatically signed-in to the application with their Windows login.
I already created a custom Authentication middleware, please see code below:

public class AutoLoginMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger _logger;

    public AutoLoginMiddleware(RequestDelegate next, ILogger<AutoLoginMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(HttpContext context, UserService userService, UserManager<IntranetUser> userManager, 
        SignInManager<IntranetUser> signInManager)
    {
        if (signInManager.IsSignedIn(context.User))
        {
            _logger.LogInformation("User already signed in");
        }
        else
        {
            if (context.User.Identity as WindowsIdentity != null)
            {
                _logger.LogInformation($"User with Windows Login {context.User.Identity.Name} needs to sign in");
                var windowsLogin = context.User.Identity.Name;


                var user = await userManager.Users.FirstOrDefaultAsync(u => u.NormalizedWindowsLogin == windowsLogin.ToUpperInvariant());

                if (user != null)
                {
                    await signInManager.SignInAsync(user, true, "automatic");
                    _logger.LogInformation($"User with id {user.Id}, name {user.UserName} successfully signed in");

                    // Workaround
                    context.Items["IntranetUser"] = user;
                }
                else
                {
                    _logger.LogInformation($"User cannot be found in identity store.");
                    throw new System.InvalidOperationException($"user not found.");
                }
            }
        }

        // Pass the request to the next middleware
        await _next(context);
    }
}

文档说 SignInManager.SignInAsync 创建了一个新的 ClaimsIdentity -但似乎从未发生- HttpContext.User 始终保持 WindowsIdentity .在用户再次登录的每个请求中,对 signInManager.IsSignedIn()的调用始终返回false.

The doc says that SignInManager.SignInAsync creates a new ClaimsIdentity - but it seems that never happens - HttpContext.User always stays a WindowsIdentity. On every request the user is signed in again, the call to signInManager.IsSignedIn() always returns false.

我现在的问题是:以这种方式进行自动身份验证通常是一个好主意吗?存在哪些其他方式?

My question now: is it generally a good idea to have automatic authentication in this way? What other ways do exists?

我的下一个要求是拥有一个自定义的 AuthorizationHandler .这里的问题是,有时在 HandleRequirementAsync 方法中, AuthorizationHandlerContext.User.Identity WindowsIdentity ,然后是对 context的调用.User.Identity.Name 引发以下异常:

My next requirement is to have a custom AuthorizationHandler. The problem here is that sometimes in the HandleRequirementAsync method the AuthorizationHandlerContext.User.Identity is a WindowsIdentity and then the call to context.User.Identity.Name raises the following Exception:

System.ObjectDisposedException: Safe handle has been closed.

Object name: 'SafeHandle'.

   at System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean& success)

   at System.StubHelpers.StubHelpers.SafeHandleAddRef(SafeHandle pHandle, Boolean& success)

   at Interop.Advapi32.GetTokenInformation(SafeAccessTokenHandle TokenHandle, UInt32 TokenInformationClass, SafeLocalAllocHandle TokenInformation, UInt32 TokenInformationLength, UInt32& ReturnLength)

   at System.Security.Principal.WindowsIdentity.GetTokenInformation(SafeAccessTokenHandle tokenHandle, TokenInformationClass tokenInformationClass, Boolean nullOnInvalidParam)

   at System.Security.Principal.WindowsIdentity.get_User()

   at System.Security.Principal.WindowsIdentity.<GetName>b__51_0()

   at System.Security.Principal.WindowsIdentity.<>c__DisplayClass67_0.<RunImpersonatedInternal>b__0(Object <p0>)

   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)

我现在的假设是,这两个部分不能很好地协同工作.有时似乎存在计时问题-在对 AutoLoginMiddleware

My assumption now is that these both parts don't work well together. Sometimes it seems there is a timing issue - my custom AuthorizationHandler is called in between the call to AutoLoginMiddleware

推荐答案

此问题现已修复.这是预览版本中的一个错误.现在它正在按预期工作.祝你好运!

This is fixed now. It's been a bug in the preview releases. Now it's working like intended. Good luck!

更新:我想发布.NET Core 3.1 Final的工作代码.

Update: I'd like to post my working code for .NET Core 3.1 Final.

  1. 在框架中间件之后在 Configure 中注册自定义登录中间件是必不可少的:
  1. It's essential to register the custom login middleware after framework middlewares in Configure:

    app.UseAuthentication();
    app.UseAuthorization();
    app.UseMiddleware<AutoLoginMiddleware>();

  1. 在自定义中间件中,登录用户后,您必须调用 CreateUserPrincipalAsync 并将此主体保存到 HttpContext.User 属性.

  1. In the custom middleware, after signing in the user you must call CreateUserPrincipalAsync and save this principal to the HttpContext.User property.

await signInManager.SignInAsync(user, true);
context.User = await signInManager.CreateUserPrincipalAsync(user);

  • 对于Blazor,我们必须使用 AuthenticationStateProvider .它具有属性 User ,其中包含来自 HttpContext ClaimsPrincipal .就是这样.

  • For Blazor, we must use AuthenticationStateProvider. It has a property User which contains the ClaimsPrincipal from HttpContext. That's it.

    您现在可以按照以下方式获取身份用户:

    You are now able to get the Identity user like follows:

    var authState = await _authenticationStateProvider.GetAuthenticationStateAsync();
    var intranetUser = await UserManager.GetUserAsync(authState.User);
    

  • 这篇关于具有Windows身份验证的ASP.NET Core身份的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆