我怎样才能获得用户的使用操作筛选索赔资料? [英] How can I get user and claim information using action filters?

查看:127
本文介绍了我怎样才能获得用户的使用操作筛选索赔资料?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

现在我这样做是为了得到我需要的信息:

在我的基本控制器:

 公众诠释角色ID {搞定;私人集; }
    公众诠释用户id {搞定;私人集; }    公共无效setUserAndRole()
    {
        ClaimsIdentity claimsIdentity;
        VAR的HttpContext = HttpContext.Current;
        claimsIdentity = httpContext.User.Identity为ClaimsIdentity;
        角色ID = Int32.Parse(claimsIdentity.FindFirst(角色ID)值。);
        用户id = Int32.Parse(User.Identity.GetUserId());
    }

在我的控制器方法:

 公共异步任务< IHttpActionResult> getTest(INT examId,诠释userTestId,INT检索)
    {
        setUserAndRole();

我想要的角色ID和用户id可用在我的类的构造函数,但人口从我的理解构造闪光之前授权信息是可用的。

谁能告诉我我怎么可以这样用行动过滤器?我非常希望行动过滤器是在控制器级别,但如果没有的话可以把它在方法级别来完成。

我希望一些好的意见和建议。谢谢

更新,以显示System.Web.Http

 #地区大会System.Web.Http,版本= 5.2.2.0,文化=中性公钥= 31bf3856ad364e35
// C:\\ ^ h \\服务器\\包\\ Microsoft.AspNet.WebApi.Core.5.2.2 \\ lib目录\\ net45 \\ System.Web.Http.dll
#endregion使用的System.Threading;
使用System.Threading.Tasks;
使用System.Web.Http.Controllers;命名空间System.Web.Http.Filters
{
    //
    //摘要:
    //重新presents所有行动过滤器属性的基类。
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method,继承= TRUE,的AllowMultiple = TRUE)]
    公共抽象类ActionFilterAttribute:FilterAttribute,IActionFilter,IFilter的
    {
        //
        //摘要:
        //初始化System.Web.Http.Filters.ActionFilterAttribute的新实例
        //类。
        保护ActionFilterAttribute();        //
        //摘要:
        //调用操作方法后发生。
        //
        //参数:
        // actionExecutedContext:
        //动作执行上下文。
        公共虚拟无效OnActionExecuted(HttpActionExecutedContext actionExecutedContext);
        公共虚拟任务OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext,的CancellationToken的CancellationToken);
        //
        //摘要:
        //调用操作方法之前发生。
        //
        //参数:
        // ActionContext中:
        //动作环境。
        公共虚拟无效OnActionExecuting(HttpActionContext ActionContext中);
        公共虚拟任务OnActionExecutingAsync(HttpActionContext ActionContext中,的CancellationToken的CancellationToken);
    }
}


解决方案

根据您的方法签名(及以下后评论)在code假设你正在使用Web API,而不是MVC虽然这可能很容易对被改变MVC也是如此。

我要指定,如果你在要求纯粹看其如何创建code的维护一块被重复使用。在这种情况下,code获得基于声明的信息,并将其注入到你的控制器。你要求过滤器的事实是一个技术要求,但我也要去present不使用过滤器,但一个IoC,而不是它增加了一些灵活性(恕我直言)的解决方案。

一些提示


  • 尝试时/在可能的情况总是使用接口。这使得更容易单元测试,更容易改变的实施,等等。我不会进入所有的在这里,但<一个href=\"http://artofsoftwarereuse.com/2010/04/24/5-advantages-of-using-interfaces-for-reusable-assets/\">here是一个链接。

  • 在的WebAPI,也MVC不使用 System.Web.HttpContext.Current 。这是单元测试code,使得利用这个非常辛苦。 MVC和Web API有一个名为 HttpContextBase ,尽可能使用一个常见的​​抽象。如果没有其他的方式(我还没有看到这个没有),然后使用新HttpContextWrapper(System.Web.HttpContext.Current)并通过这个实例来什么都法/类,你要使用。
  • HttpContextWrapper HttpContextBase 派生)

