Windows身份验证-特殊用户需要其他密码

时间:2019-05-06 18:31:13

标签: c# asp.net-core windows-authentication

我正在开发一个intranet asp.net核心Web api应用程序。身份验证的要求是:

  • REQ1-当尝试访问该网站的用户不在Active Directory的特殊组中(简称为“ commonUsers”)时,它完全未被授权
  • REQ2-当尝试访问该网站的用户位于Active Directory的“ commonUsers”组中时,将得到授权并返回Web资源
  • REQ3-当试图访问该网站的用户位于Active Directory的“ superUser”组中时,需要再次提示其输入域密码(因为它试图访问一些非常受限的资源)

现在,我到目前为止所拥有的:

  • 我的服务使用http.sys服务器托管,以支持Windows身份验证。
  • 我正在使用Claims Middleer来检查用户的Active Directory组,让我们这样说:

    public class ClaimsTransformer : IClaimsTransformation {
    private readonly IAuthorizationService _authorizationService;
    public ClaimsTransformer(IAuthorizationService authorizationService)
    {
        _authorizationService = authorizationService;
    }
    
    public Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        _authorizationService.Authorize(principal as  IHmiClaimsPrincipal);
        return Task.FromResult(principal);
    }}
    
  • 我还在服务配置中指定了特殊策略,例如:

    services.AddAuthorization(options =>
        {
            options.AddPolicy("TestPolicy", policy => 
                                       policy.RequireClaim(ClaimTypes.Role, "TestUser"));
            options.AddPolicy("TestPolicy2", policy => 
                                       policy.RequireClaim(ClaimTypes.Role, "SuperUser"));
        });
  • 我正在将[Authorize]属性与特定策略结合使用,以便根据策略限制对特定资源的访问

现在的问题是,我应该如何满足REQ3?

3 个答案:

答案 0 :(得分:2)

我想我会尝试使用MVC过滤器:https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-2.2#authorization-filters

过滤器在所有中间件之后运行,但在操作之前运行。这将允许您仅针对特定操作或控制器来控制“重定向到凭据”页面。通常,这不是推荐的授权方法,但我认为这符合您对混合二级身份验证的要求。

RefId

然后您创建一个登录控制器

public class SuperUserFilter : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        if (context.HttpContext.Request.Cookies.TryGetValue("SuperUserCookie", out string cookieVal))
        {
            if (!IsValidCookie(cookieVal))
                context.Result = LoginPage(context);

        }
        else
        {
            context.Result = LoginPage(context);
        }
    }

    private bool IsValidCookie(string cookieVal)
    {
        //validate cookie value somehow
        // crytpographic hash, store value in session, whatever
        return true;
    }

    private ActionResult LoginPage(AuthorizationFilterContext context)
    {
        return new RedirectToActionResult("SuperUser", "Login",
            new {redirectUrl = context.HttpContext.Request.GetEncodedUrl()});
    }
}

然后,您可以根据需要装饰特定的操作(或控制器):

public class LoginController : Controller
{    
    [HttpGet]    
    public IActionResult SuperUser(string redirectUrl)
    {
        // return a page to enter credentials
        // Include redirectUrl as field
    }

    [HttpPost]
    public IActionResult SuperUser(LoginData loginData)
    {
        // Validate User & Password
        Response.Cookies.Append("SuperUserCookie", "SomeValue");
        return Redirect(loginData.RedirectUrl);
    }
}

答案 1 :(得分:0)

我猜您正在尝试为some of your resource实施两步身份验证。
为此,您必须使用多个authentication schemeAuthorize policies, 但是这很困难,因为Windows身份验证是不可控制的。我们需要使用一些技巧才能知道这是您的第二次登录。

身份验证

  1. 默认身份验证方案:Windows,它是用于验证Windows用户的基本方案。
  2. 第二个基于Cookies的认证方案:SuperUserTwoStep。我们需要使用它来进入我们的自定义登录逻辑。

授权

  1. 指定方案的Authorize policies
  2. 用于登录SuperUserTwoStep方案的登录页面。
//startup
            services.AddAuthentication(HttpSysDefaults.AuthenticationScheme)
                .AddCookie("SuperUserTwoStep",op=>op.LoginPath = "/account/superuser2steplogin");

            services.AddAuthorization(op =>
            {
                op.AddPolicy("SuperUser", b => b.AddAuthenticationSchemes("SuperUserTwoStep")
                    .RequireAuthenticatedUser()
                    .RequireClaim(ClaimTypes.Role, "SuperUser"));
            });

// login 
        public static IDictionary<string, string> States { get; set; } = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

        [Route("/account/superuser2steplogin")]
        public async Task<IActionResult> LoginTwoStepConfirm(string returnUrl, [FromServices]IAuthorizationService authorizationService,
            [FromServices]IAuthorizationPolicyProvider policyProvider)
        {

            var winresult = await HttpContext.AuthenticateAsync(IISDefaults.AuthenticationScheme);
            if (winresult.Succeeded)
            {
                if (States.TryGetValue(winresult.Principal.Identity.Name, out _))
                {
                    States.Remove(winresult.Principal.Identity.Name);
                    var principal = new System.Security.Claims.ClaimsPrincipal(new System.Security.Claims.ClaimsIdentity(winresult.Principal.Claims,"twostepcookie"));
                    await HttpContext.SignInAsync("SuperUserTwoStep", principal);
                    return Redirect(returnUrl);
                }
                else
                {
                    States[winresult.Principal.Identity.Name] = "1";
                    return Challenge(IISDefaults.AuthenticationScheme);
                }
            }

            else
            {
                return Challenge(IISDefaults.AuthenticationScheme);
            }
        }

        [Authorize("SuperUser")]
        public IActionResult YourSecurePage()
        {
            return Content("hello world");
        }

最困难的事情是跟踪这是第二次登录,我尝试使用cookie,但是它不起作用,因此我创建了static IDitionary<string,string>进行跟踪,也许使用分布式缓存更好

答案 2 :(得分:0)

我认为您应该考虑使用:带需求的基于策略的授权,基本上,您有不同的授权需求,您希望基于AND对其进行处理

REQ1和REQ2和REQ3

在这里您具有文档链接:Requirements

但是您需要了解identity!=权限,向Microsoft引入了这种策略概念的人们创建了一个名为:PolicyServer的项目,该项目是开源的:PolicyServer Git,他们在那里创建了一个模式,您应该如何使用使用您的政策。基本上,您具有根据AD进行身份验证的外部和内部用户,所有内部用户应具有分配给角色的权限。而且,您只会使用为该策略创建的权限规则来装饰控制器操作

[Authorize("PerformSurgery")]
public async Task<IActionResult> PerformSurgery()
{
    // omitted
}

要了解代码及其对政策的评估方式,我认为您应该在网站Policy Server

上观看他们在线观看的视频。

希望这会有所帮助