我应该在 ActionFilter 中测试 AdalException 吗?

Should I be testing for an AdalException inside an ActionFilter?

在 GitHub like this one 上的一些 Azure 示例中,我们有一个使用 ADAL 访问受保护 Web API 资源的示例。这项工作受到 try/catch 寻找 AdalException

的保护

我将代码总结如下:

 try 
 { 
     //pseudo code...  configure a client to use an access token..
     var token = ADAL.AcquireTokenAsync...
     var httpClient = new HttpClient(baseUri, token);

     // use the token for querying some protected API
     var result = //await HttpClient to return data...

     return View(result); 
 } 
 catch (AdalException) 
 { 
     // do something important with the exception, 
     // e.g. return an error View w/login link
 } 

因此,当我开始充实我的 MVC 控制器以使用 ADAL-access_token 的请求时,我真的希望每个控制器都包含所有这些 try/catch 业务吗?

创建一个 ActionFilter 有意义吗?这段代码的灵感来自于我在 this Azure Sample

看到的代码
public class AdalErrorAttribute : FilterAttribute, IExceptionFilter
{
    void IExceptionFilter.OnException(ExceptionContext filterContext)
    {
        if(filterContext.Exception is AdalException)
        {
            if (filterContext.RequestContext.HttpContext.Request.QueryString["reauth"] == "True")
            {
                //
                // Send an OpenID Connect sign-in request to get a new set of tokens.
                // If the user still has a valid session with Azure AD, they will not be prompted for their credentials.
                // The OpenID Connect middleware will return to this controller after the sign-in response has been handled.
                //
                filterContext.RequestContext.HttpContext.GetOwinContext().Authentication.Challenge(
                    new AuthenticationProperties(),
                    OpenIdConnectAuthenticationDefaults.AuthenticationType);
            }
        }
    }
}

我的背景: 我正在使用一组相当同质的脚手架 MVC 控制器,这些控制器在生成时以 EntityFramework 为中心......但现在需要重新配置以访问我的 Web API(通过我的新AutoRest 客户端)

该方法有两个问题。

  1. 您提到的示例代码和过滤器实现是针对 web APP 的,而不是 web API。这是一个重要的区别。 Web APP 可以依赖浏览器与用户交互进行身份验证; web APIs 不知道客户端有什么用户体验(或者即使有任何用户体验)因此错误行为完全不同
  2. 一个控制器可能会调用多个 API,需要针对不同资源的多个令牌请求 - 这可能会独立失败或成功,并连接到不同的提供者。不同的控制器可能调用不同的资源。对错误的反应可能会有所不同。诸如您设计的原型过滤器之类的过滤器只能帮助处理非常有限的情况。 因此我会说除非你的控制器都被期望执行非常同质的逻辑,否则像上面这样的过滤器不会给你所需的灵活性。

@vibronet 提出了一个很好的观点 - 不要 为您的 WebAPI 端点这样做。它们是通过承载身份验证调用的,不应自动重定向到登录过程。返回一个 401 指示凭据无效并放手。

但对于用户交互使用的 MVC 应用程序,这是一个合理的想法,但要遵守一些限制条件。

  1. 确保您的过滤器对匹配的内容非常严格。 IE。确保它 处理异常,您可以合理地确定身份验证问题(而不是访问被拒绝的问题)。也许是您的包装逻辑抛出的自定义异常,或者超出它的一些额外条件是 ADALException 以确保它是可以通过再次登录解决的问题。
  2. 除非你真的想要每个 请求都有这个处理,看看将它附加到控制器或操作层而不是全局。
  3. 寻找潜在的 "loop" 问题,如果出现错误,请告诉用户重新登录,收到错误信息,让他们重新登录等。也许在会话中设置一些数据触发登录,或在登录过程中,或类似的东西。给出错误消息比让用户的浏览器陷入无限重定向循环更好。 (当然,这也适用于手动处理异常的情况)

希望对您有所帮助。