提出的解决方案

这是在任何特定的顺序。请参阅结束为每个解决方案的基本职业清单。


  1. 网络API过滤器 - 你问什么了。一个Web API动作过滤器注入基于声明的信息到你的Web API方法。

  2. 的IoC / DI - 一个非常灵活的方式来注入依赖到你的控制器和类。我用AutoFac作为迪框架,并说明如何获得基于声明的方式注入到控制器。

  3. 授权过滤器 - 本质上的解决方案1的延伸,但在其中您可以保护您的Web API接口访问的方式使用。正如你想如何使用这些信息并不清楚我在做这个建议,你想,以确保用户有足够的权限跳。


共同code

UserInfo.cs

这是在这两个解决方案,我会在下面演示使用普通code。这是你身边要访问基于性能/索赔信息通用抽象。这样,您就不必扩展方法,如果你要访问添加到另一个属性,但只是扩展接口/类。

 使用系统;
使用System.Security.Claims;
使用的System.Web;
使用Microsoft.AspNet.Identity;命名空间了myNameSpace
{
    公共接口IUserInfo
    {
        INT角色ID {搞定; }
        INT用户ID {搞定; }
        布尔IsAuthenticated {搞定; }
    }    公共类WebUserInfo:IUserInfo
    {
        公众诠释角色ID {搞定;组; }
        公众诠释用户ID {搞定;组; }
        公共BOOL IsAuthenticated {搞定;组; }        公共WebUserInfo(HttpContextBase的HttpContext)
        {
            尝试
            {
                VAR claimsIdentity = httpContext.User.Identity为ClaimsIdentity;
                IsAuthenticated = httpContext.User.Identity.IsAuthenticated;
                如果(claimsIdentity!= NULL)
                {
                    角色ID = Int32.Parse(claimsIdentity.FindFirst(角色ID)值。);
                    用户ID = Int32.Parse(claimsIdentity.GetUserId());
                }
            }
            赶上(异常前)
            {
                IsAuthenticated = FALSE;
                用户ID = -1;
                角色ID = -1;                //日志异常
            }        }
    }
}


解决方案1 ​​ - 网页API过滤器

此解决方案演示,你问什么,该填充基于声明的信息可重用的Web API过滤器。

WebApiClaimsUserFilter.cs

 使用的System.Web;
使用System.Web.Http.Controllers;命名空间了myNameSpace
{
    公共类WebApiClaimsUserFilterAttribute:System.Web.Http.Filters.ActionFilterAttribute
    {
        公共覆盖无效OnActionExecuting(HttpActionContext ActionContext中)
        {
            //访问HttpContextBase实例可以使用属性集合MS_HttpContext完成
            VAR上下文=(HttpContextBase)actionContext.Request.Properties [MS_HttpContext];
            VAR用户=新WebUserInfo(背景);
            actionContext.ActionArguments [claimsUser] =用户; //键名在这里必须参数名中的方法要与此实例来填充匹配
            base.OnActionExecuting(ActionContext中);
        }
    }
}

现在你可以把它应用到像一个属性或类级别的Web API方法使用此过滤器。如果你想访问你到处也可以将其添加到 WebApiConfig.cs code像这样(的可选的)。

 公共静态类WebApiConfig
{
    公共静态无效的注册(HttpConfiguration配置)
    {
        config.Filters.Add(新WebApiClaimsUserFilterAttribute());
        // code的其余部分在这里
    }
}

WebApiTestController.cs

下面如何在Web API方法使用它。请注意,匹配基于参数名完成的,这必须匹配在过滤 actionContext.ActionArguments [claimsUser]指定的名称。你的方法现在将与你的过滤器添加的实例填充。

 使用System.Web.Http;
