Is ASP.NET Core Identity needed for Intranet app u

2019-04-02 04:21发布

问题:

Using Windows Authentication in an Intranet web application I want to achieve the following:

  • Gather additional attributes from AD (name, employee number)
  • Gather additional attributes from a database table (working hours, pay)
  • Authorize based on application roles (not AD groups)
  • Authorize based on an AD attribute (has direct reports)
  • User not provide a username/password

In my search for an answer it is suggested that I need to add ClaimsTransformation to my application:

How do I use Windows Authentication with users in database

Populate custom claim from SQL with Windows Authenticated app in .Net Core

Caching Claims in .net core 2.0

Though I don't fully understand the solution and why ClaimsTransformation happens on every request so I'm looking for answers to the following:

  1. Is ASP.NET Core Identity required for ClaimsTransformation to work?
  2. Does ClaimsTransformation happen on every request with just Windows Authentication or also with form based authentication?
  3. Does this have to happen on every request?
  4. Caching claims like GivenName, Surname seem simple but what about roles? What steps need to be taken to ensure the database isn't hit every time but roles do get updated when there are changes.
  5. Is there a simpler alternative for what I'm trying to do?

回答1:

This article gave me some ideas and here is a possible solution.

Controllers would inherit from a base controller which has a policy that requires the Authenticated claim. When this isn't present it goes to the AccessDeniedPath and silently performs the login adding the Authenticated claim along with any other claims, if this is already present then the Access Denied message would appear.

When creating the new ClaimsIdentity I've had to strip most of the Claims in the original identity as I was getting a HTTP 400 - Bad Request (Request Header too long) error message.

Are there any obvious issues with this approach?

Startup.cs

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(options =>
            {
                options.LoginPath = "/Home/Login";
                options.AccessDeniedPath = "/Home/AccessDenied";
            });

        services.AddAuthorization(options =>
        {
            options.AddPolicy("Authenticated",
                policy => policy.RequireClaim("Authenticated"));
            options.AddPolicy("Admin",
                policy => policy.RequireClaim("Admin"));
        });
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseBrowserLink();
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();
        app.UseAuthentication();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}

Controller

[Authorize(Policy = "Authenticated")]
public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [Authorize(Policy = "Admin")]
    public IActionResult About()
    {
        return View();
    }

    [AllowAnonymous]
    public async Task<IActionResult> Login(string returnUrl)
    {
        var identity = ((ClaimsIdentity)HttpContext.User.Identity);

        var claims = new List<Claim>
        {
            new Claim("Authenticated", "True"),
            new Claim(ClaimTypes.Name,
                identity.FindFirst(c => c.Type == ClaimTypes.Name).Value),
            new Claim(ClaimTypes.PrimarySid,
                identity.FindFirst(c => c.Type == ClaimTypes.PrimarySid).Value)
        };

        var claimsIdentity = new ClaimsIdentity(
            claims,
            identity.AuthenticationType,
            identity.NameClaimType,
            identity.RoleClaimType);

        await HttpContext.SignInAsync(
            CookieAuthenticationDefaults.AuthenticationScheme,
            new ClaimsPrincipal(claimsIdentity),
            new AuthenticationProperties());

        return Redirect(returnUrl);
    }

    [AllowAnonymous]
    public IActionResult AccessDenied(string returnUrl)
    {
        if (User.FindFirst("Authenticated") == null)
            return RedirectToAction("Login", new { returnUrl });

        return View();
    }
}