情况:我有一个(仅内部网)网站,该网站利用用户名/密码登录。也可以使用Windows用户登录。
我要做什么:当用户转到该网站上的页面并且尚未使用用户名/密码登录时,该用户将使用Windows身份验证登录。这导致他的HttpContext.User
对象的类型为WindowsPrincipal
。然后,我通过SignInManager<User>.SignInAsync()
自动将用户登录到其相应的用户。现在,用户拥有我数据库中指定的所有角色,而不是AD赋予的角色。
当前方法的问题:最初,我仅在默认开始页面上进行过此重写。因此,我可以在部分完成签名后明确重新加载此页面。如果用户转而转到另一个子页面(例如,通过书签),则将跳过身份验证类型的重写=>他停留为WindowsPrincipal
。
我尝试的解决方法:通过中间件部分登录。我有一个服务(实现IMiddleware,比较https://stackoverflow.com/a/52214120/2968106),该服务在其InvokeAsync()方法中进行此操作。
我的解决方案存在的问题:以用户身份使用我的中间件登录太晚了,因此该页面返回“访问被拒绝”,因为该用户当时缺少所需的角色。再次加载页面可以解决此问题。我在Configure
和Startup.cs
之后的app.UseAuthentication()
的{{1}}方法中调用了中间件。在这两个位置之前移动它不会改变任何内容。
问题:a)这种方法可行吗? b)我应该在何时调用此方法,或者在登录完成后,是否有一种方法可以从中间件内部完整请求所有参数的给定页面?
关于b):是否有某种功能可以从头开始重新启动管道,我可以在app.UseSession()
之后在中间件中调用它?
修改:
1)我的中间件
SignInAsync()
2)public class WindowsPrincipalToClaimPrincipal :IMiddleware
{
private readonly SignInManager<User> _signInManager;
private readonly UserService _userService;
public WindowsPrincipalToClaimPrincipal(SignInManager<User> signInManager, UserService userService)
{
_signInManager = signInManager;
_userService = userService;
}
public Task InvokeAsync(HttpContext context, RequestDelegate next)
{
if (context.User is WindowsPrincipal)
{
_signInManager.SignInAsync(_userService.GetCurrentUser(), false).Wait();
}
return next(context);
}
}
Startup.cs
答案 0 :(得分:0)
似乎答案比预期的要容易。如果此方法在所有情况下都能按预期工作,我将不得不进行更详细的尝试,但在短期内,我发现了以下可能的解决方案:
在中间件中,在SignInAsync()
之后添加以下行:
context.User = _signInManager.CreateUserPrincipalAsync(_userService.GetCurrentUser()).Result;
我已经习惯了只读用户(例如使用PageModel.User时),以至于我甚至都没有想到写该属性的可能性。
编辑:另一个要点:不要过早调用中间件。应该在app.useAuthentication()
之后调用它,否则您将失去使用普通帐户登录的能力。