使用System.Threading.Tasks;命名空间了myNameSpace
{
    公共类WebApiTestController:ApiController
    {
        [WebApiClaimsUserFilterAttribute] //不是必要的,如果注册webapiconfig.cs
        公共异步任务&LT; IHttpActionResult&GT;获取(IUserInfo claimsUser)
        {
            VAR角色ID = claimsUser.RoleId;
            等待Task.Delay(1).ConfigureAwait(假);
            返回OK();
        }
    }
}


解决方案2 - 的IoC / DI

下面是控制和的维基://en.wikipedia。组织/维基/ Dependency_injection>依赖注入维基。这些条款,IOC和DI,通常交替使用。简单地说,你定义依赖,具有DI或IoC框架进行注册,然后将这些依赖实例在你的跑步code注入适合你。

有很多的IoC框架在那里,我用 AutoFac 但你可以使用任何你想要的。下面这个方法,你曾经定义注射剂和无论你想访问它们。只是引用我的新界面在构造将与实例在运行时被注入。

DependencyInjectionConfig.cs

 使用的System.Reflection;
使用System.Web.Http;
使用System.Web.Mvc;
使用Autofac;
使用Autofac.Integration.Mvc;
使用Autofac.Integration.WebApi;命名空间了myNameSpace
{
    公共静态类DependencyInjectionConfig
    {
        ///&LT;总结&gt;
        ///执行使用AutoFac所有依赖注入
        ///&LT; /总结&gt;
        ///&LT;&言论GT;看到AutoFac文档:https://github.com/autofac/Autofac/wiki
        ///比较AutoFac的速度与其他的IoC框架:HTTP://nareblog.word$p$pss.com/tag/ioc-autofac-ninject-asp-asp-net-mvc-inversion-of-control
        ///&LT; /言论&GT;
        公共静态无效RegisterDependencyInjection()
        {
            VAR建设者=新ContainerBuilder();
            无功配置= GlobalConfiguration.Configuration;            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());            builder.RegisterControllers(typeof运算(DependencyInjectionConfig).Assembly);            builder.RegisterModule(新AutofacWebTypesModule());            //这里我们指定我们要注入WebUserInfo无论遇到IUserInfo(即在控制器的公共构造函数)
            builder.RegisterType&LT; WebUserInfo&GT;()
                。至于&LT; IUserInfo&GT;()
                .InstancePerRequest();            变种容器= builder.Build();
            //对于Web API
            config.DependencyResolver =新AutofacWebApiDependencyResolver(容器);            // 2线MVC(不是Web API)
            VAR解析器=新AutofacDependencyResolver(容器);
            DependencyResolver.SetResolver(旋);
        }
    }
}

现在我们只需要调用这个当我们的应用程序启动,这可以在的Global.asax.cs 文件来完成。

 使用系统;
使用的System.Web;
使用System.Web.Mvc;
使用System.Web.Routing;
使用System.Web.Http;命名空间了myNameSpace
{
    公共类全球:一个HttpApplication
    {
        无效的Application_Start(对象发件人,EventArgs的发送)
        {
            DependencyInjectionConfig.RegisterDependencyInjection();
            // code休息
        }
    }
}

现在我们可以用它在以往任何时候我们想要的。

WebApiTestController.cs

 使用System.Web.Http;
使用System.Threading.Tasks;命名空间了myNameSpace
{
    公共类WebApiTestController:ApiController
    {
        私人IUserInfo _userInfo;
        公共WebApiTestController(IUserInfo USERINFO)
        {
            _userInfo =用户信息; //从AutoFac注入
        }
        公共异步任务&LT; IHttpActionResult&GT;得到()
        {
            VAR角色ID = _userInfo.RoleId;
            等待Task.Delay(1).ConfigureAwait(假);
            返回OK();
        }
    }
}

下面是你可以得到的NuGet这个例子的依赖关系。

 安装封装Autofac
