【发布时间】:2018-08-13 16:14:23
【问题描述】:
主要目标是在 OIDC 用户具有类型为“BlockedFrom”的自定义声明时阻止访问门户,该声明已添加到 ClaimsTransformation 中。
我已经通过Startup.Configure 方法中的中间件解决了它。一般原因是保留原始请求 URL 而不重定向到 /Account/AccessDenied 页面。
app.Use((context, next) =>
{
var user = context.User;
if (user.IsAuthenticated())
{
// Do not rewrite path when it marked with custom [AllowBlockedAttribute]!
// /Home/Logout, for example. But how?
//
if (user.HasClaim(x => x.Type == UserClaimTypes.BlockedFrom))
{
// Rewrite to run specific method of HomeController for blocked users
// with detailed message.
//
context.Request.Path = GenericPaths.Blocked;
}
}
return next();
});
但是有一个意想不到的结果:HomeController 的Logout 方法也被阻塞了。用户在被阻止时无法注销,哈哈!
想到的第一件事-检查自定义属性,例如[AllowBlockedAttribute]。中间件中的硬编码路径常量看起来很疯狂。如何访问中间件中调用方法的属性?
另一种(更优雅)的方法是将此逻辑放入自定义BlockedHandler : AuthorizationHandler<BlockedRequirement> 并将其分配到Startup.ConfigureServices 方法的MVC 选项中作为一般策略:
services.AddSingleton<IAuthorizationHandler, BlockedHandler>();
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddRequirements(new BlockedRequirement())
.Build();
// Set the default authentication policy to require users to be authenticated.
//
options.Filters.Add(new AuthorizeFilter(policy));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
BlockedHandler的假设实现:
public class BlockedHandler : AuthorizationHandler<BlockedRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, BlockedRequirement requirement)
{
if (!context.User.HasClaim(c => c.Type == UserClaimTypes.BlockedFrom))
{
context.Succeed(requirement);
return Task.CompletedTask;
}
// User is blocked!
if (context.Resource is AuthorizationFilterContext mvcContext)
{
if (mvcContext.ActionDescriptor is ControllerActionDescriptor descriptor)
{
var allowBlocked = descriptor.ControllerTypeInfo.CustomAttributes
.Concat<CustomAttributeData>(descriptor.MethodInfo.CustomAttributes)
.Any(x => x.AttributeType == typeof(AllowBlockedAttribute));
// User can access called action.
//
if (allowBlocked)
context.Succeed(requirement);
}
// Ugly to call this as the next step?
// mvcContext.HttpContext.Request.Path = GenericPaths.Blocked;
}
// Prevent redirection to AccessDenied
// Stop authorization chain.
return Task.CompletedTask;
}
}
好的,现在我们可以处理自定义属性了。似乎 AuthorizationHandler 不是告诉 HttpContext 在没有重定向的情况下更改它的 RequestPath 的最佳位置。哪里可以做?
【问题讨论】:
标签: c# asp.net-core-2.1