根据操作名称授权用户
Authorizing a user depending on the action name
我有很多控制器,可以执行很多操作。每个动作都有自己的角色(角色名称 = ControllerName.actionName)。
在以前的版本中,我可以使用 "generic" AuthorizeAttribute 来测试当前用户是否可以访问某个操作:
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
string currentAction = actionContext.ActionDescriptor.ActionName;
string currentController = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
Roles = (currentController + "." + currentAction).ToLower();
base.OnAuthorization(actionContext);
}
对于版本 asp.net 5,我发现我需要使用 requirements ( )。问题是 AuthorizationContext 没有向我们提供有关用户尝试进行的操作的信息。
我不想在每个操作上都添加一个授权属性,有什么方法可以用新框架实现我的要求吗? (我更愿意避免使用 HttpContext.Current,它不太适合管道架构)
以下是执行自定义身份验证的一般过程。您的情况可能可以在第一步中完全解决,因为您可以为装饰您的
的角色添加声明
1. 通过为用户创建身份来验证
编写中间件并通过 IApplicationBuilder.UseMiddleware<>
将其插入管道是自定义身份验证的完成方式。这是我们提取以后授权可能需要的任何信息的地方,并将其放入 ClaimsIdentity
。我们这里有一个 HttpContext
,所以我们可以从 header、cookies、请求的路径等中获取信息。这是一个例子:
public class MyAuthHandler : AuthenticationHandler<MyAuthOptions>
{
protected override Task<AuthenticationTicket> HandleAuthenticateAsync()
{
// grab stuff from the HttpContext
string authHeader = Request.Headers["Authorization"] ?? "";
string path = Request.Path.ToString() ?? "";
// make a MyAuth identity with claims specifying what we'll validate against
var identity = new ClaimsIdentity(new[] {
new Claim(ClaimTypes.Authentication, authHeader),
new Claim(ClaimTypes.Uri, path)
}, Options.AuthenticationScheme);
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity),
new AuthenticationProperties(), Options.AuthenticationScheme);
return Task.FromResult(ticket);
}
}
public class MyAuthOptions : AuthenticationOptions
{
public const string Scheme = "MyAuth";
public MyAuthOptions()
{
AuthenticationScheme = Scheme;
AutomaticAuthentication = true;
}
}
public class MyAuthMiddleware : AuthenticationMiddleware<MyAuthOptions>
{
public MyAuthMiddleware(
RequestDelegate next,
IDataProtectionProvider dataProtectionProvider,
ILoggerFactory loggerFactory,
IUrlEncoder urlEncoder,
IOptions<MyAuthOptions> options,
ConfigureOptions<MyAuthOptions> configureOptions)
: base(next, options, loggerFactory, urlEncoder, configureOptions)
{
}
protected override AuthenticationHandler<MyAuthOptions> CreateHandler()
{
return new MyAuthHandler();
}
}
public static class MyAuthMiddlewareAppBuilderExtensions
{
public static IApplicationBuilder UseMyAuthAuthentication(this IApplicationBuilder app, string optionsName = "")
{
return app.UseMiddleware<MyAuthMiddleware>(
new ConfigureOptions<MyAuthOptions>(o => new MyAuthOptions()) { Name = optionsName });
}
}
要使用此中间件,请在路由之前的 Startup.Configure
中插入:app.UseMyAuthAuthentication();
2。 授权 通过强制要求身份
我们已经为用户创建了一个身份,但我们仍然需要强制执行它。为此,我们需要这样写 AuthorizationHandler
:
public class MyAuthRequirement : AuthorizationHandler<MyAuthRequirement>, IAuthorizationRequirement
{
public override void Handle(AuthorizationContext context, MyAuthRequirement requirement)
{
// grab the identity for the MyAuth authentication
var myAuthIdentities = context.User.Identities
.Where(x => x.AuthenticationType == MyAuthOptions.Scheme).FirstOrDefault();
if (myAuthIdentities == null)
{
context.Fail();
return;
}
// grab the authentication header and uri types for our identity
var authHeaderClaim = myAuthIdentities.Claims.Where(x => x.Type == ClaimTypes.Authentication).FirstOrDefault();
var uriClaim = context.User.Claims.Where(x => x.Type == ClaimTypes.Uri).FirstOrDefault();
if (uriClaim == null || authHeaderClaim == null)
{
context.Fail();
return;
}
// enforce our requirement (evaluate values from the identity/claims)
if ( /* passes our enforcement test */ )
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
}
3。将需求处理程序添加为授权策略
我们的身份验证要求仍然需要添加到 Startup.ConfigureServices
以便可以使用:
// add our policy to the authorization configuration
services.ConfigureAuthorization(auth =>
{
auth.AddPolicy(MyAuthOptions.Scheme,
policy => policy.Requirements.Add(new MyAuthRequirement()));
});
4.使用授权策略
最后一步是通过用 [Authorize("MyAuth")]
装饰我们的动作或控制器来强制执行对特定动作的要求。如果我们有很多控制器,每个控制器都有很多需要强制执行的操作,那么我们可能想要制作一个基础 class 并只装饰那个控制器。
你的情况比较简单:
Each action has it's own Role ( Role name = ControllerName.actionName> )
如果您已经完成 fine-tuned 和 [Authorize(Roles = "controllername.actionname")]
的所有操作,那么您可能只需要上面的第 1 部分。只需添加一个对特定请求有效的新 Claim(ClaimTypes.Role, "controllername.actionname")
。
我有很多控制器,可以执行很多操作。每个动作都有自己的角色(角色名称 = ControllerName.actionName)。
在以前的版本中,我可以使用 "generic" AuthorizeAttribute 来测试当前用户是否可以访问某个操作:
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
string currentAction = actionContext.ActionDescriptor.ActionName;
string currentController = actionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
Roles = (currentController + "." + currentAction).ToLower();
base.OnAuthorization(actionContext);
}
对于版本 asp.net 5,我发现我需要使用 requirements (
我不想在每个操作上都添加一个授权属性,有什么方法可以用新框架实现我的要求吗? (我更愿意避免使用 HttpContext.Current,它不太适合管道架构)
以下是执行自定义身份验证的一般过程。您的情况可能可以在第一步中完全解决,因为您可以为装饰您的
的角色添加声明1. 通过为用户创建身份来验证
编写中间件并通过 IApplicationBuilder.UseMiddleware<>
将其插入管道是自定义身份验证的完成方式。这是我们提取以后授权可能需要的任何信息的地方,并将其放入 ClaimsIdentity
。我们这里有一个 HttpContext
,所以我们可以从 header、cookies、请求的路径等中获取信息。这是一个例子:
public class MyAuthHandler : AuthenticationHandler<MyAuthOptions>
{
protected override Task<AuthenticationTicket> HandleAuthenticateAsync()
{
// grab stuff from the HttpContext
string authHeader = Request.Headers["Authorization"] ?? "";
string path = Request.Path.ToString() ?? "";
// make a MyAuth identity with claims specifying what we'll validate against
var identity = new ClaimsIdentity(new[] {
new Claim(ClaimTypes.Authentication, authHeader),
new Claim(ClaimTypes.Uri, path)
}, Options.AuthenticationScheme);
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity),
new AuthenticationProperties(), Options.AuthenticationScheme);
return Task.FromResult(ticket);
}
}
public class MyAuthOptions : AuthenticationOptions
{
public const string Scheme = "MyAuth";
public MyAuthOptions()
{
AuthenticationScheme = Scheme;
AutomaticAuthentication = true;
}
}
public class MyAuthMiddleware : AuthenticationMiddleware<MyAuthOptions>
{
public MyAuthMiddleware(
RequestDelegate next,
IDataProtectionProvider dataProtectionProvider,
ILoggerFactory loggerFactory,
IUrlEncoder urlEncoder,
IOptions<MyAuthOptions> options,
ConfigureOptions<MyAuthOptions> configureOptions)
: base(next, options, loggerFactory, urlEncoder, configureOptions)
{
}
protected override AuthenticationHandler<MyAuthOptions> CreateHandler()
{
return new MyAuthHandler();
}
}
public static class MyAuthMiddlewareAppBuilderExtensions
{
public static IApplicationBuilder UseMyAuthAuthentication(this IApplicationBuilder app, string optionsName = "")
{
return app.UseMiddleware<MyAuthMiddleware>(
new ConfigureOptions<MyAuthOptions>(o => new MyAuthOptions()) { Name = optionsName });
}
}
要使用此中间件,请在路由之前的 Startup.Configure
中插入:app.UseMyAuthAuthentication();
2。 授权 通过强制要求身份
我们已经为用户创建了一个身份,但我们仍然需要强制执行它。为此,我们需要这样写 AuthorizationHandler
:
public class MyAuthRequirement : AuthorizationHandler<MyAuthRequirement>, IAuthorizationRequirement
{
public override void Handle(AuthorizationContext context, MyAuthRequirement requirement)
{
// grab the identity for the MyAuth authentication
var myAuthIdentities = context.User.Identities
.Where(x => x.AuthenticationType == MyAuthOptions.Scheme).FirstOrDefault();
if (myAuthIdentities == null)
{
context.Fail();
return;
}
// grab the authentication header and uri types for our identity
var authHeaderClaim = myAuthIdentities.Claims.Where(x => x.Type == ClaimTypes.Authentication).FirstOrDefault();
var uriClaim = context.User.Claims.Where(x => x.Type == ClaimTypes.Uri).FirstOrDefault();
if (uriClaim == null || authHeaderClaim == null)
{
context.Fail();
return;
}
// enforce our requirement (evaluate values from the identity/claims)
if ( /* passes our enforcement test */ )
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
}
3。将需求处理程序添加为授权策略
我们的身份验证要求仍然需要添加到 Startup.ConfigureServices
以便可以使用:
// add our policy to the authorization configuration
services.ConfigureAuthorization(auth =>
{
auth.AddPolicy(MyAuthOptions.Scheme,
policy => policy.Requirements.Add(new MyAuthRequirement()));
});
4.使用授权策略
最后一步是通过用 [Authorize("MyAuth")]
装饰我们的动作或控制器来强制执行对特定动作的要求。如果我们有很多控制器,每个控制器都有很多需要强制执行的操作,那么我们可能想要制作一个基础 class 并只装饰那个控制器。
你的情况比较简单:
Each action has it's own Role ( Role name = ControllerName.actionName> )
如果您已经完成 fine-tuned 和 [Authorize(Roles = "controllername.actionname")]
的所有操作,那么您可能只需要上面的第 1 部分。只需添加一个对特定请求有效的新 Claim(ClaimTypes.Role, "controllername.actionname")
。