ASP.Net 在 ASP.Net Core 中带有自定义表的身份内置函数
ASP.Net Identity built in functions with custom tables in ASP.Net Core
我在 .Net 2.1 Framework 上使用 ASP.Net Core Web Api 2
我有自定义 AppUsers 和 AppRoles tables,与桥 table AppUserRoles
链接
我的主要问题是我想使用 [Authorize(Roles = "UserRole")]
由于 User.Identity 工作正常并且我从 User.Identity.Name
获取用户 ID,我认为有一些方法可以在控制器请求之前设置角色并检查它们,或者使用 User.IsInRole("UserRole")
来检查控制器内部。
是否可以通过某种方式重建或重载 .IsInRole("UserRole")
函数或 [Authorize(Roles = "UserRole")]
属性后台函数,以便我可以编写自己的逻辑来检查用户权限?或者将我的 tables 设置为要使用的默认 tables,这样它就可以在自逻辑上工作。
对于我的任务,速度与安全同样重要。
如果有其他方法,我愿意接受建议,但我的观点也是为了更好地理解这些功能。
您不需要重写 Authorize 或 IsInRole。只需将角色作为声明添加到 User.Identity。您可以使用中间件进行声明转换。
作为示例,我建议您查看 PolicyServer. It has the same approach. The free OSS version adds claims in the middleware。
/// Add the policy server claims transformation middleware to the pipeline.
/// This middleware will turn application roles and permissions into claims
/// and add them to the current user
public static IApplicationBuilder UsePolicyServerClaims(this IApplicationBuilder app)
{
return app.UseMiddleware<PolicyServerClaimsMiddleware>();
}
PolicyServerClaimsMiddleware 所在位置:
public class PolicyServerClaimsMiddleware
{
private readonly RequestDelegate _next;
/// <summary>
/// Initializes a new instance of the <see cref="PolicyServerClaimsMiddleware"/> class.
/// </summary>
/// <param name="next">The next.</param>
public PolicyServerClaimsMiddleware(RequestDelegate next)
{
_next = next;
}
/// <summary>
/// Invoke
/// </summary>
/// <param name="context">The context.</param>
/// <param name="client">The client.</param>
/// <returns></returns>
public async Task Invoke(HttpContext context, IPolicyServerRuntimeClient client)
{
if (context.User.Identity.IsAuthenticated)
{
var policy = await client.EvaluateAsync(context.User);
var roleClaims = policy.Roles.Select(x => new Claim("role", x));
var permissionClaims = policy.Permissions.Select(x => new Claim("permission", x));
var id = new ClaimsIdentity("PolicyServerMiddleware", "name", "role");
id.AddClaims(roleClaims);
id.AddClaims(permissionClaims);
context.User.AddIdentity(id);
}
await _next(context);
}
}
从启动开始:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore(options =>
{
// workaround: https://github.com/aspnet/Mvc/issues/7809
options.AllowCombiningAuthorizeFilters = false;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddAuthorization();
// This is not relevant for you, but just to show how policyserver is implemented.
// The bottom line is that you can implement this anyway you like.
// this sets up the PolicyServer client library and policy
// provider - configuration is loaded from appsettings.json
services.AddPolicyServerClient(Configuration.GetSection("Policy"))
.AddAuthorizationPermissionPolicies();
}
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
// add this middleware to make roles and permissions available as claims
// this is mainly useful for using the classic [Authorize(Roles="foo")] and IsInRole functionality
// this is not needed if you use the client library directly or the new policy-based authorization framework in ASP.NET Core
app.UsePolicyServerClaims();
app.UseMvc();
}
该示例从文件中读取配置,这也可能是您的一个选项。但是你也可以实现一个存储并添加一些缓存。
如果您想添加一些授权逻辑,那么我建议您创建一些策略和授权处理程序。只需确保在正确的位置使用中间件即可。
另一种方法是使用您自己的过滤器/属性:
//using Microsoft.AspNetCore.Authorization;
//using Microsoft.AspNetCore.Mvc;
//using Microsoft.AspNetCore.Mvc.Filters;
public class CustomPolicyAttribute : AuthorizeAttribute, IAsyncAuthorizationFilter
{
private int _number;
public CustomPolicyAttribute(int number)
{
_number = number;
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var service = (IAuthorizationService)context.HttpContext.RequestServices.GetService(typeof(IAuthorizationService));
var requirement = new CustomRequirement
{
Number = _number
};
var result = await service.AuthorizeAsync(context.HttpContext.User, null, requirement);
if (!result.Succeeded)
context.Result = new ForbidResult();
}
}
您可以通过多种方式使用它。用作属性(等效授权):
[CustomPolicy(1)]
public async Task<IActionResult> DoSomething()
{
}
或手动验证(等效的 IsInRole):
public class MyController : Controller
{
private readonly IAuthorizationService _authorizationService;
public MyController(IAuthorizationService authorizationService)
{
_authorizationService = authorizationService;
}
public async Task<IActionResult> DoSomething(int number)
{
var requirement = new CustomRequirement
{
Number = number
};
var result = await _authorizationService.AuthorizeAsync(User, null, requirement);
if (!result.Succeeded) return Forbid();
return View("success");
}
}
您将需要一个 AuthorizationHandler 来评估需求:
public class CustomRequirementHandler : AuthorizationHandler<CustomRequirement>
{
// Use dependency injection to include services you need.
public CustomRequirementHandler ()
{
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomRequirement requirement)
{
// Add your advanced check here.
if (requirement.Number > 0)
{
context.Succeed(requirement);
}
}
}
并在启动时注册:
services.AddTransient<IAuthorizationHandler, CustomRequirementHandler>();
在处理程序中,您可以添加自己的逻辑。在这种情况下,您不必添加政策,也不必添加授权声明。
我在 .Net 2.1 Framework 上使用 ASP.Net Core Web Api 2 我有自定义 AppUsers 和 AppRoles tables,与桥 table AppUserRoles
链接我的主要问题是我想使用 [Authorize(Roles = "UserRole")]
由于 User.Identity 工作正常并且我从 User.Identity.Name
获取用户 ID,我认为有一些方法可以在控制器请求之前设置角色并检查它们,或者使用 User.IsInRole("UserRole")
来检查控制器内部。
是否可以通过某种方式重建或重载 .IsInRole("UserRole")
函数或 [Authorize(Roles = "UserRole")]
属性后台函数,以便我可以编写自己的逻辑来检查用户权限?或者将我的 tables 设置为要使用的默认 tables,这样它就可以在自逻辑上工作。
对于我的任务,速度与安全同样重要。
如果有其他方法,我愿意接受建议,但我的观点也是为了更好地理解这些功能。
您不需要重写 Authorize 或 IsInRole。只需将角色作为声明添加到 User.Identity。您可以使用中间件进行声明转换。
作为示例,我建议您查看 PolicyServer. It has the same approach. The free OSS version adds claims in the middleware。
/// Add the policy server claims transformation middleware to the pipeline.
/// This middleware will turn application roles and permissions into claims
/// and add them to the current user
public static IApplicationBuilder UsePolicyServerClaims(this IApplicationBuilder app)
{
return app.UseMiddleware<PolicyServerClaimsMiddleware>();
}
PolicyServerClaimsMiddleware 所在位置:
public class PolicyServerClaimsMiddleware
{
private readonly RequestDelegate _next;
/// <summary>
/// Initializes a new instance of the <see cref="PolicyServerClaimsMiddleware"/> class.
/// </summary>
/// <param name="next">The next.</param>
public PolicyServerClaimsMiddleware(RequestDelegate next)
{
_next = next;
}
/// <summary>
/// Invoke
/// </summary>
/// <param name="context">The context.</param>
/// <param name="client">The client.</param>
/// <returns></returns>
public async Task Invoke(HttpContext context, IPolicyServerRuntimeClient client)
{
if (context.User.Identity.IsAuthenticated)
{
var policy = await client.EvaluateAsync(context.User);
var roleClaims = policy.Roles.Select(x => new Claim("role", x));
var permissionClaims = policy.Permissions.Select(x => new Claim("permission", x));
var id = new ClaimsIdentity("PolicyServerMiddleware", "name", "role");
id.AddClaims(roleClaims);
id.AddClaims(permissionClaims);
context.User.AddIdentity(id);
}
await _next(context);
}
}
从启动开始:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore(options =>
{
// workaround: https://github.com/aspnet/Mvc/issues/7809
options.AllowCombiningAuthorizeFilters = false;
})
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddAuthorization();
// This is not relevant for you, but just to show how policyserver is implemented.
// The bottom line is that you can implement this anyway you like.
// this sets up the PolicyServer client library and policy
// provider - configuration is loaded from appsettings.json
services.AddPolicyServerClient(Configuration.GetSection("Policy"))
.AddAuthorizationPermissionPolicies();
}
public void Configure(IApplicationBuilder app)
{
app.UseAuthentication();
// add this middleware to make roles and permissions available as claims
// this is mainly useful for using the classic [Authorize(Roles="foo")] and IsInRole functionality
// this is not needed if you use the client library directly or the new policy-based authorization framework in ASP.NET Core
app.UsePolicyServerClaims();
app.UseMvc();
}
该示例从文件中读取配置,这也可能是您的一个选项。但是你也可以实现一个存储并添加一些缓存。
如果您想添加一些授权逻辑,那么我建议您创建一些策略和授权处理程序。只需确保在正确的位置使用中间件即可。
另一种方法是使用您自己的过滤器/属性:
//using Microsoft.AspNetCore.Authorization;
//using Microsoft.AspNetCore.Mvc;
//using Microsoft.AspNetCore.Mvc.Filters;
public class CustomPolicyAttribute : AuthorizeAttribute, IAsyncAuthorizationFilter
{
private int _number;
public CustomPolicyAttribute(int number)
{
_number = number;
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var service = (IAuthorizationService)context.HttpContext.RequestServices.GetService(typeof(IAuthorizationService));
var requirement = new CustomRequirement
{
Number = _number
};
var result = await service.AuthorizeAsync(context.HttpContext.User, null, requirement);
if (!result.Succeeded)
context.Result = new ForbidResult();
}
}
您可以通过多种方式使用它。用作属性(等效授权):
[CustomPolicy(1)]
public async Task<IActionResult> DoSomething()
{
}
或手动验证(等效的 IsInRole):
public class MyController : Controller
{
private readonly IAuthorizationService _authorizationService;
public MyController(IAuthorizationService authorizationService)
{
_authorizationService = authorizationService;
}
public async Task<IActionResult> DoSomething(int number)
{
var requirement = new CustomRequirement
{
Number = number
};
var result = await _authorizationService.AuthorizeAsync(User, null, requirement);
if (!result.Succeeded) return Forbid();
return View("success");
}
}
您将需要一个 AuthorizationHandler 来评估需求:
public class CustomRequirementHandler : AuthorizationHandler<CustomRequirement>
{
// Use dependency injection to include services you need.
public CustomRequirementHandler ()
{
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomRequirement requirement)
{
// Add your advanced check here.
if (requirement.Number > 0)
{
context.Succeed(requirement);
}
}
}
并在启动时注册:
services.AddTransient<IAuthorizationHandler, CustomRequirementHandler>();
在处理程序中,您可以添加自己的逻辑。在这种情况下,您不必添加政策,也不必添加授权声明。