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對象。

相關問題