1

在使用 MVC 5、Web API 2.0 和 EF Core 1.0 的 Azure 移动应用服务服务器端应用程序上,可以像这样装饰控制器以实现基于令牌的身份验证:

// Server-side EF Core 1.0 / Web API 2 REST API
[Authorize]
public class TodoItemController : TableController<TodoItem>
{
  protected override void Initialize(HttpControllerContext controllerContext)
  {
     base.Initialize(controllerContext);

     DomainManager = new EntityDomainManager<TodoItem>(context, Request);
  }

  // GET tables/TodoItem
  public IQueryable<TodoItem> GetAllTodoItems()
  {
     return Query();
  }
  ...
}

我希望能够在客户端做类似的事情,我用上面的 [Authorize] 之类的东西装饰一个方法,也许用下面的 [Secured] 装饰:

public class TodoItem
{
    string id;
    string name;
    bool done;

    [JsonProperty(PropertyName = "id")]
    public string Id
    {
        get { return id; }
        set { id = value;}
    }

    [JsonProperty(PropertyName = "text")]
    public string Name
    {
        get { return name; }
        set { name = value;}
    }

    [JsonProperty(PropertyName = "complete")]
    public bool Done
    {
        get { return done; }
        set { done = value;}
    }

    [Version]
    public string Version { get; set; }
}

// Client side code calling GetAllTodoItems from above
[Secured]
public async Task<ObservableCollection<TodoItem>> GetTodoItemsAsync()
{
    try
    {
        IEnumerable<TodoItem> items = await todoTable
            .Where(todoItem => !todoItem.Done)
            .ToEnumerableAsync();

        return new ObservableCollection<TodoItem>(items);
    }
    catch (MobileServiceInvalidOperationException msioe)
    {
        Debug.WriteLine(@"Invalid sync operation: {0}", msioe. 
    }
    catch (Exception e)
    {
        Debug.WriteLine(@"Sync error: {0}", e.Message);
    }

    return null;
}

其中 [Secured] 可能被定义为:

public class SecuredFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // Check if user is logged in, if not, redirect to the login page.
    }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // Check some globally accessible member to see if user is logged out.
    }
}

不幸的是,上述代码仅适用于 MVC 1.0 应用程序及更高版本中的控制器,根据 Microsoft 关于“创建自定义操作过滤器”的文章: https://msdn.microsoft.com/en-us/library/dd381609(v=vs. 100).aspx

如何实现类似于“自定义操作过滤器”的功能,允许我在移动应用服务客户端而不是服务器中使用“[Secured]”装饰?答案将帮助我从客户端创建自定义身份验证并将代码保存在一个位置而不会使实现复杂化,即,它是一个横切关注点,如性能指标、重复尝试的自定义执行计划、日志记录等。

使场景复杂化的是,客户端还实现了适用于 iOS 的 Xamarin.Forms,并且由于 iOS 对本机代码的要求,它必须是功能性的 Ahead of Time 模式,JIT 尚不可能。

4

2 回答 2

1

您通过几个不同的名称/术语来更广泛地描述的内容。首先想到的是“面向方面的编程”(或简称 AOP)。它处理所谓的横切关注点。我愿意打赌你想做两件事之一

  1. 以标准化的有意义的方式记录异常/消息
  2. 记录系统区域的时间/性能

在一般意义上,是的,C# 能够做这样的事情。将有无数关于如何做到这一点的在线教程,以这种方式回答太宽泛了。

但是,asp.net MVC 的作者对这些东西很有想法,并为您提供了许多属性,就像您描述的那样,可以随意扩展,并提供对管道的轻松访问,为开发人员提供所有信息他们需要(例如当前路由、任何参数、任何异常、任何授权/身份验证请求等)

这将是一个很好的起点: http: //www.strathweb.com/2015/06/action-filters-service-filters-type-filters-asp-net-5-mvc-6/

这看起来也不错: http: //www.dotnetcurry.com/aspnet-mvc/976/aspnet-mvc-custom-action-filter

于 2016-03-29T21:57:34.960 回答
1

属性在您描述的场景中起作用的原因是因为其他代码负责实际调用方法或读取属性,而其他代码将查找属性并相应地修改行为。当您只是在运行 C# 代码时,通常不会得到它;没有一种本地方法可以在执行方法之前执行属性中的代码。

从您所描述的情况来看,听起来您正在追求面向方面的编程。请参阅.Net 中 AOP 的最佳实现是什么?获取框架列表。

本质上,使用适当的 AOP 框架,您可以添加属性或其他标记,并在编译时执行或插入代码。有很多方法,因此我不是很具体,抱歉。您确实需要了解 AOP 方法与 ASP.Net MVC 之类的工作方式不同,因为 AOP 通常会修改您的运行时代码(无论如何,在我的理解中,我确信这方面也有变化)。

至于 AOP 是否真的可行,将取决于您的要求,但我会谨慎行事 - 这不适合胆小的人。

这个问题的一个完全替代解决方案是查看类似Mediatr或类似的东西,将您的逻辑分解为一组命令,您可以通过消息总线调用这些命令。有帮助的原因是您可以使用各种类型的逻辑(包括授权逻辑)来装饰您的消息总线(或管道)。该解决方案与您所要求的非常不同 - 但无论如何可能更可取。

或者只是添加一个单行授权调用作为每个方法中的第一行,而不是作为一个属性来做......

于 2016-03-29T22:14:03.173 回答