安装封装Autofac.Mvc5
安装封装Autofac.WebApi2


解决方案3 - 授权过滤器

还有一个解决方案,我想到的。你永远不指定为什么你需要的用户和角色ID。也许你要检查的访问级别的方法之前。如果是这种情况下,最好的解决办法是,不仅实现一个过滤器,但创建 System.Web.Http.Filters.AuthorizationFilterAttribute 的覆盖。这可以让你在你的code甚至执行将是非常方便的,如果你已经在你的网络API接口不同级别的访问权限进行授权检查。在code我放在一起说明了这一点,但你可以扩展它来实际调用添加到支票的存储库。

WebApiAuthorizationClaimsUserFilterAttribute.cs

 使用System.Net;
使用System.Net.Http;
使用的System.Web;
使用System.Web.Http.Controllers;命名空间了myNameSpace
{
    公共类WebApiAuthorizationClaimsUserFilterAttribute:System.Web.Http.Filters.AuthorizationFilterAttribute
    {
        //授权角色ID(再次,只是一个例子来说明这一点。我不是在code崇尚硬codeD标识符)
        公众诠释AuthorizedRoleId {搞定;组; }        公共覆盖无效OnAuthorization(HttpActionContext ActionContext中)
        {
            VAR上下文=(HttpContextBase)actionContext.Request.Properties [MS_HttpContext];
            VAR用户=新WebUserInfo(背景);            //检查,如果用户进行身份验证,如果没有返回未经授权
            如果(user.IsAuthenticated || user.UserId&LT;!1)
                actionContext.Response = actionContext.Request.CreateResponse(的HTTPStatus code.Unauthorized,用户未通过身份验证......);
            否则,如果(user.RoleId大于0和放大器;&安培;!user.RoleId = AuthorizedRoleId)//如果用户进行身份验证,但不应该有访问返回紫禁城
                actionContext.Response = actionContext.Request.CreateResponse(的HTTPStatus code.Forbidden,不允许访问......);
        }
    }
}

WebApiTestController.cs

 使用System.Web.Http;
使用System.Threading.Tasks;命名空间了myNameSpace
{
    公共类WebApiTestController:ApiController
    {
        [WebApiAuthorizationClaimsUserFilterAttribute(AuthorizedRoleId = 21)] //一些角色ID
        公共异步任务&LT; IHttpActionResult&GT;获取(IUserInfo claimsUser)
        {
            如果用户是基于过滤器的授权// code将只能达到
            等待Task.Delay(1).ConfigureAwait(假);
            返回OK();
        }
    }
}


解决方案的快速比较


  • 如果您想要的灵活性,AutoFac去。您可以为您的许多解决方案/项目的运动部件的再利用这一点。这使得很容易维护和测试code。你可以很轻松地扩展它,一旦其设置和运行。

  • 如果你想要的东西的静态和简单的保证不会改变,你有运动部件凡DI框架将是矫枉过正然后用过滤解决方案去的最少数量。

  • 如果你想在一个位置执行授权检查,然后自定义 AuthorizationFilterAttribute 是最好的一段路要走。您可以从过滤溶液#1添加code将该code如果授权通过,这样,你仍然可以访问,为您的code其他目的的用户信息。

编辑


  • 我加了第三个解决方案的可能性列表。

  • 新增的答案顶部的解决方案总结。

Right now I am doing this to get the information I need:

In my base controller:

    public int roleId { get; private set; }
    public int userId { get; private set; }

    public void setUserAndRole()
    {
        ClaimsIdentity claimsIdentity;
        var httpContext = HttpContext.Current;
        claimsIdentity = httpContext.User.Identity as ClaimsIdentity;
        roleId = Int32.Parse(claimsIdentity.FindFirst("RoleId").Value);
        userId = Int32.Parse(User.Identity.GetUserId());
    }

