Я использую .NET Core 3.0 Preview6.
У нас есть приложение для интрасети с включенной аутентификацией Windows, что означает, что только действительные пользователи AD могут использовать приложение.
Однако нам нравится запускать собственный бэкэнд аутентификации с ASP.NET Identity, потому что он работает "из коробки". Я только что добавил столбец в таблицу AspNetUsers с именем пользователя Windows.
Чего я хотел бы добиться, так это чтобы пользователи 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()
всегда возвращает значение false.
Мой вопрос сейчас: это вообще хорошая идея иметь автоматическую аутентификацию таким образом? Какие еще способы существуют?
Мое следующее требование - иметь пользовательский 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