具有Windows身份验证的ASP.NET Core身份 [英] ASP.NET Core Identity with Windows Authentication
问题描述
我正在使用.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.
- 在框架中间件之后在
Configure
中注册自定义登录中间件是必不可少的:
- It's essential to register the custom login middleware after framework middlewares in
Configure
:
app.UseAuthentication();
app.UseAuthorization();
app.UseMiddleware<AutoLoginMiddleware>();
-
在自定义中间件中,登录用户后,您必须调用
CreateUserPrincipalAsync
并将此主体保存到HttpContext.User
属性.
In the custom middleware, after signing in the user you must call
CreateUserPrincipalAsync
and save this principal to theHttpContext.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屋!