In my controller methods:

    public async Task<IHttpActionResult> getTest(int examId, int userTestId, int retrieve)
    {
        setUserAndRole();

I wanted the roleId and userId to be available and populated in the constructor of my class but from what I understand the constructor fires before authorization information is available.

Can someone tell me how I could do this with an Action Filter? Ideally I would like the Action Filter to be at the controller level but if not then could it be done at the method level.

I am hoping for some good advice and suggestions. Thank you

Update to show System.Web.Http

#region Assembly System.Web.Http, Version=5.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
// C:\H\server\packages\Microsoft.AspNet.WebApi.Core.5.2.2\lib\net45\System.Web.Http.dll
#endregion

using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;

namespace System.Web.Http.Filters
{
    //
    // Summary:
    //     Represents the base class for all action-filter attributes.
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IFilter
    {
        //
        // Summary:
        //     Initializes a new instance of the System.Web.Http.Filters.ActionFilterAttribute
        //     class.
        protected ActionFilterAttribute();

        //
        // Summary:
        //     Occurs after the action method is invoked.
        //
        // Parameters:
        //   actionExecutedContext:
        //     The action executed context.
        public virtual void OnActionExecuted(HttpActionExecutedContext actionExecutedContext);
        public virtual Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken);
        //
        // Summary:
        //     Occurs before the action method is invoked.
        //
        // Parameters:
        //   actionContext:
        //     The action context.
        public virtual void OnActionExecuting(HttpActionContext actionContext);
        public virtual Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken);
    }
}

解决方案

Based on your method signature (and later comments below) the code assumes that you are using Web API and not MVC although this could easily be changed for MVC as well.

I do want to specify that if you look purely at the requirements its how can I create a maintainable piece of code that is reused. In this case the code gets claims based information and injects it into your controllers. The fact that you are asking for a Filter is a technical requirement but I am also going to present a solution that does not use a Filter but an IoC instead which adds some flexibility (IMHO).

Some Tips

  • Try to always use interfaces when/where possible. It makes for easier unit testing, easier to alter the implementation, etc. I will not go into that all here but here is a link.
  • In WebAPI and also MVC do not use the System.Web.HttpContext.Current. It is very hard to unit test code that makes use of this. Mvc and Web API have a common abstraction called HttpContextBase, use this when possible. If there is no other way (I have not seen this yet) then use new HttpContextWrapper(System.Web.HttpContext.Current) and pass this instance in to what ever method/class you want to use (HttpContextWrapper derives from HttpContextBase).

Proposed Solutions

These are in no particular order. See end for a basic pro list of each solution.

  1. Web API Filter - exactly what you are asking for. A Web API action filter to inject the claims based information into your Web Api methods.
  2. IoC/DI - A very flexible approach to injecting dependencies into your Controllers and classes. I used AutoFac as the Di framework and illustrate how you can get the claims based info injected into your controller.
  3. Authorization Filter - Essentially an extension on solution 1 but used in a manner in which you can secure access to your Web API interface. As it was not clear how you wanted to use this information I made the jump in this proposal that you wanted it to ensure the user had sufficient privileges.


Common Code

UserInfo.cs

This is common code used in both solutions that I will demo below. This is a common abstraction around the properties / claims based info you want access to. This way you do not have to extend methods if you want to add access to another property but just extend the interface / class.

using System;
using System.Security.Claims;
using System.Web;
using Microsoft.AspNet.Identity;

namespace MyNamespace
{
    public interface IUserInfo
    {
        int RoleId { get; }
        int UserId { get; }
        bool IsAuthenticated { get; }
    }

    public class WebUserInfo : IUserInfo
    {
        public int RoleId { get; set; }
        public int UserId { get; set; }
        public bool IsAuthenticated { get; set; }

