.Net Core中AuthorizationHandlerContext如何获取当前请求的相关信息

12 篇文章 2 订阅

.Net Core中要自定义用户身份认证,需要实现IAuthorizationHandler,实现的代码也比较简单,一般我们只要实现本地认证AuthorizationHandler<T>.HandleRequirementAsync即可,认证时一般需要用到一些用于判断是否允许访问的认证信息,比如当前的用户信息,比如当前请求的资源信息,这些信息呢,我们都可以通过AuthorizationHandlerContext来获取。

AuthorizationHandlerContext.Resource对应当前请求的资源信息,其返回值为object,所以我们也不知道这个值究竟是什么东西,但没关系,我们可以通过调试阶段的快速监视来查看实际Resource究竟是什么。
在这里插入图片描述
可以看到其类型为Microsoft.AspNetCore.Routing.RouteEndpointEndpoint.DisplayName为请求的action,继续展开,可以看到Endpoint.Metadata内包含了action对应的Attribute之类的信息,这些信息就是我们真正需要的内容。
PS:注意具体AuthorizationHandlerContext.Resource具体是什么和当前应用的宿主模式有关,我们开发时用的是默认的Kestrel模式,其它模式很可能不是Microsoft.AspNetCore.Routing.RouteEndpoint
在这里插入图片描述
上面说完了当前请求的资源部分,下面说当前用户信息部分,这部分就简单了,AuthorizationHandlerContext.User直接就可以获取当前的用户信息,如果这部分信息还不够,那你也可以在AuthorizationHandler<T>中直接注入你需要的内容,比如注入IHttpContextAccessor来获取当前请求的上下文,比如注入IOptions<T>来获取一些配置信息等。

下面举一个使用例子,该例子是设置接口在HttpGet时对所有人员公开,但非HttpGet请求时只有指定用户可以调用

    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
    public class UserLimitOperationAttribute : AuthorizeAttribute
    {
        /// <summary>
        /// 直接指定当前的PolicyName
        /// </summary>
        public const string PolicyName = "UserLimitOperation";
        public UserLimitOperationAttribute()
            : base(PolicyName)
        {
        }
    }

    public class UserLimitOperationRequirement : IAuthorizationRequirement
    {
        /// <summary>
        /// 如果设置了<see cref="UserLimitOperationAttribute"/>,但又没配置允许的用户,那么就认为对所有人开放(测试环境开放)
        /// </summary>
        public bool NoLimit
        {
            get
            {
                return this.Users.Count == 0;
            }
        }
        public HashSet<string> Users { get; } = new HashSet<string>();
        public UserLimitOperationRequirement(string limitUser)
        {
            if (!string.IsNullOrWhiteSpace(limitUser))
            {
                this.Users = limitUser.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToHashSet();
            }
        }
    }
    public class UserLimitOperationHandler : AuthorizationHandler<UserLimitOperationRequirement>
    {
        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserLimitOperationRequirement requirement)
        {
            if (requirement.NoLimit)
            {
                context.Succeed(requirement);
            }
            else
            {
                var endpoint = context.Resource as RouteEndpoint;
                if (endpoint != null)
                {
                    var http = endpoint.Metadata.Where(_=>_ is HttpMethodAttribute).First() as HttpMethodAttribute;
                    if (http is HttpGetAttribute)
                    {//Get请求是公开的
                        context.Succeed(requirement);
                        return Task.CompletedTask;
                    }
                }
                if (context.User.Identity.IsAuthenticated
                    && !string.IsNullOrWhiteSpace(context.User.Identity.Name) && requirement.Users.Contains(context.User.Identity.Name!))
                {
                    //只有配置用户才允许调用
                    context.Succeed(requirement);
                }
            }
            return Task.CompletedTask;
        }
    }

Startup.ConfigureServices注册代码如下

            services.AddSingleton<IAuthorizationHandler, UserLimitOperationHandler>();
            services.AddMvcCore().AddAuthorization(
                options =>
                {
                    options.AddPolicy(
                        UserLimitOperationAttribute.PolicyName,
                        policy =>
                        {
                            //这里的例子是通过IAuthorizationRequirement传递配置,也可以直接在AuthorizationHandler<T>中直接注入IOptions<T>
                            policy.AddRequirements(new UserLimitOperationRequirement(this.Configuration.GetValue<string>("ConfigLimitUsers")));
                        });
                });

然后在要限制的controlleraction上添加[UserLimitOperation]声明即可。

当然如果你的某些配置是直接在AuthorizeAttribute上指定的,比如指定资源标志的ResourceAuthorizeAttribute,那在判断时,你可以通过下面的代码来读取到相应的ResourceAuthorizeAttribute集合,然后进行逻辑判断即可。

var attributes = endpoint.Metadata.Where(_ => _ is ResourceAuthorizeAttribute).Cast<ResourceAuthorizeAttribute>().ToList();

最后再加个Log部分,个人老是忘记怎么自行指定日志的categoryName

ILoggerFactory loggerFactory;//注入
var loggerFactory.CreateLogger("limitLog");

可以扩展阅读的参考资料:

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值