Вопрос по web-services – Базовая проверка подлинности веб-службы Asmx

14

Я хочу реализовать базовую аутентификацию с использованием проверки имени пользователя и пароля в моемasmx веб-сервис.
I don't want to use WCF and I know this is not secure way, но мне нужно использовать базовую аутентификацию без использования https.

Мой веб-сервис выглядит так:

[WebService(Namespace = "http://www.mywebsite.com/")]
public class Service1
{
    [WebMethod]
    public string HelloWorld()
    {
        return "Hello world";
    }
}

И я использую этот кастомный HttpModule:

public class BasicAuthHttpModule : IHttpModule
{
    void IHttpModule.Init(HttpApplication context)
    {
        context.AuthenticateRequest += new EventHandler(OnAuthenticateRequest);
    }

    void OnAuthenticateRequest(object sender, EventArgs e)
    {
        string header = HttpContext.Current.Request.Headers["Authorization"];

        if (header != null && header.StartsWith("Basic"))  //if has header
        {
            string encodedUserPass = header.Substring(6).Trim();  //remove the "Basic"
            Encoding encoding = Encoding.GetEncoding("iso-8859-1");
            string userPass = encoding.GetString(Convert.FromBase64String(encodedUserPass));
            string[] credentials = userPass.Split(':');
            string username = credentials[0];
            string password = credentials[1];

            if(!MyUserValidator.Validate(username, password))
            {
                HttpContext.Current.Response.StatusCode = 401;
                HttpContext.Current.Response.End();
            }
        }
        else
        {
            //send request header for the 1st round
            HttpContext context = HttpContext.Current;
            context.Response.StatusCode = 401;
            context.Response.AddHeader("WWW-Authenticate", String.Format("Basic realm=\"{0}\"", string.Empty));
        }
    }

    void IHttpModule.Dispose()
    {
    }
}

И в web.config я использую это:

<?xml version="1.0"?>
<configuration>
    <appSettings/>
    <connectionStrings/>
    <system.web>
        <customErrors mode="Off" />
        <compilation debug="true" targetFramework="4.0"/>
        <authentication mode="None"/>
    </system.web>
    <system.webServer>
        <modules runAllManagedModulesForAllRequests="true">
            <add name="BasicAuthHttpModule"
                 type="AuthService.BasicAuthHttpModule, AuthService" />
        </modules>
    </system.webServer>
</configuration>    

Код вызова:

static void Main(string[] args)
{
    var proxy = new Service1.Service1()
                    {
                        Credentials = new NetworkCredential("user1", "[email protected]"),
                        PreAuthenticate = true
                    };
    try
    {
        var result = proxy.HelloWorld();
        Console.WriteLine(result);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
    Console.ReadKey();
}

когда я использую этот веб-сервис, сервис запрашивает базовую аутентификацию, ноheader переменная вOnAuthenticateRequest метод всегда равен нулю иMyUserValidator.Validate() никогда не беги.

EDIT

Результаты скрипача:

POST http://www.mywebsite.com/Service1.asmx HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.4927)
VsDebuggerCausalityData: uIDPo+drc57U77xGu/ZaOdYvw6IAAAAA8AjKQNpkV06FEWDEs2Oja2C+h3kM7dlDvnFfE1VlIIIACQAA
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://www.mywebsite.com/HelloWorld"
Host: www.mywebsite.com
Content-Length: 291
Expect: 100-continue
Connection: Keep-Alive

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><HelloWorld xmlns="http://www.mywebsite.com/" /></soap:Body></soap:Envelope>
HTTP/1.1 401 Unauthorized
Cache-Control: private
Content-Type: text/html
Server: Microsoft-IIS/7.5
WWW-Authenticate: Basic realm=""
X-AspNet-Version: 4.0.30319
WWW-Authenticate: Basic realm="www.mywebsite.com"
X-Powered-By: ASP.NET
Date: Sun, 03 Jun 2012 07:14:40 GMT
Content-Length: 1293
------------------------------------------------------------------

POST http://www.mywebsite.com/Service1.asmx HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.4927)
VsDebuggerCausalityData: uIDPo+drc57U77xGu/ZaOdYvw6IAAAAA8AjKQNpkV06FEWDEs2Oja2C+h3kM7dlDvnFfE1VlIIIACQAA
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://www.mywebsite.com/HelloWorld"
Authorization: Basic dXNlcjE6cEBzc3cwcmQ=
Host: www.mywebsite.com
Content-Length: 291
Expect: 100-continue

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 

xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><HelloWorld xmlns="http://www.mywebsite.com/" /></soap:Body></soap:Envelope>
HTTP/1.1 401 Unauthorized
Content-Type: text/html
Server: Microsoft-IIS/7.5
WWW-Authenticate: Basic realm="www.mywebsite.com"
X-Powered-By: ASP.NET
Date: Sun, 03 Jun 2012 07:14:41 GMT
Content-Length: 1293
------------------------------------------------------------------
Также посмотрите, что на самом деле делает ваш класс Service1. И посмотрите, что передается по проводам с помощью такого инструмента, как скрипач. Preet Sangha
Да, я уверен. Всегдаelse блок работает Majid Shamkhani
Я добавил также результат Fiddler в вопрос. Majid Shamkhani
Я добавил это в вопрос. Majid Shamkhani
Вы уверены, что он никогда не запускается? Вы поставили точку останова, чтобы подтвердить это? Preet Sangha

Ваш Ответ

2   ответа
12

Измените свой собственный код HttpModule на это:

public class BasicAuthHttpModule : IHttpModule
{
    public void Dispose()
    {
    }

    public void Init(HttpApplication application)
    {
        application.AuthenticateRequest += new 
            EventHandler(this.OnAuthenticateRequest);
        application.EndRequest += new 
            EventHandler(this.OnEndRequest);
    }

    public void OnAuthenticateRequest(object source, EventArgs
                        eventArgs)
    {
        HttpApplication app = (HttpApplication)source;

        string authHeader = app.Request.Headers["Authorization"];
        if (!string.IsNullOrEmpty(authHeader))
        {
            string authStr = app.Request.Headers["Authorization"];

            if (authStr == null || authStr.Length == 0)
            {
                return;
            }

            authStr = authStr.Trim();
            if (authStr.IndexOf("Basic", 0) != 0)
            {
                return;
            }

            authStr = authStr.Trim();

            string encodedCredentials = authStr.Substring(6);

            byte[] decodedBytes =
            Convert.FromBase64String(encodedCredentials);
            string s = new ASCIIEncoding().GetString(decodedBytes);

            string[] userPass = s.Split(new char[] { ':' });
            string username = userPass[0];
            string password = userPass[1];

            if (!MyUserValidator.Validate(username, password))
            {
                DenyAccess(app);
                return;
            }
        }
        else
        {
            app.Response.StatusCode = 401;
            app.Response.End();
        }
    }
    public void OnEndRequest(object source, EventArgs eventArgs)
    {
        if (HttpContext.Current.Response.StatusCode == 401)
        {
            HttpContext context = HttpContext.Current;
            context.Response.StatusCode = 401;
            context.Response.AddHeader("WWW-Authenticate", "Basic Realm");
        }
    }

    private void DenyAccess(HttpApplication app)
    {
        app.Response.StatusCode = 401;
        app.Response.StatusDescription = "Access Denied";
        app.Response.Write("401 Access Denied");
        app.CompleteRequest();
    }
}

Затем включитеAnonymous authentication и отключитьBasic, Digest а такжеWindows аутентификация для вашего сайта в IIS.

Note: Эта реализация будет работать и с WCF.

В моем случае мне также пришлось отключить анонимную аутентификацию.<security> <authentication> <digestAuthentication enabled="false"/> <windowsAuthentication enabled="false" /> <basicAuthentication enabled="false"/> <anonymousAuthentication enabled="false" /> ...
Для меня это работает только в пуле приложений, который использует «Интегрированный режим пула приложений». - не работает в классическом режиме. Но я не могу объяснить, почему именно ...
Работал на меня ... Мне пришлось редактировать раздел web.config. изменить тип с type = & quot; AuthService.BasicAuthHttpModule, AuthService & quot; набрать = "BasicAuthHttpModule". Я убедился, что класс, который я добавил BasicAuthHttpModule, не содержит пространства имен.
1

Кажется, вам нужно отправить заголовки вручную в первый раз:

отБлог Рика Стрэла

    string url = "http://rasnote/wconnect/admin/wc.wc?_maintain~ShowStatus";
    HttpWebRequest req = HttpWebRequest.Create(url) as HttpWebRequest;

    string user = "ricks";
    string pwd = "secret";
    string domain = "www.west-wind.com";

    string auth = "Basic " + Convert.ToBase64String(System.Text.Encoding.Default.GetBytes(user + ":" + pwd));
    req.PreAuthenticate = true;
    req.Headers.Add("Authorization", auth);
    req.UserAgent = ": Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 4.0.20506)";
    WebResponse resp = req.GetResponse();
    resp.Close();
Вы следили за остальной частью статьи о предварительной аутентификации?
Я использую этот код, и он также дает ошибку аутентификации наWebResponse resp = req.GetResponse(); Majid Shamkhani

Похожие вопросы