        public WebUserInfo(HttpContextBase httpContext)
        {
            try
            {
                var claimsIdentity = httpContext.User.Identity as ClaimsIdentity;
                IsAuthenticated = httpContext.User.Identity.IsAuthenticated;
                if (claimsIdentity != null)
                {
                    RoleId = Int32.Parse(claimsIdentity.FindFirst("RoleId").Value);
                    UserId = Int32.Parse(claimsIdentity.GetUserId());
                }
            }
            catch (Exception ex)
            {
                IsAuthenticated = false;
                UserId = -1;
                RoleId = -1;

                // log exception
            }

        }
    }
}


Solution 1 - Web API Filter

This solution demos what you asked for, a reusable Web API filter that populates the claims based info.

WebApiClaimsUserFilter.cs

using System.Web;
using System.Web.Http.Controllers;

namespace MyNamespace
{
    public class WebApiClaimsUserFilterAttribute : System.Web.Http.Filters.ActionFilterAttribute
    {
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            // access to the HttpContextBase instance can be done using the Properties collection MS_HttpContext
            var context = (HttpContextBase) actionContext.Request.Properties["MS_HttpContext"];
            var user = new WebUserInfo(context);
            actionContext.ActionArguments["claimsUser"] = user; // key name here must match the parameter name in the methods you want to populate with this instance
            base.OnActionExecuting(actionContext);
        }
    }
}

Now you can use this filter by applying it to your Web API methods like an attribute or at the class level. If you want access everywhere you can also add it to the WebApiConfig.cs code like so (optional).

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Filters.Add(new WebApiClaimsUserFilterAttribute());
        // rest of code here
    }
}

WebApiTestController.cs

Here how to use it in a Web API method. Note that the matching is done based on the parameter name, this has to match the name assigned in the filter actionContext.ActionArguments["claimsUser"]. Your method will now be populated with the added instance from your filter.

using System.Web.Http;
using System.Threading.Tasks;

namespace MyNamespace
{
    public class WebApiTestController : ApiController
    {
        [WebApiClaimsUserFilterAttribute] // not necessary if registered in webapiconfig.cs
        public async Task<IHttpActionResult> Get(IUserInfo claimsUser)
        {
            var roleId = claimsUser.RoleId;
            await Task.Delay(1).ConfigureAwait(false);
            return Ok();
        }
    }
}


Solution 2 - IoC / DI

Here is a wiki on Inversion of Control and a wiki on Dependency Injection. These terms, IoC and DI, are usually used interchangeably. In a nutshell you define dependencies, register them with a DI or IoC framework, and these dependency instances are then injected in your running code for you.

There are many IoC frameworks out there, I used AutoFac but you can use whatever you want. Following this method you define your injectibles once and get access to them wherever you want. Just by referencing my new interface in the constructor it will be injected with the instance at run time.

DependencyInjectionConfig.cs

using System.Reflection;
using System.Web.Http;
using System.Web.Mvc;
using Autofac;
using Autofac.Integration.Mvc;
using Autofac.Integration.WebApi;

namespace MyNamespace
{
    public static class DependencyInjectionConfig
    {
        /// <summary>
        /// Executes all dependency injection using AutoFac
        /// </summary>
        /// <remarks>See AutoFac Documentation: https://github.com/autofac/Autofac/wiki
        /// Compare speed of AutoFac with other IoC frameworks: http://nareblog.wordpress.com/tag/ioc-autofac-ninject-asp-asp-net-mvc-inversion-of-control 
        /// </remarks>
        public static void RegisterDependencyInjection()
        {
            var builder = new ContainerBuilder();
            var config = GlobalConfiguration.Configuration;

            builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

            builder.RegisterControllers(typeof(DependencyInjectionConfig).Assembly);

            builder.RegisterModule(new AutofacWebTypesModule());

            // here we specify that we want to inject a WebUserInfo wherever IUserInfo is encountered (ie. in a public constructor in the Controllers)
            builder.RegisterType<WebUserInfo>()
                .As<IUserInfo>()
                .InstancePerRequest();

            var container = builder.Build();
            // For Web API
            config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

            // 2 lines for MVC (not web api)
            var resolver = new AutofacDependencyResolver(container);
            DependencyResolver.SetResolver(resolver);
        }
    }
}

