1

我试图创建一个相当简单的Intranet应用程序,它将使用Active Directory进行身份验证,并将使用AspNetRoles表来检查用户是否处于某个应用程序角色。这个应用程序只是一个内部抽奖,其中一些用户可以创建其他用户可以提交参赛作品的活动/比赛。我想开始了与2个基本角色:ASP.NET核心Windows身份验证和应用程序角色

  • 管理员 - 可以在“事件”或 “竞赛”实体
  • 参赛者执行CRUD操作 - 可在 “竞赛”的实体执行GET操作,并可以创建新的“Entry”实体。

这里是我卡住的地方:我有Windows身份验证工作的意义上说,从控制器,我可以做一个User.Identity.Name并看到我的域名登录名。此外,我可以通过执行User.IsInRole("Domain Users")来验证某个帐户属于域组。如果我想避免为我的应用程序中的每个角色创建新的AD组(假设设计变更需要额外的角色),如何使用控制器上的授权来检查应用程序角色?

这里有一个例子控制器我想用:

[Route("api/[controller]")] 
[Authorize(Roles = "Contestant")] 
public class EventTypesController : Controller 
{ 
    private IRaffleRepository _repository; 
    private ILogger<EventTypesController> _logger; 

    public EventTypesController(IRaffleRepository repository, ILogger<EventTypesController> logger) 
    { 
     _repository = repository; 
     _logger = logger; 
    } 

    [HttpGet("")] 
    public IActionResult Get() 
    { 
     try 
     { 
      var results = _repository.GetAllEventTypes(); 
      return Ok(Mapper.Map<IEnumerable<EventTypeViewModel>>(results)); 
     } 
     catch (Exception ex) 
     { 
      _logger.LogError($"Failed to get all event types: {ex}"); 
      return BadRequest("Error occurred"); 
     } 
    } 
} 

在我Startup.cs,在ConfigureServices,我连接最多身份如下:

services.AddIdentity<RaffleUser, ApplicationRole>() 
      .AddEntityFrameworkStores<RaffleContext>(); 

我RaffleUser类是真的只是IdentityUser的默认实现:

public class RaffleUser : IdentityUser 
{ 

} 

My ApplicationRole cla ss也是IdentityRole的默认实现。我也试过在种子播种类的一些数据:

if (!await _roleManager.RoleExistsAsync("Administrator")) 
{ 
    var adminRole = new ApplicationRole() 
    { 
     Name = "Administrator" 
    }; 
    await _roleManager.CreateAsync(adminRole); 
    await _context.SaveChangesAsync(); 
} 

if (await _userManager.FindByNameAsync("jmoor") == null) 
{ 
    using (var context = new PrincipalContext(ContextType.Domain)) 
    { 
     var principal = UserPrincipal.FindByIdentity(context, "DOMAIN\\jmoor"); 
     if (principal != null) 
     { 
      var user = new RaffleUser() 
      { 
       Email = principal.EmailAddress, 
       UserName = principal.SamAccountName 
      }; 

      await _userManager.CreateAsync(user); 
      await _context.SaveChangesAsync(); 

      var adminRole = await _roleManager.FindByNameAsync("Administrator"); 
      if (adminRole != null) 
      { 
       await _userManager.AddToRoleAsync(user, adminRole.Name); 
       await _context.SaveChangesAsync(); 
      } 
     } 
    } 
} 

的数据,使得它的表,但它似乎只是在控制器级别,我需要通过身份验证的用户转换为IdentityUser。我需要一些中间件类来为我做这个吗?这是在所有控制器上授权可重用的最佳方式吗?

回答

0

您需要添加一个DefaultChallangeScheme才能使用Windows身份验证。这是我的方式,但如果有人有一个更好的解决方案,我都耳朵:)

我在我目前的应用程序中使用以下设置。

services.AddIdentity<ApplicationUser, ApplicationRole>() 
      .AddEntityFrameworkStores<SecurityDbContext>() 
      .AddDefaultTokenProviders(); 

services.AddAuthentication(options => 
{ 
      options.DefaultChallengeScheme = IISDefaults.AuthenticationScheme; 
}); 

然后我把在变压器我的申请要求。

services.AddTransient<IClaimsTransformation, ClaimsTransformer>(); 

我希望这会让你走向正确的方向。

+0

oops。没有看到你问题的日期。我希望你很久以前就解决了它。 – Peter

+0

我还没有彻底测试过所有的控制器,但它看起来像这样可以完成我正在寻找的任务。我将发布我提出的替代方案,这也是使用较新的基于策略的授权。 –

0

首先,我创建了一个自定义ClaimsTransformer,它返回一个填充UserClaims和RoleClaims的ClaimsPrincipal(在重构我的应用程序之后,我决定使用基于策略的授权,并且访问声明可以添加到角色或用户级别):

public async Task<ClaimsPrincipal> TransformAsync(ClaimsTransformationContext context) 
{ 
    var identity = (ClaimsIdentity)context.Principal.Identity; 
    var userName = identity.Name; 
    if (userName != null) 
    { 
     var user = await _userManager.FindByLoginAsync("ActiveDirectory", userName); 
     if (user != null) 
     { 
      identity.AddClaims(await _userManager.GetClaimsAsync(user)); 
      var roles = await _userManager.GetRolesAsync(user); 
      identity.AddClaims(await GetRoleClaims(roles)); 
     } 
    } 
    return context.Principal; 
} 

private async Task<List<Claim>> GetRoleClaims(IList<string> roles) 
{ 
    List<Claim> allRoleClaims = new List<Claim>(); 
    foreach (var role in roles) 
    { 
     var rmRole = await _roleManager.FindByNameAsync(role); 
     var claimsToAdd = await _roleManager.GetClaimsAsync(rmRole); 
     allRoleClaims.AddRange(claimsToAdd); 
    } 
    return allRoleClaims; 
} 

我有线,最多在Startup.cs:

services.AddScoped<IClaimsTransformer, Services.ClaimsTransformer>(); 

我也去与基于策略的授权:

services.AddAuthorization(options => 
{ 
    options.AddPolicy("Administrator", policy => policy.RequireClaim("AccessLevel", "Administrator")); 
    options.AddPolicy("Project Manager", policy => policy.RequireClaim("AccessLevel", "Project Manager")); 
}); 

因此,用户或角色可以声明一个名称为“AccessLevel”并指定了值的声明。为了完成所有工作,我还创建了一个自定义UserManager,它在CreateAsync期间使用来自ActiveDirectory的其他详细信息填充User对象。

相关问题