Correct way to authorize an ASMX .NET web service from MVC 4 Project

后端 未结 4 1607
心在旅途
心在旅途 2021-02-14 00:45

I have an ASP.NET MVC application that has a .asmx web service

I wrote an action filter attribute that I wanted to use on web methods on the web service, to che

4条回答
  •  情书的邮戳
    2021-02-14 01:04

    .ASMX Service and AuthorizeAttribute

    The MVC and Web API pipeline are not directly compatible with the older style of .ASMX web services. This is why those attributes do not fire when you place them on your web methods. Depending on your code base you could convert (rewrite) your code to the Web API 2 platform which is the new recommended way to write services. This has the following advantages over the traditional web services (.asmx).

    1. Data Format - The client can determine the format of the data that is received. Currently the 2 out of the box supported formats are xml and json. This can be significantly easier to work with for a client as the payload sent and received is usually much simpler not to mention light weight (the SOAP envelop used in .asmx services is very bloated.)
    2. Action Filters - You can take advantage of the Authorize attribute as well as custom Action Filters to execute common action preprocessing and post processing.
    3. Intentions with HTTP Verb - Actions become based on HTTP instead of SOAP. You can utilize the http methods to give direct meaning to your exposed web methods (GET, POST, PUT, DELETE).
    4. Ease of use across development platforms - All other things being equal it is much simpler to write against a web api method than an ASMX method because the payload and responses are easier to translate due to the lack of bloat. Some of the standard types are also easier to translate which are usually included in the WSDL definition language like nullable types and .net DateTime instances.

    The question then becomes "Should you convert your existing code?" That depends on:

    • Do you have existing clients that already call your code base that would also need to be converted? That might not make this possible if those clients are outside of your control (if these calling clients are created by your customers for example).
    • The size or number of methods that you already have created. If you are just starting your project it might still be easy to convert over to Web Api but if you already have a substantial code base with unit tests this might not be cost effective.
    • If you already have a contract defined with outside parties around your code. It is possible to create the definitions in a WSDL and have client development and server side development run concurrently based on that contract, if this is the case you would need to convince your client side developer(s)/parties to convert to a Web API contract but this might not be possible.

    What I would avoid is writing a wrapper in Web API that calls through to the Web Service.

    • It adds a physical layer between calls (crossing another network boundary) which increases the delay between message sent and response received
    • It adds another layer of code that you have to create and maintain
    • Additional (unnecessary) layers also like this make it very easy to inadvertently introduce defects when you have to implement changes

    .ASMX Authorization

    Lets now assume that you want to continue with the .ASMX web services and address the question How can you execute Authorization on a web service.

    Traditional / defacto

    The traditional way to authenticate is to include the authentication information in the SOAP header. This can be easily accomplished using the existing SoapHeaderAttribute.

    • Place the SoapHeaderAttribute on your web method(s)
    • Create an Authentication object that will contain the passed in arguments used for authentication
    • Write the authentication method

    I prefer to create an abstract base service that my other services inherit from. This should create a little less duplicate code. Here is a full example without the authentication details. In this example I use a traditional user name and password but really it can be anything (token, a password hash, HMAC info, etc) and as that is a little out of scope for the question I will not get into authentication details.

    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 Authentication

    You can use Active Directory authentication. In c# a client would then pass in the credentials using the NetworkCredential class. Essentially what the client does is apply the authentication credentials to the HTTP header. I found this rather good SO answer on what the NetworkCredential class will actually translate into when making an HTTP call. You have to configure IIS so that authentication and authorization occur before the request reaches your method. You could also execute custom code for the authorization directly in your web methods (similar to above) but not for the authentication.

    Forms Authentication

    As for Forms Authentication there is no good way to do this with Web Services that has any advantage over the above specified Traditional / defacto way. However, if you already have a web site setup which (now) includes your .asmx services then you could include authorization for the service in the web.config assuming that the client has already authenticated to your site.

    Custom HttpModule

    You could also write a custom HttpModule which handles the authentication and possible Authorization. The pro of this approach is you decouple the business logic in the web service from the authentication/authorization. This is a double edged sword though as you will have to maintain a module that parses the url and also the intended method to see if the request is authorized. This can lead to a fragile coupling.

提交回复
热议问题