我试图使一个自定义授权属性在ASP。净的核心。在以前的版本中,可以重写bool AuthorizeCore(HttpContextBase httpContext)。但是这在AuthorizeAttribute中不再存在。
当前制作自定义AuthorizeAttribute的方法是什么?
我想要完成的:我正在头授权中接收会话ID。通过该ID,我将知道特定操作是否有效。
我试图使一个自定义授权属性在ASP。净的核心。在以前的版本中,可以重写bool AuthorizeCore(HttpContextBase httpContext)。但是这在AuthorizeAttribute中不再存在。
当前制作自定义AuthorizeAttribute的方法是什么?
我想要完成的:我正在头授权中接收会话ID。通过该ID,我将知道特定操作是否有效。
当前回答
基于Derek Greer伟大的答案,我用枚举来做。
下面是我的代码示例:
public enum PermissionItem
{
User,
Product,
Contact,
Review,
Client
}
public enum PermissionAction
{
Read,
Create,
}
public class AuthorizeAttribute : TypeFilterAttribute
{
public AuthorizeAttribute(PermissionItem item, PermissionAction action)
: base(typeof(AuthorizeActionFilter))
{
Arguments = new object[] { item, action };
}
}
public class AuthorizeActionFilter : IAuthorizationFilter
{
private readonly PermissionItem _item;
private readonly PermissionAction _action;
public AuthorizeActionFilter(PermissionItem item, PermissionAction action)
{
_item = item;
_action = action;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
bool isAuthorized = MumboJumboFunction(context.HttpContext.User, _item, _action); // :)
if (!isAuthorized)
{
context.Result = new ForbidResult();
}
}
}
public class UserController : BaseController
{
private readonly DbContext _context;
public UserController( DbContext context) :
base()
{
_logger = logger;
}
[Authorize(PermissionItem.User, PermissionAction.Read)]
public async Task<IActionResult> Index()
{
return View(await _context.User.ToListAsync());
}
}
其他回答
现代的方法是AuthenticationHandlers
在startup.cs中添加
services.AddAuthentication("BasicAuthentication").AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);
public class BasicAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
{
private readonly IUserService _userService;
public BasicAuthenticationHandler(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger,
UrlEncoder encoder,
ISystemClock clock,
IUserService userService)
: base(options, logger, encoder, clock)
{
_userService = userService;
}
protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
{
if (!Request.Headers.ContainsKey("Authorization"))
return AuthenticateResult.Fail("Missing Authorization Header");
User user = null;
try
{
var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
var username = credentials[0];
var password = credentials[1];
user = await _userService.Authenticate(username, password);
}
catch
{
return AuthenticateResult.Fail("Invalid Authorization Header");
}
if (user == null)
return AuthenticateResult.Fail("Invalid User-name or Password");
var claims = new[] {
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
};
var identity = new ClaimsIdentity(claims, Scheme.Name);
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, Scheme.Name);
return AuthenticateResult.Success(ticket);
}
}
IUserService是一个你有用户名和密码的服务。 基本上它返回一个用户类,您可以使用它来映射您的声明。
var claims = new[] {
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Username),
};
然后你可以查询这些索赔和她的任何数据你映射,有相当多,看看ClaimTypes类
您可以在扩展方法中使用它来获取任何映射
public int? GetUserId()
{
if (context.User.Identity.IsAuthenticated)
{
var id=context.User.FindFirst(ClaimTypes.NameIdentifier);
if (!(id is null) && int.TryParse(id.Value, out var userId))
return userId;
}
return new Nullable<int>();
}
我认为这种新方法比这里展示的旧方法更好,两种方法都有效
public class BasicAuthenticationAttribute : AuthorizationFilterAttribute
{
public override void OnAuthorization(HttpActionContext actionContext)
{
if (actionContext.Request.Headers.Authorization != null)
{
var authToken = actionContext.Request.Headers.Authorization.Parameter;
// decoding authToken we get decode value in 'Username:Password' format
var decodeauthToken = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(authToken));
// spliting decodeauthToken using ':'
var arrUserNameandPassword = decodeauthToken.Split(':');
// at 0th postion of array we get username and at 1st we get password
if (IsAuthorizedUser(arrUserNameandPassword[0], arrUserNameandPassword[1]))
{
// setting current principle
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(arrUserNameandPassword[0]), null);
}
else
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}
}
else
{
actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
}
}
public static bool IsAuthorizedUser(string Username, string Password)
{
// In this method we can handle our database logic here...
return Username.Equals("test") && Password == "test";
}
}
下面的代码适合我在。net Core 5中使用
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AccessAuthorizationAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public string Module { get; set; } //Permission string to get from controller
public AccessAuthorizationAttribute(string module)
{
Module = module;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
//Validate if any permissions are passed when using attribute at controller or action level
if (string.IsNullOrEmpty(Module))
{
//Validation cannot take place without any permissions so returning unauthorized
context.Result = new UnauthorizedResult();
return;
}
if (hasAccess)
{
return;
}
context.Result = new UnauthorizedResult();
return;
}
}
下面是一个简单的5步指南,教你如何使用策略来实现自定义角色授权:)。我使用了这些文档。
创建需求:
public class RoleRequirement : IAuthorizationRequirement
{
public string Role { get; set; }
}
创建一个处理器:
public class RoleHandler : AuthorizationHandler<RoleRequirement>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, RoleRequirement requirement)
{
var requiredRole = requirement.Role;
//custom auth logic
// you can use context to access authenticated user,
// you can use dependecy injection to call custom services
var hasRole = true;
if (hasRole)
{
context.Succeed(requirement);
}
else
{
context.Fail(new AuthorizationFailureReason(this, $"Role {requirement.Role} missing"));
}
}
}
在Program.cs中添加处理器:
builder.Services.AddSingleton<IAuthorizationHandler, RoleHandler>();
在program.cs中添加带有角色需求的策略:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("Read", policy => policy.Requirements.Add(new RoleRequirement{Role = "ReadAccess_Custom_System"}));
});
使用你的策略:
[Authorize("Read")]
public class ExampleController : ControllerBase
{
}
什么? !
我决定再补充一个简单的答案。B/c我发现大多数答案都有点过度设计。也因为我需要一种授予授权的方法,而不仅仅是否认它。这里的大多数答案都提供了一种“加强”安全性的方法,但我想“放松”它。例如:“如果配置了某些应用程序设置,则允许匿名用户访问”。
public class MyAuthAttribute : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
//check access
if (CheckPermissions())
{
//all good, add optional code if you want. Or don't
}
else
{
//DENIED!
//return "ChallengeResult" to redirect to login page (for example)
context.Result = new ChallengeResult(CookieAuthenticationDefaults.AuthenticationScheme);
}
}
}
就是这样。不需要混淆“策略”,“声明”,“处理程序”和其他[哔]
用法:
// GET api/Get/5
[MyAuth]
public ActionResult<string> Get(int id)
{
return "blahblah";
}
您可以创建自己的AuthorizationHandler,它将在控制器和动作上找到自定义属性,并将它们传递给handlerrequirementasync方法。
public abstract class AttributeAuthorizationHandler<TRequirement, TAttribute> : AuthorizationHandler<TRequirement> where TRequirement : IAuthorizationRequirement where TAttribute : Attribute
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement)
{
var attributes = new List<TAttribute>();
var action = (context.Resource as AuthorizationFilterContext)?.ActionDescriptor as ControllerActionDescriptor;
if (action != null)
{
attributes.AddRange(GetAttributes(action.ControllerTypeInfo.UnderlyingSystemType));
attributes.AddRange(GetAttributes(action.MethodInfo));
}
return HandleRequirementAsync(context, requirement, attributes);
}
protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement, IEnumerable<TAttribute> attributes);
private static IEnumerable<TAttribute> GetAttributes(MemberInfo memberInfo)
{
return memberInfo.GetCustomAttributes(typeof(TAttribute), false).Cast<TAttribute>();
}
}
然后你可以在你的控制器或动作上使用它的任何自定义属性。例如,添加权限要求。只需创建您的自定义属性。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class PermissionAttribute : AuthorizeAttribute
{
public string Name { get; }
public PermissionAttribute(string name) : base("Permission")
{
Name = name;
}
}
然后创建一个需求,添加到您的策略
public class PermissionAuthorizationRequirement : IAuthorizationRequirement
{
//Add any custom requirement properties if you have them
}
然后为您的自定义属性创建AuthorizationHandler,继承我们之前创建的AttributeAuthorizationHandler。它将被传递一个IEnumerable,用于handlerrequirementsasync方法中的所有自定义属性,这些属性是由控制器和动作积累而来的。
public class PermissionAuthorizationHandler : AttributeAuthorizationHandler<PermissionAuthorizationRequirement, PermissionAttribute>
{
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionAuthorizationRequirement requirement, IEnumerable<PermissionAttribute> attributes)
{
foreach (var permissionAttribute in attributes)
{
if (!await AuthorizeAsync(context.User, permissionAttribute.Name))
{
return;
}
}
context.Succeed(requirement);
}
private Task<bool> AuthorizeAsync(ClaimsPrincipal user, string permission)
{
//Implement your custom user permission logic here
}
}
最后,在Startup.cs ConfigureServices方法中,将您的自定义AuthorizationHandler添加到服务中,并添加您的Policy。
services.AddSingleton<IAuthorizationHandler, PermissionAuthorizationHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy("Permission", policyBuilder =>
{
policyBuilder.Requirements.Add(new PermissionAuthorizationRequirement());
});
});
现在你可以简单地用你的自定义属性装饰你的控制器和动作。
[Permission("AccessCustomers")]
public class CustomersController
{
[Permission("AddCustomer")]
IActionResult AddCustomer([FromBody] Customer customer)
{
//Add customer
}
}