ASP.NET 具有 Windows 身份验证的核心身份
ASP.NET Core Identity with Windows Authentication
我正在使用 .NET Core 3.0 Preview6。
我们有一个启用了 Windows 身份验证的 Intranet 应用程序,这意味着只允许有效的 AD 用户使用该应用程序。
但是,我们喜欢 运行 我们自己的身份验证后端具有 ASP.NET 身份,因为它有效 "out-of-the-box"。我刚刚使用用户的 Windows 登录名向 AspNetUsers table 添加了一列。
我想要完成的是 Windows 用户使用他们的 Windows 登录名自动登录到应用程序。
我已经创建了自定义身份验证中间件,请参阅下面的代码:
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()
的调用总是 returns 错误。
我现在的问题是:以这种方式进行自动身份验证通常是个好主意吗?还存在哪些其他方式?
我的下一个要求是定制 AuthorizationHandler
。
这里的问题是有时在 HandleRequirementAsync
方法中 AuthorizationHandlerContext.User.Identity
是 WindowsIdentity
然后调用 context.User.Identity.Name
会引发以下异常:
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)
我现在的假设是这两个部分不能很好地协同工作。有时似乎存在时间问题 - 我的自定义 AuthorizationHandler
在 AutoLoginMiddleware
的调用之间被调用
此问题现已修复。这是预览版中的一个错误。现在它按预期工作。祝你好运!
更新:我想 post 我的 .NET Core 3.1 Final 工作代码。
- 必须在
Configure
框架中间件之后注册自定义登录中间件:
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<AutoLoginMiddleware>();
在自定义中间件中,登录用户后必须调用 CreateUserPrincipalAsync
并将此主体保存到 HttpContext.User
属性.
await signInManager.SignInAsync(user, true);
context.User = await signInManager.CreateUserPrincipalAsync(user);
对于Blazor,我们必须使用AuthenticationStateProvider
。它有一个 属性 User
,其中包含来自 HttpContext
的 ClaimsPrincipal
。就是这样。
您现在可以像下面这样获得身份用户:
var authState = await _authenticationStateProvider.GetAuthenticationStateAsync();
var intranetUser = await UserManager.GetUserAsync(authState.User);
我正在使用 .NET Core 3.0 Preview6。
我们有一个启用了 Windows 身份验证的 Intranet 应用程序,这意味着只允许有效的 AD 用户使用该应用程序。
但是,我们喜欢 运行 我们自己的身份验证后端具有 ASP.NET 身份,因为它有效 "out-of-the-box"。我刚刚使用用户的 Windows 登录名向 AspNetUsers table 添加了一列。
我想要完成的是 Windows 用户使用他们的 Windows 登录名自动登录到应用程序。
我已经创建了自定义身份验证中间件,请参阅下面的代码:
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()
的调用总是 returns 错误。
我现在的问题是:以这种方式进行自动身份验证通常是个好主意吗?还存在哪些其他方式?
我的下一个要求是定制 AuthorizationHandler
。
这里的问题是有时在 HandleRequirementAsync
方法中 AuthorizationHandlerContext.User.Identity
是 WindowsIdentity
然后调用 context.User.Identity.Name
会引发以下异常:
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)
我现在的假设是这两个部分不能很好地协同工作。有时似乎存在时间问题 - 我的自定义 AuthorizationHandler
在 AutoLoginMiddleware
此问题现已修复。这是预览版中的一个错误。现在它按预期工作。祝你好运!
更新:我想 post 我的 .NET Core 3.1 Final 工作代码。
- 必须在
Configure
框架中间件之后注册自定义登录中间件:
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<AutoLoginMiddleware>();
在自定义中间件中,登录用户后必须调用
CreateUserPrincipalAsync
并将此主体保存到HttpContext.User
属性.await signInManager.SignInAsync(user, true); context.User = await signInManager.CreateUserPrincipalAsync(user);
对于Blazor,我们必须使用
AuthenticationStateProvider
。它有一个 属性User
,其中包含来自HttpContext
的ClaimsPrincipal
。就是这样。您现在可以像下面这样获得身份用户:
var authState = await _authenticationStateProvider.GetAuthenticationStateAsync(); var intranetUser = await UserManager.GetUserAsync(authState.User);