从MVC 4 Project授权ASMX .NET Web服务的正确方法

时间:2016-03-07 15:06:32

标签: asp.net asp.net-mvc web-services asp.net-mvc-4 asmx

我有一个 ASP.NET MVC 应用程序,它具有.asmx Web服务

我编写了一个动作过滤器属性,我希望在Web服务上的Web方法上使用,检查UserID和Password的Request标头,如果无效或不存在,则抛出未经授权的响应代码。

然而,他们似乎没有被召唤!断点不会被击中。

首先,使用 MVC 属性是一种可接受的方式来授权在 ASMX Web服务上调用的Web服务吗?

其次,是否有更好/更有效的方式来授权Web服务方法调用?

4 个答案:

答案 0 :(得分:7)

在回答您的第一个问题时, ASMX 网络服务无法触发 MVC 过滤器和 Web API 过滤器

  1. 操作过滤器是 MVC 管道的一部分,在执行控制器(或API控制器)上的操作方法之前(或之后)触发。它们只能在 MVC 框架中使用。

    操作过滤器覆盖 MVC 控制器(OnActionExecuting)上的虚拟方法。由于只有 MVC 控制器具有此类方法,并且只有 MVC 管道检查它们

  2. 更糟糕的是, ASMX 服务默认使用 SOAP 协议而不是 HTTP 协议。 SOAP 服务无法访问HTTP上下文(例如HttpContext.Current.User)或 HTTP 框架。

    可以将 的Web服务配置为使用 HTTP协议。但是,即使这样, MVC 特定的属性也无济于事。

  3. 验证传统 ASMX 服务的方法

    • 理想的方式是add a Service Reference MVC 4 项目,像{{1}中的任何类库方法一样调用 ASMX 方法安全的Action方法或 Web API 方法。

      这样,您就可以利用 MVC Web API 身份验证过滤器。

    • 如果您希望直接保护 ASMX 服务,可以通过配置 ASMX 服务使用<来检查[Authorize]表单身份验证em> HTTP 协议。

    中的

    HttpContext.Current.User

答案 1 :(得分:2)

我认为为Authorization创建自定义属性过滤器是个好主意。 您可以创建自定义授权的服装过滤器。

namespace CustomeFilters
{
    class CustomAuthorize : AuthorizeAttribute
    {
        private const string _securityParameter = "someCredentials"; // Name of the url parameter. 
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            if (Authorize(filterContext))
            {
                return;
            }

            HandleUnauthorizedRequest(filterContext);
        }


    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        //Your logic for unauthorized access
        HttpRequestBase request = filterContext.RequestContext.HttpContext.Request;
        string deviceId = request.Params[_securityParameter]; //Your may have values in request headers

        if (!string.IsNullOrEmpty(_securityParameter ))
        {
            base.HandleUnauthorizedRequest(filterContext);

        }

        //You can also check if request is authorized as basic authentication or not
        //if(!filterContext.HttpContext.User.Identity.IsAuthenticated)
    }


    private bool Authorize(AuthorizationContext actionContext)
    {
            HttpRequestBase request = actionContext.RequestContext.HttpContext.Request;

            // Your authorisation logic goes here..                                     

           //actionContext.RequestContext.HttpContext.Response.StatusCode = 400;

           //actionContext.Result = new JsonResult { JsonRequestBehavior = JsonRequestBehavior.AllowGet, Data = "Request from invalid device !" };

            bool success = <true/false>;//Acording to authorisation logic
            return success;
    }
}

它会像这样使用

    [CustomAuthorize]
    public ActionResult Test()
    { 
        ViewBag.Message = "Hello World.";

        return View();
    }

这里是从MVC授权继承Authorize属性。 它覆盖了两种方法:

  
      
  1. OnAuthorisation:这里是您的授权逻辑。这是检查未经授权的请求。
  2.   
  3. HandleUnauthorizedRequest:这里用于处理未经授权的访问的逻辑。它正在调用它的parrent类   HandleUnauthorizedRequest执行处理未授权   访问。
  4.   

