ASP.NET Core Windows 身份验证和应用程序角色
Posted
技术标签:
【中文标题】ASP.NET Core Windows 身份验证和应用程序角色【英文标题】:ASP.NET Core Windows Authentication and Application Roles 【发布时间】:2017-08-31 05:10:42 【问题描述】:我正在尝试创建一个相当简单的 Intranet 应用程序,该应用程序将使用 Active Directory 进行身份验证,并将使用 AspNetRoles 表来检查用户是否处于某个应用程序角色中。这个应用程序只是一个内部彩票,一些用户可以在其中创建活动/比赛,然后其他用户可以提交参赛作品。我正在考虑从 2 个基本角色开始:
管理员 - 可以对“事件”执行 CRUD 操作或 “竞赛”实体 参赛者 - 可以执行 GET 操作 “竞赛”实体,并且可以创建新的“参赛”实体。这就是我卡住的地方:我已经让 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 中,我按如下方式连接 Identity:
services.AddIdentity<RaffleUser, ApplicationRole>()
.AddEntityFrameworkStores<RaffleContext>();
我的 RaffleUser 类实际上只是 IdentityUser 的默认实现:
public class RaffleUser : IdentityUser
我的 ApplicationRole 类也只是 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。我需要一些中间件类来为我做这件事吗?这是否是使授权可在所有控制器上重复使用的最佳方式?
【问题讨论】:
【参考方案1】:首先,我最终创建了一个自定义 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 对象。
【讨论】:
【参考方案2】:您需要添加 DefaultChallengeScheme 才能使用 Windows 身份验证。我就是这样做的,但是如果有人有更好的解决方案,我会全力以赴:)
我在当前应用程序中使用以下设置。
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<SecurityDbContext>()
.AddDefaultTokenProviders();
services.AddAuthentication(options =>
options.DefaultChallengeScheme = IISDefaults.AuthenticationScheme;
);
然后我将我的应用程序声明放入变压器中。
services.AddTransient<IClaimsTransformation, ClaimsTransformer>();
我希望这会让你朝着正确的方向前进。
【讨论】:
哎呀。没有看到你的问题的日期。我希望你早就解决了。 我还没有彻底测试我所有的控制器,但看起来这确实完成了我正在寻找的东西。我将发布我想出的替代方案,它也使用更新的基于策略的授权。 也使用'options.DefaultScheme = IISDefaults.AuthenticationScheme;'以上是关于ASP.NET Core Windows 身份验证和应用程序角色的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core 中的 Windows 身份验证模拟是不是已死?
带有 Windows 身份验证的 ASP.Net Core 3.1 中的空闲超时
ASP.NET Core JWT/Windows 身份验证 HTTP 400 错误
带有 Windows 身份验证的 ASP.NET Core 2.1 自定义 RoleProvider