powered by simpleCommunicator - 2.0.40     © 2025 Programmizd 02
Форумы / WCF, Web Services, Remoting [игнор отключен] [закрыт для гостей] / WCF Basic аутентификация
2 сообщений из 2, страница 1 из 1
WCF Basic аутентификация
    #39149496
tikskit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Привет! Я делаю basic-авторизацию в WCF.

Я в этом новичок и мои попытки основаны на серии статей http://leastprivilege.com/2008/01/11/http-basic-authentication-against-non-windows-accounts-in-iisasp-net-part-0-intro/
Я использую привязку webHttpBinding и HTTPS включен

Главная идея - реализовать интерфейс IHttpModule следующим образом

Когда пользователь отправляет запрос, модуль проверяет присутствует ли в запросе заголовок Authorization

Если Authorization присутствует, модуль извлекает его значение, декодирует логин и пароль из Base64 и проверяет совпадение

Если Authorization отсутствует, модуль возвращает код 401 с заголовком WWW-Authenticate

Вот моя реализация модуля:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Management;
using System.Text;

namespace MyProj_A
{
    public class MyHTTPModule : IHttpModule
    {

        void IHttpModule.Dispose()
        {
        }

        void IHttpModule.Init(HttpApplication context)
        {
            context.BeginRequest += Context_BeginRequest;
            context.AuthenticateRequest += OnEnter;
            context.EndRequest += OnLeave;
        }


        private void Context_BeginRequest(object sender, EventArgs e)
        {
            HttpContext context = HttpContext.Current;
            context.Response.Write("BeginRequest");
        }

        void OnEnter(object sender, EventArgs e)
        {
            HttpContext context = HttpContext.Current;
            if (IsHeaderPresent())
            {
                if (!AuthenticateUser())
                {
                    DenyAccess();
                }
            }
            else
            {
                // if anonymous requests are not allowed - end the request
                DenyAccess();
            }
        }

        bool IsHeaderPresent()
        {
            return HttpContext.Current.Request.Headers["Authorization"] != null;
        }

        bool AuthenticateUser()
        {
            string username = "", password = "";
            string authHeader = HttpContext.Current.Request.Headers["Authorization"];
            if (authHeader != null && authHeader.StartsWith("Basic"))
            {
                // extract credentials from header
                string[] credentials = ExtractCredentials(authHeader);
                username = credentials[0];
                password = credentials[1];
                if (username.CompareTo("tikskit") == 0 && password.CompareTo("") == 0)
                {
                    return true;
                } else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }


        private static void DenyAccess()
        {
            HttpContext context = HttpContext.Current;

            context.Response.StatusCode = 401;
            context.Response.End();
        }

        void OnLeave(object sender, EventArgs e)
        {
            // check if module is enabled
            if (HttpContext.Current.Response.StatusCode == 401)
            {
                SendAuthenticationHeader();
            }
        }

        private void SendAuthenticationHeader()
        {
            HttpContext context = HttpContext.Current;

            context.Response.StatusCode = 401;
            context.Response.AddHeader(
                "WWW-Authenticate",
                "Basic realm=\"yo-ho-ho\""
                );

        }
    }

}



И вот мой web.config

Код: xml
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
<?xml version="1.0"?>
<configuration>

  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
  </appSettings>
  <system.web>
    <compilation debug="true" targetFramework="4.5.2" />
    <httpRuntime targetFramework="4.5.2"/>
    <customErrors mode="Off" />
  </system.web>


  <system.serviceModel>
    <behaviors>

      <endpointBehaviors>
        <behavior name="webBehavior">
          <webHttp automaticFormatSelectionEnabled="false"/>
        </behavior>
      </endpointBehaviors>

       <serviceBehaviors>
        <behavior name="Default" >
          <serviceMetadata httpGetEnabled="false" />
          <serviceMetadata httpsGetEnabled="false"/>
          <serviceAuthenticationManager authenticationSchemes="Basic"/>
          <serviceCredentials>
          </serviceCredentials>

        </behavior>
      </serviceBehaviors>

    </behaviors>

    <bindings>      
      <webHttpBinding>
        <binding name="MyBinding">
          <security mode="TransportCredentialOnly">
            <transport clientCredentialType="Basic"/>
          </security>
        </binding>
      </webHttpBinding>
    </bindings>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />

    <services>
      <service name="MyProj_A.Service1">
        <endpoint address="" binding="webHttpBinding" contract="MyProj_A.IService1"
                  behaviorConfiguration="webBehavior"/>
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost/" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <diagnostics>
      <endToEndTracing activityTracing="false" messageFlowTracing="true" propagateActivity="true"></endToEndTracing>
    </diagnostics>
  </system.serviceModel>

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="MyHTTPModule"
        type="MyProj_A.MyHTTPModule,MyProj-A"/>
    </modules>

    <directoryBrowse enabled="false"/>
  </system.webServer>

</configuration>




Я компилирую и публикую проект под IIS 7.5 на удаленном компьютере и подключаюсь к нему из Visual Studio через remote debugger, предварительно расставив брейкпойнты в Context_BeginRequest, OnEnter и OnLeave.

Потом я отправляю запрос к моей WCF из браузера, используя URL. И вот что происходит:


После того, как я жму в браузере Enter, срабатывает Context_BeginRequest

Там я могу видеть из VS, что заголовок Authorization в запросе отсутствует

Срабатывает OnEnter, где в конце концов ответу присваивается код 401

Срабатывает OnLeave, где в ответ добавляется заголовок WWW-Authenticate

В браузере отображается стандартное окно запроса пароля и логина

Ввожу в этом окне логин и пароль и жму ОК

Срабатывает Context_BeginRequest, где я вижу, что заголовок Authorization присутствует с значением "Basic <логин и пароль в Base64>"

На этот раз OnEnter не срабатывает

Выполнение попадает в OnLeave, где значение HttpContext.Current.Response.StatusCode уже почему-то равно 401


У меня следующие вопросы:

Почему OnEnter не срабатывает во второй раз, когда браузер присылает запрос с Authorization в заголовках? Вот тут сказано, что AuthenticateRequest срабатывает тогда, когда пользователь уже прошел аутентификацию. Тогда я не понимаю, почему OnEnter срабатывает в первый раз, когда никто еще не вводил никакого пароля? У меня каким-то образом включена анонимная аутентификация? Я в IIS удалил все модули аутентификации, кроме BasicAuthenticationModule! Манипуляции с <authentication mode="Forms"/> в <system.web> тоже ничего не дали

Почему, когда браузер присылает запрос с Authorization, в OnLeave код ответа уже установлен 401? Что и где это устанавливает?

Как мне правильно настроить мой web.config и IIS и как правильно реализовать Basic-аутентификацию?

Спасибо!
...
Рейтинг: 0 / 0
WCF Basic аутентификация
    #39152181
tikskit
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Вопрос закрыт

Забыл сослаться на конфигурацию binding в конфигурировании endpoint
Код: xml
1.
2.
3.
<endpoint address="" binding="webHttpBinding" contract="MyProj_A.IService1"
                  behaviorConfiguration="webBehavior"
                  bindingConfiguration="MyBinding"/>
...
Рейтинг: 0 / 0
2 сообщений из 2, страница 1 из 1
Форумы / WCF, Web Services, Remoting [игнор отключен] [закрыт для гостей] / WCF Basic аутентификация
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]