答案 2 :(得分:2)

问题的第一部分:

  

使用MVC属性是一种可接受的授权Web服务的方式   ASMX网络服务?

根据@DaveAlperovich

ASMX网络服务无法触发MVC过滤器和Web API过滤器。

但是从这个SO答案

  

由于ASMX也是ASP.NET管道的服务器,你可以使用   HttpModules,它为您提供了很多控制方式和方式   进行。

     

这是一个参考和一个例子:   http://msdn.microsoft.com/en-us/library/aa719858%28VS.71%29.aspx

     

如果你想让它非常像“MVC”那么你会写一个自定义   http模块,检查webservice的属性,如   [授权]等。由于ASP.NET MVC是开源的,你可以使用   作为参考的部分,他们如何检查属性等   然后将其构建到您的HTTPModule中。

Link to SO Question

所以我仍然无法找到关于你的第一个问题的正式文件 我仍然怀疑使用MVC属性时某些事件不会触发Web服务

<强>更新

来到ASMX(source

  

使用XML信息集作为其消息格式,并依赖于   应用层协议,最值得注意的是超文本传输​​协议   (HTTP)或简单邮件传输协议(SMTP),用于消息   谈判和传播

Scott Hanselman Blog开始,默认情况下,请求不由ASP.NET MVC路由机制处理

  

为什么ASP.NET MVC没有抓住请求?两个原因。首先,有   RouteCollection上的一个名为RouteExistingFiles的选项。它被设定为   默认情况下为false会导致ASP.NET MVC自动跳过   磁盘上存在文件时的路由。

第二个Qst:

  

是否有更好/更有效的授权Web服务方法的方法   呼叫?

您可以使用SOAP标头中发送的凭据来授权Web服务

以下是一个例子:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

namespace AuthExample
{

    public class Authentication : SoapHeader
    {
        public string User;
        public string Password;
    }

    /// <summary>
    /// Summary description for webrusterapi
    /// </summary>
    [WebService(Namespace = "http://xxxx.xxx")]
    [WebServiceBinding(ConformsTo = Profiles.BProfile1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class Webrusterapi: System.Web.Services.WebService
    {
        public Authentication authHeader;

        [WebMethod]
        public string HelloWorld()
        {
            return "Hello World";
        }

        [WebMethod]
        [SoapHeader("authHeader")]
        public string HelloWorldWithCredentials()
        {
            if (authHeader.User != "Foouser" & authHeader.Password != "barPassword")
            {
                new SoapException("Fault occurred", SoapException.ClientFaultCode);
            }
            return string.Format("Hello {0}", authHeader.User);
        }
    }
}

答案 3 :(得分:2)

.ASMX Service和AuthorizeAttribute

MVC和Web API管道与旧式的.ASMX Web服务不直接兼容。这就是为什么当您将这些属性放在Web方法上时,这些属性不会触发。根据您的代码库,您可以将代码转换(重写)到Web API 2平台,这是新推荐的编写服务的方式。与传统的Web服务(.asmx)相比,这具有以下优势。

  1. 数据格式 - 客户端可以确定接收数据的格式。目前支持的2种格式包括xmljson。对于客户端来说,这可以非常容易,因为发送和接收的有效负载通常更简单,更不用说轻量级(.asmx服务中使用的SOAP信封非常臃肿。)
  2. 操作过滤器 - 您可以利用“授权”属性以及自定义“操作过滤器”来执行常用操作预处理和后期处理。
  3. 使用HTTP Verb的意图 - 操作基于HTTP而不是SOAP。您可以使用http方法为您公开的Web方法(GET,POST,PUT,DELETE)提供直接意义。
  4. 跨开发平台的易用性 - 在所有其他条件相同的情况下,使用Web api方法编写比ASMX方法更简单,因为有效负载和响应更容易翻译臃肿一些标准类型也更容易翻译,这些类型通常包含在WSDL定义语言中,如可空类型和.net DateTime实例。
  5. 然后问题变为&#34;您是否应该转换现有代码?&#34; 取决于:

    • 您是否已经调用了您的代码库并且还需要转换的客户端?如果这些客户端不受您的控制(例如,如果这些客户是由您的客户创建的话),那么这可能无法实现这一点。
    • 您已创建的方法的大小或数量。如果你刚刚开始你的项目,它可能仍然很容易转换为Web Api,但如果你已经有一个大量的代码库与单元测试,这可能不符合成本效益。
    • 如果您已经与代码周围的外部各方签订了合同。可以在WSDL中创建定义,并根据该合同同时运行客户端开发和服务器端开发,如果是这种情况,您需要说服客户端开发人员/各方转换为Web API合同但这可能是不可能的。

    我要避免的是在Web API中编写一个包装器来调用Web服务。

    • 它在呼叫之间添加物理层(穿过另一个网络边界),这增加了发送的消息和收到的响应之间的延迟
    • 它添加了您必须创建和维护的另一层代码
    • 这样的附加(不必要的)层使得在必须实施更改时无意中引入缺陷非常容易

    .ASMX授权

    现在假设您要继续使用.ASMX Web服务并解决问题How can you execute Authorization on a web service

    传统/事实

    传统的身份验证方法是在SOAP标头中包含身份验证信息。使用现有的SoapHeaderAttribute可以轻松完成此操作。

    • SoapHeaderAttribute放在您的网络方法
    • 创建一个Authentication对象,该对象将包含用于身份验证的传入参数
    • 编写身份验证方法

    我更喜欢创建我的其他服务继承的抽象基础服务。这应该创建一个少一点重复的代码。这是一个没有身份验证详细信息的完整示例。在这个例子中,我使用传统的用户名和密码,但实际上它可以是任何东西(令牌,密码哈希,HMAC信息等),因为这个问题有点超出了我不会进入身份验证细节的范围。 / p>

    using System.Web.Services;
    using System.Web.Services.Protocols;
    
    public abstract class AuthorizedWebService : System.Web.Services.WebService 
    {
        // authentication info
        public Authentication Authentication { get; set; }
        // execute the actual authentication and authorization check
        protected virtual void Authorize()
        {
            // check the Authentication instance object (passed in credentials)
            // if not authenticate or authorized
            // throw new System.Security.Authentication.AuthenticationException();
        }
    }
    // authentication info
    public class Authentication : SoapHeader
    {
        public string Username { get; set; }
        public string Password { get; set; }
    }
    
    [WebService(Namespace = "http://tempuri.org/")]
    public class MyTraditionalWebService : AuthorizedWebService
    {
    
        [WebMethod(Description = "Some web method.")]
        [SoapHeader("Authentication")]
        public string HelloWorld()
        {
            base.Authorize();
            return "Hello " + base.Authentication.Username;
        }
    }
    

    Active Directory身份验证

    您可以使用Active Directory身份验证。然后,在c#中,客户端将使用NetworkCredential类传递凭据。基本上客户端执行的操作是将身份验证凭据应用于HTTP标头。我发现这个good SO answer代表了在进行HTTP调用时NetworkCredential类实际转化为什么。您必须配置IIS,以便在请求到达方法之前进行身份验证和授权。您也可以直接在Web方法中执行授权的自定义代码(类似于上面的内容),但不能用于身份验证。

    表单身份验证

    对于表单身份验证,使用与上述指定Traditional / defacto方式相比具有任何优势的Web服务没有好办法。但是,如果您已经拥有(现在)包含.asmx服务的网站设置,那么您可以在web.config中包含该服务的授权,前提是客户端已经对您的网站进行了身份验证。

    自定义HttpModule

    您还可以编写一个自定义HttpModule来处理身份验证和可能的授权。这种方法的优点是您可以将Web服务中的业务逻辑与身份验证/授权分离。这是一把双刃剑,但你必须维护一个解析url的模块,以及查看请求是否被授权的预期方法。这可能导致脆弱的耦合。