Now we just have to call this when our application starts, this can be done in the Global.asax.cs file.

using System;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Http;

namespace MyNamespace
{
    public class Global : HttpApplication
    {
        void Application_Start(object sender, EventArgs e)
        {
            DependencyInjectionConfig.RegisterDependencyInjection();
            // rest of code
        }
    }
}

Now we can use it where ever we want.

WebApiTestController.cs

using System.Web.Http;
using System.Threading.Tasks;

namespace MyNamespace
{
    public class WebApiTestController : ApiController
    {
        private IUserInfo _userInfo;
        public WebApiTestController(IUserInfo userInfo)
        {
            _userInfo = userInfo; // injected from AutoFac
        }
        public async Task<IHttpActionResult> Get()
        {
            var roleId = _userInfo.RoleId;
            await Task.Delay(1).ConfigureAwait(false);
            return Ok();
        }
    }
}

Here are the dependencies you can get from NuGet for this example.

Install-Package Autofac
Install-Package Autofac.Mvc5
Install-Package Autofac.WebApi2


Solution 3 - Authorization Filter

One more solution I thought of. You never specified why you needed the user and role id. Maybe you want to check access level in the method before proceeding. If this is the case the best solution is to not only implement a Filter but to create an override of System.Web.Http.Filters.AuthorizationFilterAttribute. This allows you to execute an authorization check before your code even executes which is very handy if you have varying levels of access across your web api interface. The code I put together illustrates the point but you could extend it to add actual calls to a repository for checks.

WebApiAuthorizationClaimsUserFilterAttribute.cs

using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http.Controllers;

namespace MyNamespace
{
    public class WebApiAuthorizationClaimsUserFilterAttribute : System.Web.Http.Filters.AuthorizationFilterAttribute
    {
        // the authorized role id (again, just an example to illustrate this point. I am not advocating for hard coded identifiers in the code)
        public int AuthorizedRoleId { get; set; }

        public override void OnAuthorization(HttpActionContext actionContext)
        {
            var context = (HttpContextBase) actionContext.Request.Properties["MS_HttpContext"];
            var user = new WebUserInfo(context);

            // check if user is authenticated, if not return Unauthorized
            if (!user.IsAuthenticated || user.UserId < 1)
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized, "User not authenticated...");
            else if(user.RoleId > 0 && user.RoleId != AuthorizedRoleId) // if user is authenticated but should not have access return Forbidden
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden, "Not allowed to access...");
        }
    }
}

WebApiTestController.cs

using System.Web.Http;
using System.Threading.Tasks;

namespace MyNamespace
{
    public class WebApiTestController : ApiController
    {
        [WebApiAuthorizationClaimsUserFilterAttribute(AuthorizedRoleId = 21)] // some role id
        public async Task<IHttpActionResult> Get(IUserInfo claimsUser)
        {
            // code will only be reached if user is authorized based on the filter
            await Task.Delay(1).ConfigureAwait(false);
            return Ok();
        }
    }
}


Quick Comparison of Solutions

  • If you want flexibility go with AutoFac. You can reuse this for many of the moving parts of your solution/project. It makes for very maintainable and testable code. You can extend it very easily once its setup and running.
  • If you want something static and simple that is guaranteed not to change and you have minimal number of moving parts where an DI framework would be overkill then go with the Filter solution.
  • If you want to execute authorization checks in a single location then a custom AuthorizationFilterAttribute is the best way to go. You can add the code from the filter in solution #1 to this code if authorization passes, this way you still have access to the user information for other purposes in your code.

Edits

  • I added a 3rd solution to the list of possibilities.
  • Added a solution summary at the top of the answer.

这篇关于我怎样才能获得用户的使用操作筛选索赔资料?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