Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Статья : Авторизация и аутентификация на сайтах


Автор: Brausman 22.10.2009, 19:24
Начнем по порядку, так как я пишу свою первую статью, не бейте сильно за нее.
В данной статье буду рассмотрены вопросы :
-Авторизации на любом из сайтов(http и https с подтвержденными сертификатами), через ввод логин/пароля в браузере, 2 способами;
-Аутентификация, программное подставление сертификата в запрос к серверу,если он его требует,ручная аутентификация с помощью браузера показана ниже.
http://www.radikal.ru



-Аутентификация с авторизацией,через системное окно авторизации windows , которое показано ниже
 http://www.radikal.ru


1. Начнем с теории, ниже буду приведены ссылки на ресурсы, по которым не сведущий в WinInet человек сможет разобраться, в его основах:
http://www.delphisources.ru/pages/faq/base/inet_win32_api_functions.html - данная статья рассказывает об основных функция Win 32 API для работы с интернетом
http://kodu.neti.ee/~juri4/vfpplus/inet_11_ru.htm - данная статья предназначена для программистов под VisualFox Pro, но полезности ее не умоляет, в ней описаны все возможные флаги для WIn 32 API функций работы с интернетом описанных ссылкой выше
http://programmersforum.ru/showthread.php?t=38803 - в данной статье рассказано как анализировать html-код страницы перед написанием запроса авторизации.

Данного материала вам хватит для понятия сути описанной ниже статьи, также по ходу описания автор будет давать пояснения, в тех местах где по его мнению они нужны, чтобы конечный но не опытный читатель мог все спокойно понять.

Автор предупреждает, что не будет вступать в споры по поводу оптимизации кода, данная статья не про это

2.  И так нам понадобится CodeGear Rad Studio 2009 и сниффер(программа для отслеживания запросов/ответов между клиентом и сервером) HTTP Analyzer.
Сначало опишем нужные нам функции, которые потом буду использоваться для наших нужд.

а) В функцию 
Код
InternetConnect
, под параметром 
Код
lpszServerName: PChar
 передается имя сервера, т.е. 
для http://www.delphisources.ru/pages/faq/base/inet_win32_api_functions.html имя сервера будет www.delphisources.ru,следовательно из полного url нам нужно его вытащить, для этого предназначена простенькая функция:
Код

function GetHostName(url : string) : string;
begin
  result := '';
  if pos('https://',url) > 0 then
    begin
      delete(url,1,length('https://'));
      SetLength(url,pos('/',url) - 1);
      result := url;
    end
  else
    if pos('http://',url) > 0 then
      begin
        delete(url,1,length('http://'));
        SetLength(url,pos('/',url) - 1);
        result := url;
      end;
end;


б) Идем дальше)), в функцию 
Код
HttpOpenRequest
 передается параметр
Код
lpszObjectName
 - он же скрипт, также берется из полного url, из
http://www.delphisources.ru/pages/faq/base/inet_win32_api_functions.html  скрипт будет 
pages/faq/base/inet_win32_api_functions.html ,для его вытаскивания служит следующая функция :
Код

function GetScriptName( url,hostname : string) : string;
begin
  result := '';
  delete(url,1,pos(hostname,url) + length(hostname));
  result := url;
end;


в) Теперь напишем функцию, которая в зависимости от протокола безопасности (http или https), будет возвращать нам нужные флаги для последующей их подстановки в  
Код
InternetConnect и HttpOpenReques
, напишем ее:
Код

procedure SetFlags(url : string; out Flags_connection,Flags_Request : Cardinal);
begin
  //Оприделяем на https или http
  if pos('https',url) > 0 then
    begin
      Flags_connection := INTERNET_DEFAULT_HTTPS_PORT;
      Flags_Request := INTERNET_FLAG_RELOAD or INTERNET_FLAG_IGNORE_CERT_CN_INVALID or INTERNET_FLAG_NO_CACHE_WRITE or INTERNET_FLAG_SECURE or INTERNET_FLAG_PRAGMA_NOCACHE or INTERNET_FLAG_KEEP_CONNECTION;
    end
  else
    begin
      Flags_connection := INTERNET_DEFAULT_HTTP_PORT;
      Flags_Request := INTERNET_FLAG_RELOAD or INTERNET_FLAG_IGNORE_CERT_CN_INVALID or INTERNET_FLAG_NO_CACHE_WRITE or INTERNET_FLAG_PRAGMA_NOCACHE or INTERNET_FLAG_KEEP_CONNECTION;
    end;
end;


Какой флаг, что означает вы узнаете перейдя по данной мной выше ссылки.

г) Так как нам ответ от сервера будет приходить в виде данных, то мы должны знать скольза за один раз передается нам данных от сервера, для этого служит следующая функция:
Код

function DataAvailable(hRequest: pointer; out Size : cardinal): boolean;
begin
  result := wininet.InternetQueryDataAvailable(hRequest, Size, 0, 0);
end;



Основные вспомогательные функции даны, теперь перейдем непосредственно к описанию авторизаций и аутентифиукации, но сначало  расскажу об особенностях работы в сниффере.

После запуска на отлавливание запросов/ответов, он будет фиксировать всю вашу активность в сети, т.е. работу вашего браузера,аси,торрент-трекера.
Внизу имеются вкладки, нам интересны:
-Header - двойное окно показывающая запрос от программы(например браузера IE) - слева и ответ сервера - справа;
-Response Content - html-текст который возвращает нам сервер на наш запрос;
-Post Data - отображает данные передаваемые наше программой при вызове метода Post(в данном виде передается подавляющее число логин/паролей и сопутствующей информации при авторизации через браузер);
-Query String- отображает альтернативный(методу Post Data) метод передачи данных об авторизации, через окно браузера;
-Raw Stream - окно паказывающая полный запрос программы к серверу, полезен при отладке.

Теперь переходим к авторизации и аутентификации.

3.  Авторизация на сайтах методом добавления в url , списка данных необходимых для авторизации, данный способ применим на подавляющем кол-ве серверов, исключения не сертифицированные https серверы, ну и еще какие-нибудь :P.

Добавление происходит,через специальный разделитель - ? добавляемый в конец нашего url, если он уже там есть, мы ни чего не добавляем.
В данном примере мы будем авторизовываться на сайте "в контакте", так как я находил в интернете не один пост на счет етого.
Теперь добавим разделитель и наш url будет выглядеть так:
http://vkontakte.ru/login.php?
Теперь после разделителя нужно добавить данные для авторизации, для этого я зарегистрировался на сайте, вот параметры:
Код

Логин : [email protected]
Пароль : 1234567

Но, что же подставлять, какие данные, в стать приведенной выше описывался метод, как узнать что передается, но у нас же есть сниффер предоставим все ему.
Для этого в форме регистрации на сайте в контакте вбейте приведенные выше данные и нажмите "вход"
В сниффере сразу отобразятся все запросы/ответы межу серваком и браузером.
В столбце Method - написан метод запроса к серверу(в данном примере Post), значит будем использовать его, потом url к  которому пошел запрос(наш http://vkontakte.ru/login.php?), так как метод был Post, то все данные передаваемые с запросом находятся во вкладке Post Data, но перейдя на нее мы ни чего не увидим.Почему? Все дело в том что данные передаются по url обозначенному в методе action если разбирать html-код страницы, ну тогда глянем, и вот что мы имеем:
Код

form method="post" - метод передачи
action="http://login.vk.com/" - url запроса к серверу

Следовательно данные передавались с ним, нажав на данный url и перейдя во вкладку Post Data, мы увидим нужные нам данные которые пересылаются вместе с запросом, теперьо нажимаем правой кнопкой мыши на один из параметров и в сплявающем меню нажмем "View Row Data", откроется блокнот с представленными нам в нужном виде данными, они выглядят так:
Код

act=login&success_url=&fail_url=&try_to_login=1&to=&vk=&[email protected]&pass=1234567&expire=

Теперь добавляем,это просто в конец нашего первоначально url(по  хорошему метод передачи и url запроса смотрится в коде страницы), но мы будем переходить по http://vkontakte.ru/login.php, а не описанному в action="http://login.vk.com/", просто потому, что и так проходит авторизация, но правильно брать url из action.
И финальный вид нашего url будет:
Код

http://vkontakte.ru/login.php?act=login&success_url=&fail_url=&try_to_login=1&to=&vk=&[email protected]&pass=1234567&expire=


Теперь напишу функцию которая авторизуется по данному url с данными:
Код

function GETURL2HTML(url : string;param : Ansistring ;method : string) : AnsiSTRING;//Получение страницы по url
var
  FHost,FScript : string;
  hInternet,hConnect,hRequest : Pointer;
  dwBytesRead,I,L : Cardinal;
  Flags_connection,Flags_Request : Cardinal;
begin
  result := '';

  fHost := GetHostName(url);
  fScript := GetScriptName(url,fHost);
  if Param <> '' then
    if fScript[Length(fScript)] = '?' then
      fScript := fScript + param
    else
      fScript := fScript + '?' + param;

  //Устанавливаем флаги
  SetFlags(url,Flags_connection,Flags_Request);
  //Инициализируем WinInet
  hInternet := InternetOpen(PChar(Application.ExeName),INTERNET_OPEN_TYPE_PRECONFIG,Nil,Nil,0);
  if Assigned(hInternet) then
    begin
      //Открываем сессию
      hConnect := InternetConnect(hInternet,PChar(FHost),Flags_connection,nil,nil,INTERNET_SERVICE_HTTP,0,1);
      if Assigned(hConnect) then
        begin
          //Формируем запрос
          hRequest := HttpOpenRequest(hConnect,PChar(uppercase(method)),PChar(fScript),HTTP_VERSION,nil,Nil,Flags_Request,1);
          if Assigned(hRequest) then
            begin
              //Отправляем запрос
              I := 1;
              if HttpSendRequest(hRequest,nil,0,nil,0) then
                begin
                  repeat
                  DataAvailable(hRequest, L);//Получаем кол-во принимаемых данных
                  if L = 0 then break;
                  SetLength(result,L + I);
                  if InternetReadFile(hRequest,@result[I],sizeof(L),dwBytesRead) then//Получаем данные с сервера
                  else break;

                  inc(I,dwBytesRead);
                  until dwBytesRead = 0;
                  result[I] := #0;
                end;
            end;
            InternetCloseHandle(hRequest);
        end;
        InternetCloseHandle(hConnect);
    end;
    InternetCloseHandle(hInternet);
end;


Здесь мы получаем html-код страницы,если мы авторизовались,
FHost - имя сервера;fScript - скрипт выполняемый при подключении(т.е. переход на страницу пользователяесли передаваеммые данные верня).
Данные метод действует и для http и для htpps.

4.  авторизация 2 методом, когда серверы требуют передавать данные авторизации не через конец url, а через "Post Data"- опции запроса. 
Вид представления жанных тот же ,что и в предыдущем примере:
Код

act=login&success_url=&fail_url=&try_to_login=1&to=&vk=&[email protected]&pass=1234567&expire=


Но теперь мы их будем передавать через опции запроса 
Код
HttpSendRequest
,
также отдельно стои сказать что вы должны передать в виде системной опции через туже функцию размер строки данных, она будет выглядить так:
Код

Type_Acess := 'Content-Type: application/x-www-form-urlencoded' + #13#10 +
                    'Content-Length:'+ inttostr(length(param)) ;

где 'Content-Length:'+ inttostr(length(param)) - и есть описание размерности строки.
А сами параметры передаются через 
Код
HttpSendRequest
, в виде :
Код

HttpSendRequest(hRequest,PChar(Type_Acess),length(Type_Acess),PChar(param),length(param))


ГЛАВНОЕ ЧТО НЕ ЗАБУДЬТЕ ПЕРЕМЕННАЯ PARAM ДОЛЖНА БЫТЬ ТИПА ANSISTRING ИЛИ utf8STRING, ТАК КАК HttpSendRequest - ПЕРЕДАЕТ PAnsiChar - из-за чего будут проблемы с кодировкой если использовать обычную string, так по крайней мере в Delphi 2009.

Привожу весь листинг функции авторизации :
Код

function GETURL2HTML(url : string;param : Ansistring ;method : string) : AnsiSTRING;//Получение страницы по url
var
  FHost,FScript : string;
  hInternet,hConnect,hRequest : Pointer;
  dwBytesRead,I,L : Cardinal;
  Flags_connection,Flags_Request : Cardinal;
  Type_Acess : string;
begin
  result := '';

  Type_Acess := 'Content-Type: application/x-www-form-urlencoded' + #13#10 +
                    'Content-Length:'+ inttostr(length(param)) ;
  fHost := GetHostName(url);
  fScript := GetScriptName(url,fHost);

  //Устанавливаем флаги
  SetFlags(url,Flags_connection,Flags_Request);
  //Инициализируем WinInet
  hInternet := InternetOpen(PChar(Application.ExeName),INTERNET_OPEN_TYPE_PRECONFIG,Nil,Nil,0);
  if Assigned(hInternet) then
    begin
      //Открываем сессию
      hConnect := InternetConnect(hInternet,PChar(FHost),Flags_connection,nil,nil,INTERNET_SERVICE_HTTP,0,1);
      if Assigned(hConnect) then
        begin
          //Формируем запрос
          hRequest := HttpOpenRequest(hConnect,PChar(uppercase(method)),PChar(fScript),HTTP_VERSION,nil,Nil,Flags_Request,1);
          if Assigned(hRequest) then
            begin
              //Отправляем запрос
              I := 1;
              if HttpSendRequest(hRequest,PChar(Type_Acess),length(Type_Acess),PChar(param),length(param))  then
                begin
                  repeat
                  DataAvailable(hRequest, L);//Получаем кол-во принимаемых данных
                  if L = 0 then break;
                  SetLength(result,L + I);
                  if InternetReadFile(hRequest,@result[I],sizeof(L),dwBytesRead) then//Получаем данные с сервера
                  else break;

                  inc(I,dwBytesRead);
                  until dwBytesRead = 0;
                  result[I] := #0;
                end;
            end;
            InternetCloseHandle(hRequest);
        end;
        InternetCloseHandle(hConnect);
    end;
    InternetCloseHandle(hInternet);
end;

Автор: Brausman 22.10.2009, 19:39
5.  Теперь давайте чучуть отклонимся от темы и рассмотрим такой пример, что после авторизации, редирект(перенаправление) не происходит, это случется в основном если приходит к нам скрипт и внутри него ссылка куда переходить, по такому методу идет авторизация на yahoo.com.
Вот логин и пароль для тестирования:
Логин: [email protected]
Пароль : 1234567

Делаем, что и в предыдущем примере, сначала через браузер, потом исследуем все в сниффере, мы будем передавать данные как и в первом случае через дописывания в url.
Привожу листинг функции:
Код

function GETURL2HTML(url : string;param : Ansistring ;method : string) : AnsiSTRING;//Получение страницы по url
label 10;
var
  FHost,FScript : string;
  hInternet,hConnect,hRequest : Pointer;
  dwBytesRead,I,L : Cardinal;
  Flags_connection,Flags_Request : Cardinal;
  Type_Acess : string;
begin
  result := '';

  fHost := GetHostName(url);
  fScript := GetScriptName(url,fHost);
  if Param <> '' then
    if fScript[Length(fScript)] = '?' then
      fScript := fScript + param
    else
      fScript := fScript + '?' + param;

  //Устанавливаем флаги
  SetFlags(url,Flags_connection,Flags_Request);
  //Инициализируем WinInet
  hInternet := InternetOpen(PChar(Application.ExeName),INTERNET_OPEN_TYPE_PRECONFIG,Nil,Nil,0);
  if Assigned(hInternet) then
    begin
      //Открываем сессию
      hConnect := InternetConnect(hInternet,PChar(FHost),Flags_connection,nil,nil,INTERNET_SERVICE_HTTP,0,1);
      if Assigned(hConnect) then
        begin
          //Формируем запрос
          hRequest := HttpOpenRequest(hConnect,PChar(uppercase(method)),PChar(fScript),HTTP_VERSION,nil,Nil,Flags_Request,1);
          if Assigned(hRequest) then
            begin
10:
              //Отправляем запрос
              I := 1;
              if HttpSendRequest(hRequest,{PChar(Type_Acess)}nil,{length(Type_Acess)}0,{PChar(param)}nil,{length(param)}0)  then
                begin
                  repeat
                  DataAvailable(hRequest, L);//Получаем кол-во принимаемых данных
                  if L = 0 then break;
                  SetLength(result,L + I);
                  if InternetReadFile(hRequest,@result[I],sizeof(L),dwBytesRead) then//Получаем данные с сервера
                  else break;

                  inc(I,dwBytesRead);
                  until dwBytesRead = 0;
                  result[I] := #0;
                end;
            end;
            InternetCloseHandle(hRequest);
        end;

        if pos('window.location.replace("',result) > 0 then
          begin
            url := 'http://ru.yahoo.com/'; //Ест я сам тут кинул по идее можно прям от туда тащить из результа
            fHost := GetHostName(url);
            fScript := GetScriptName(url,fHost);
            //Устанавливаем флаги
            SetFlags(url,Flags_connection,Flags_Request);
            //Если не через редирект то методом гет заходим
            hConnect := InternetConnect(hInternet,PChar(fHost),Flags_connection,nil,nil,INTERNET_SERVICE_HTTP,0,1);
            if Assigned(hConnect) then
              begin
                //Формируем запрос
                hRequest := HttpOpenRequest(hConnect,PChar(uppercase('GET')),PChar(fScript),HTTP_VERSION,nil,Nil,Flags_Request,1);
                if Assigned(hRequest) then
                  begin
                    result := '';
                    goto 10;
                  end;
              end;
          end;
        InternetCloseHandle(hConnect);
    end;
    InternetCloseHandle(hInternet);
end;

Теперь поясняю после запроса метода POST, мы получает ответ от сервера в виде:
Код

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script language="JavaScript">
<!--
window.location.replace("http://my.yahoo.com");
// -->
</script>
<meta http-equiv="Refresh" content="0; url=http://my.yahoo.com">
</head>
<body>
If you are seeing this page, your browser settings prevent you
from automatically redirecting to a new URL.
<p>
Please <a href="http://my.yahoo.com">click here</a> to continue.
</body>
</html>


Так как мы не указывали в параметрах запроса что мы из России:
Код

Referer:https://login.yahoo.com/config/login_verify2?.src=www&.intl=ru&.done=http://ru.yahoo.com/
Accept-Language:ru

То нам вернули ссылку на англоязычный сервис 
Код
http://my.yahoo.com
, но главное вернули значит мы все сделаи правильно и потом методом GET - основной метод переходов, переходим на наш ru.yahoo.com)))? вот в принципе и все на этот счет, идем дальше.


Примечание:

У серверов с не подтвержденным сертификатом(когда браузер ругается и предлогает не заходить на данный сервер), имеется проблема, если не получается к нему присоединится 12003 - ошибка, то есть два выхода:
1) У некоторых серверов есть семитричные url, только на обычном http, т.е. можно по тупому взять и вместо https//:блаблабла написать http//: и авторизоваться через него(у моего провайдера нета так у меня и получилось)
2)И более верный просто вместо имени подставиь IP сервера,его можно узнать когда сделаете запрос через браузер к этому серверу и в сниффере на вкладке "Raw Stream" - над текстом будет его IP.

6.  Ну и наконец мы подошли до аутетификации я решил взять и совместить 2 и 3 вопос статьи, так как отличий я не вижу, а коментарии дам одни.

Щас разберем пример, когда сервер по https(хотя без разницы http или https), требует сертификат и также авторизацию через системное окно Windows и к тому сертификат не проверенный(это бывает когда создатели сертификата не хотят платить Microsoft за то чтоб он зарегистрировал их сертификат в базе данных сертификатов Microsoft). К сожалению тестовый пример я дать не могу так как это конфиденциальная информация предприятия, так что поверьте мне наслово:P.


Как говорилось выше в примечании, будем использовать IP а не имя из url'а.

Теперь всьтает вопрос как программно добавить сертификат в запрос, для этого надо получить указатель на него в хранилище сертификатов вашего комп. И вот как это делается.
Вы не сможите найти сертификат нужный вам без его идентификационного имени в хранилище сертификатов( по буржуйски Subject),для этого я прилогаю к статье небольшой проект который в тексстовом формате может выводит все сертификаты которые имеются в хранилищах сертификатов вашего компа.Я сказал хранилищах? Да я не оговорился их не 1, а 3, а с помощью нас программистов их может быть 4, и у них есть свои уникальные названия :
//MY - для хранения сертификатов отдельного пользователя
//СА - от Certification Authority - для хранения сертификатов центров сертификации
//ROOT - для хранения корневых сертификатов
//А также тан называемое хранилище колекции сертификатов создаваемое исключительно программистом под себя, как назовете так и будет.

Теперь вам необходимо подключить к проекту .pas - файл для работы с сертификатами - wcrypt2.pas, я его также приложил к статье отдельно, стоит упомянуть, что он не до конца доработат, многих констант ошибок и некоторых функций для работы с сертификатами там попросту нет, что мне надо было я дописал, так что я предупредил.

Также отмечу, что пока вы не авторизуетесь на сервере через браузер, сертификат не добавится не в одно из хранилищ и вы его попросту не найдете, а метод через путь до сертификата на компе, когда он лежит файлом я рассматривать не буду. По умолчанию данные сертификаты добавляются в MY хранилище


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

//Функция нахождения сертификата
function FindCertificate( Subject : string; CertStore : string ) : PCCERT_CONTEXT;
var
    prov: HCRYPTPROV;
    store: HCERTSTORE;
    stor: PChar;
    subj: PWideChar;
    encType : DWORD;
    error : string;
begin

result := nil;

CertStore := uppercase(CertStore);//переводим в верхний регистр

encType := PKCS_7_ASN_ENCODING or X509_ASN_ENCODING;//виды шифрования

//Проверяем криптопровайдера на всекий случай можно и без этого
if not CryptAcquireContext(@prov, nil, nil, PROV_RSA_FULL, 0)
then
    begin
      case int64(GetLastError) of
        ERROR_INVALID_PARAMETER: error := 'ERROR_INVALID_PARAMETER';
        ERROR_NOT_ENOUGH_MEMORY: error := 'ERROR_NOT_ENOUGH_MEMORY';
        NTE_BAD_FLAGS: error := 'NTE_BAD_FLAGS';
        NTE_BAD_KEYSET: error := 'NTE_BAD_KEYSET';
        NTE_BAD_KEYSET_PARAM: error := 'NTE_BAD_KEYSET_PARAM';
        NTE_BAD_PROV_TYPE: error := 'NTE_BAD_PROV_TYPE';
        NTE_BAD_SIGNATURE: error := 'NTE_BAD_SIGNATURE';
        NTE_EXISTS: error := 'NTE_EXISTS';
        NTE_KEYSET_ENTRY_BAD: error := 'NTE_KEYSET_ENTRY_BAD';
        NTE_KEYSET_NOT_DEF: error := 'NTE_KEYSET_NOT_DEF';
        NTE_NO_MEMORY: error := 'NTE_NO_MEMORY';
        NTE_PROV_DLL_NOT_FOUND: error := 'NTE_PROV_DLL_NOT_FOUND';
        NTE_PROV_TYPE_ENTRY_BAD: error := 'NTE_PROV_TYPE_ENTRY_BAD';
        NTE_PROV_TYPE_NO_MATCH: error := 'NTE_PROV_TYPE_NO_MATCH';
        NTE_PROV_TYPE_NOT_DEF: error := 'NTE_PROV_TYPE_NOT_DEF';
        NTE_PROVIDER_DLL_FAIL: error := 'NTE_PROVIDER_DLL_FAIL';
        NTE_SIGNATURE_FILE_BAD: error := 'NTE_SIGNATURE_FILE_BAD';
      else error := 'Не известная ошибка';
      end;
      MessageDlg('Ошибка создания контейнера: ' + error, mtError, [mbOK], 0);
      exit;
    end;

stor := StrAlloc(length(CertStore) + 1);//выделяем память под строку
StrPCopy(stor, CertStore);//копируем
store := CertOpenSystemStore(prov, stor);//Открываем хранилище сертификатов
StrDispose(stor);//Освобождаем память
if store = nil then
   begin
    MessageDlg('Не можем открыть хранилище сертификатов', mtError, [mbOK], 0);
    CertCloseStore(store, 0);//освобождаем память
    CryptReleaseContext(prov, 0);//освобождаем память
    result := nil;
    exit;
   end;
GetMem(subj, 2 * length(Subject) + 1);//выделяем память
StringToWideChar(Subject, subj, 2 * length(Subject) + 1);//Переводим
result := CertFindCertificateInStore(store, encType, 0, CERT_FIND_SUBJECT_STR,subj, nil);//Ищем по нашему Subject нужный нам сертификат и передаем на result его указатель
FreeMem(subj, 2 * length(Subject) + 1);//Освобождаем память
if result = nil then
   begin
    MessageDlg('Сертификат не найден', mtError, [mbOK], 0);
    CertCloseStore(store, 0);//освобождаем память
    CryptReleaseContext(prov, 0);//освобождаем память
    exit;
   end;
end;


В коментариях все написано, так что пояснять ни чего не буду.

Ну а теперь когда мы получили указатель на сертификать можно аутентифицироваться, в опции к запросу добавляется сертификат и передается запросом.А авторизация системного окна проходит путем, подставления логин/пароля в InternetConnect:
Код

hConnect := InternetConnect(hInternet,PChar('195.161.126.16'),8443,PChar(login){наш логин в системном окне},PChar(password){наш пароль в системном окне},INTERNET_SERVICE_HTTP,0,1);


Ну а теперь привожу листинк функции полностью :
Код

function Authentication_and_SysAuthorization(url,login,password : string) : ansistring;
const
  INTERNET_OPTION_CLIENT_CERT_CONTEXT = 84;//Стандартный флаг для отправки запроса с ручным построением аутентификацие
label 10;
var
  FHost,FScript : string;
  hInternet,hConnect,hRequest : Pointer;
  dwBytesRead,I,L : Cardinal;
  Flags_connection,Flags_Request : Cardinal;
  dwError, dwErrorCode,flags_security : DWORD;
  data : pointer;
  Sertificat : PCCERT_CONTEXT;
begin
  result := '';
  if (login = '') or (password = '') then exit;//Выходи если не задано логин/пароля для авторизации

  fHost := GetHostName(url);
  fScript := GetScriptName(url,fHost);

  //Устанавливаем флаги в данном случае мы не используем стандартный https порт - 443 и по этому Flags_connection - нам не подходит
  SetFlags(url,Flags_connection,Flags_Request);
  //Инициализируем WinInet
  hInternet := InternetOpen(PChar(Application.ExeName),INTERNET_OPEN_TYPE_PRECONFIG,Nil,Nil,0);
  if Assigned(hInternet) then
    begin
      //Открываем сессию
      hConnect := InternetConnect(hInternet,PChar('195.161.126.16'),8443,PChar(login){наш логин в системном окне},PChar(password){наш пароль в системном окне},INTERNET_SERVICE_HTTP,0,1);
      if Assigned(hConnect) then
        begin
          //Формируем запрос
          hRequest := HttpOpenRequest(hConnect,PChar('GET'),PChar(fScript),HTTP_VERSION,nil,Nil,Flags_Request ,1);
          if Assigned(hRequest) then
            begin
10:
              //Отправляем запрос
              I := 1;
              if HttpSendRequest(hRequest,{PChar(Type_Acess)}nil,{length(Type_Acess)}0,{PChar(param)}nil,{length(param)}0)  then
                begin
                  repeat
                  DataAvailable(hRequest, L);//Получаем кол-во принимаемых данных
                  if L = 0 then break;
                  SetLength(result,L + I);
                  if InternetReadFile(hRequest,@result[I],sizeof(L),dwBytesRead) then//Получаем данные с сервера и заносим их в результ
                  else break;

                  inc(I,dwBytesRead);//Обновляем величину переменной
                  until dwBytesRead = 0;
                  result[I] := #0;
                end;
            end;
            //опредиляем код ошибки, нам нужен 12044 - код не прохождения аутентификации
            dwErrorCode := GetLastError;
            //Если код 12044, то добавляем в запрос сертификат из хранилища для прохождения аутентификации
            if  dwErrorCode = ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED then
              begin
                //Обрабатываем программное подставление сертификата
                //Возможны 4 варианта хранилищ сертификатов
                //MY - для хранения сертификатов отдельного пользователя
                //СА - от Certification Authority - для хранения сертификатов центров сертификации
                //ROOT - для хранения корневых сертификатов
                //А также тан называемое хранилище колекции сертификатов создаваемое исключительно программистом под себя
                //Находим наш сертификат по умолчанию они сохраняются всегда в MY после того как вы откроете вашу страницу любым из браузеров
                Sertificat := FindCertificate('******************************Nikolaevich','my');
                //Добавляем в опции передаваемые с запросом
                InternetSetOptionw(hRequest,INTERNET_OPTION_CLIENT_CERT_CONTEXT,Sertificat,SIZEOF(cert_context));
                //также в опции запроса добавим флаги,
                //как иногда у меня был глюк что они не передавались когда описывались в форме HttpOpenRequest
                flags_security := SECURITY_FLAG_IGNORE_UNKNOWN_CA or
                                  INTERNET_FLAG_IGNORE_CERT_CN_INVALID or
                                  INTERNET_FLAG_IGNORE_CERT_DATE_INVALID or INTERNET_FLAG_NO_AUTH;
                //Добавляем в опции передаваемые с запросом
                InternetSetOptionw(hRequest,INTERNET_OPTION_SECURITY_FLAGS,@flags_security,SIZEOF(DWord));
                //можно передавать пароль и логин здесь кому как интересно, но мне кажется в InternetConnection легче :-)
                //InternetSetOption(hRequest, INTERNET_OPTION_USERNAME, PChar(Login), length(Login));
                //InternetSetOption(hRequest, INTERNET_OPTION_PASSWORD, PChar(Password), length(Password));
                //Освобождаем память от сертификата
                CertFreeCertificateContext(Sertificat);
                //Переходим опять на запрос
                goto 10;
                //Тут закоментен диалог вывода на экран формы выбора сертификата если кому нужно)))
                //dwError := InternetErrorDlg(Form2.Handle, hRequest, dwErrorCode, FLAGS_ERROR_UI_FILTER_FOR_ERRORS or FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS or FLAGS_ERROR_UI_FLAGS_GENERATE_DATA,data);
              end;
            InternetCloseHandle(hRequest);
        end;
        InternetCloseHandle(hConnect);
    end;
    InternetCloseHandle(hInternet);
end;



Код пояснять не буду, так как в коментариях и описании выше все становится ясно.

В конце хочу отметить, что если возвращается код в виде абрыкадабры, то это означает что у сервера ответ в виде кодировки UTF8, смените AnsiString->UTF8string или обратно.

Надеюсь данная статья вам поможет, думаю мое полутора недельное исследование данного вопроса вам поможет,а мне репутацию увеличитsmile

Спасибо всем кто меня слушал, с уважением Анатолий "Anatol_rus" Федоров

Автор: Brausman 22.10.2009, 19:55
Также прикрепляю проект на Delphi 2009 и надеюсь, что данную статью прикрепят.

Автор: darkmamba 23.10.2009, 12:47
Статья хорошая, НО хотелось бы побольше информации по авторизации в окне виндоус... у меня стоит Д7 скачал компонент v1.5 а там функции InternetConnect() нету =) подскажите где найти компонент для Д7, д2009 не предлагать  smile 

Автор: Brausman 23.10.2009, 20:35
Цитата(darkmamba @ 23.10.2009,  12:47)
Статья хорошая, НО хотелось бы побольше информации по авторизации в окне виндоус... у меня стоит Д7 скачал компонент v1.5 а там функции InternetConnect() нету =) подскажите где найти компонент для Д7, д2009 не предлагать  smile

InternetConnect - это стандартная Win 32 API функция, просто подключите
Код

uses WinInet;


И все будет.
По поводу системного окна описано в пункте 6 моей статьи, вот цитирую:
Код

А авторизация системного окна проходит путем, подставления логин/пароля в InternetConnect:
hConnect := InternetConnect(hInternet,PChar('195.161.126.16'),8443,PChar(login){наш логин в системном окне},PChar(password){наш пароль в системном окне},INTERNET_SERVICE_HTTP,0,1);


Автор: darkmamba 24.10.2009, 22:38
Все понял но вылетают эти ошибки при InternetOpen и InternetConnect 00CC0008 и 00CC0004

а вот код 

Код

procedure TForm1.Button1Click(Sender: TObject);
var
  pConnect, hInet : Pointer;
begin
hInet := InternetOpen(PChar(Application.ExeName),INTERNET_OPEN_TYPE_PRECONFIG,0,0,0);
pConnect := InternetConnect(hInet, PChar('212.33.232.164'), 80, PChar('123123'), PChar('123123'), INTERNET_SERVICE_HTTP, 0, 1);
end;

Автор: Brausman 25.10.2009, 00:47
Цитата(darkmamba @ 24.10.2009,  22:38)
Все понял но вылетают эти ошибки при InternetOpen и InternetConnect 00CC0008 и 00CC0004

а вот код 

Код

procedure TForm1.Button1Click(Sender: TObject);
var
  pConnect, hInet : Pointer;
begin
hInet := InternetOpen(PChar(Application.ExeName),INTERNET_OPEN_TYPE_PRECONFIG,0,0,0);
pConnect := InternetConnect(hInet, PChar('212.33.232.164'), 80, PChar('123123'), PChar('123123'), INTERNET_SERVICE_HTTP, 0, 1);
end;

А Запрос то к серверу кто будет делать? он делается функциями httpSendRequest
То что вы привели, вы просто назначали имя интернет сессии с которой сервер будет общаться и назвали имя сервера больше ни чего
Код

if Assigned(pConnect) then
//Формируем запрос
          hRequest := HttpOpenRequest(hConnect,PChar(uppercase(method)),PChar(fScript),HTTP_VERSION,nil,Nil,Flags_Request,1);
          if Assigned(hRequest) then
            begin
              //Отправляем запрос
              I := 1;
              if HttpSendRequest(hRequest,nil,0,nil,0) then
                begin
                   repeat
                  DataAvailable(hRequest, L);//Получаем кол-во принимаемых данных
                  if L = 0 then break;
                  SetLength(result,L + I);
                  if InternetReadFile(hRequest,@result[I],sizeof(L),dwBytesRead) then//Получаем данные с сервера и заносим их в результ
                  else break;
                  inc(I,dwBytesRead);//Обновляем величину переменной
                  until dwBytesRead = 0;
                  result[I] := #0;
                end;
            end;
end;


В статье же все написано и ссылки хорошие доны на объяснение функций, а если ошиблки не понятные лезут пользуйтесь функцией GetLastError;
method - то GET или Post, в зависимости от того что вы делаете
fScript - куда вы переходите по серверу
Flags_Request - флаги которые вы задали для данного запроса к серверу

Автор: MetalFan 25.10.2009, 10:01
спасибо. кое с чем не сталкивался (с сертификатами). хотя тут все рассмотрено поверхностно и в итоге я все равно толком не понял что почему и как (касательно сертификатов).
Цитата(Brausman @  22.10.2009,  19:24 Найти цитируемый пост)
Автор предупреждает, что не будет вступать в споры по поводу оптимизации кода, данная статья не про это

тем не менее - ужасное оформление кода (он просто местами не читаем) и приемы программирования (goto...буэээ, ненужное дублирование кода).
в общем использовать части приведенного кода в своих проектах общественности крайне не рекомендую.
очень страдает грамматика. у автора нет хотя бы ворда, чтобы текст статьи подкорректировать?

а в целом, если причесать, то весьма познавательно для тех, кто с этой темой сталкивается впервые.

Автор: darkmamba 25.10.2009, 16:23
Вобщем я запутался, помогите разгрести кучу.

Код

procedure TForm1.Button1Click(Sender: TObject);
var
  hRequest, hConnect, hInet : Pointer;
  BufferLength, Reserved, ReadedSize, Size : cardinal;
  Buff : ANSIString;
begin
hInet := InternetOpen(PChar('Adios!'),INTERNET_OPEN_TYPE_PRECONFIG,0,0,0);
hConnect := InternetConnect(hInet, PChar('212.33.232.164'), 80, PChar('123123'),   //212.33.232.164
            PChar('123123'), INTERNET_SERVICE_HTTP, 0, 1);
hRequest := HttpOpenRequest(hConnect, 0,pchar('www.l2r.ru/admin'),
            HTTP_VERSION, 0, 0, 1, 1); - Здесь вылазит 122 ошибка
HttpSendRequest(hRequest, 0, 0, 0, 0); - Здесь 12150
 MessageBox(0, pchar(IntToStr(GetLastError)), pchar('GetLastError'),0);
if InternetQueryDataAvailable(hRequest, size, 0, 0) then messagebox(0,pchar(IntToStr(Size)),pchar('InternetQueryDataAvailable'),0);
SetLength(Buff, 1024);
InternetReadFile(hRequest, @Buff[1], size, ReadedSize);
showmessage(buff); // это просто для наглядности..


Вылазят какието ошибки, природу понять немогу. Вроде все делаю так как написано, а не работает хз почему.

Update
Непонятным образом ошибка 12150 испарилась!!! 122 попрежнему вылетает но видимо не фатально, но разобратся бы хотелось всеравно!

Шас вылазит типа HTTPProtocolException 403 Forbiden или по-русски нет доступа, через браузер вылазит 401 Необходима авторизация... тупик... может какой флаг надо поставить ???

Автор: Brausman 25.10.2009, 19:55
Цитата(MetalFan @ 25.10.2009,  10:01)
спасибо. кое с чем не сталкивался (с сертификатами). хотя тут все рассмотрено поверхностно и в итоге я все равно толком не понял что почему и как (касательно сертификатов).
Цитата(Brausman @  22.10.2009,  19:24 Найти цитируемый пост)
Автор предупреждает, что не будет вступать в споры по поводу оптимизации кода, данная статья не про это

тем не менее - ужасное оформление кода (он просто местами не читаем) и приемы программирования (goto...буэээ, ненужное дублирование кода).
в общем использовать части приведенного кода в своих проектах общественности крайне не рекомендую.
очень страдает грамматика. у автора нет хотя бы ворда, чтобы текст статьи подкорректировать?

а в целом, если причесать, то весьма познавательно для тех, кто с этой темой сталкивается впервые.

Спасибо за критику учту, но давайте по порядку:
1. На счет сертификатов, в статье написано, что прилагается программка моя через ,которую можно узнать Subject, своего сертификата, потом это полное subject, подставляешь в мою функцию FindCertificate, и далее указатель передаешь в InternetSetOption, вот в принципе и все и ни чего сложного smile
2. На счет грамматике русской - ет да признаю она у меня плоха, но какое оно имеет отношение к статье?
3. Я писал что код не претендует на оптимальность, нро все же объясните почему вам так не нравится переход goto,там ни какого дубляжа нет, так как в любом случае надо вызывать функцию HttpSendRequest?
4. В чем проявляется плохая читаемость кода?? Если не сложно приведите ссылку или напишите фрагмент  хорошо читаемого кода.
5. Ну и скажите что причесывать, чтоб можно было привести статью к завершенному виду, так как опыта в написании статей у меня не было.

Это конечно начался флуд но все равно, интересно узнать на мои вопросы ответы.

Автор: darkmamba 25.10.2009, 20:07
Ура, запрос отправился нормальный!!!! Относительно! Неотправляются пароль и логин в базе64....

Странно, но почемуто отправляется 2 запроса сразу, в 1ом нету логина и пароля во втором есть, это че прикол такой ?

Автор: Brausman 25.10.2009, 20:14
Цитата(darkmamba @ 25.10.2009,  16:23)
Вобщем я запутался, помогите разгрести кучу.

Код

procedure TForm1.Button1Click(Sender: TObject);
var
  hRequest, hConnect, hInet : Pointer;
  BufferLength, Reserved, ReadedSize, Size : cardinal;
  Buff : ANSIString;
begin
hInet := InternetOpen(PChar('Adios!'),INTERNET_OPEN_TYPE_PRECONFIG,0,0,0);
hConnect := InternetConnect(hInet, PChar('212.33.232.164'), 80, PChar('123123'),   //212.33.232.164
            PChar('123123'), INTERNET_SERVICE_HTTP, 0, 1);
hRequest := HttpOpenRequest(hConnect, 0,pchar('www.l2r.ru/admin'),
            HTTP_VERSION, 0, 0, 1, 1); - Здесь вылазит 122 ошибка
HttpSendRequest(hRequest, 0, 0, 0, 0); - Здесь 12150
 MessageBox(0, pchar(IntToStr(GetLastError)), pchar('GetLastError'),0);
if InternetQueryDataAvailable(hRequest, size, 0, 0) then messagebox(0,pchar(IntToStr(Size)),pchar('InternetQueryDataAvailable'),0);
SetLength(Buff, 1024);
InternetReadFile(hRequest, @Buff[1], size, ReadedSize);
showmessage(buff); // это просто для наглядности..


Вылазят какието ошибки, природу понять немогу. Вроде все делаю так как написано, а не работает хз почему.

Update
Непонятным образом ошибка 12150 испарилась!!! 122 попрежнему вылетает но видимо не фатально, но разобратся бы хотелось всеравно!

Шас вылазит типа HTTPProtocolException 403 Forbiden или по-русски нет доступа, через браузер вылазит 401 Необходима авторизация... тупик... может какой флаг надо поставить ???

1.Обратите внимание что передается в HttpSendRequest вместо:
Код

HttpSendRequest(hRequest, 0, 0, 0, 0); - Здесь 12150

надо
Код

HttpSendRequest(hRequest, nil, 0, nil, 0); 

Это на первый взгляд,что я увидел
И еще вот ссылка на все ошибки winineta - http://support.microsoft.com/kb/193625
там ясно сказано,что передаваемый заголовок не может быть обнаружен

2.hRequest := HttpOpenRequest(hConnect, 0,pchar('www.l2r.ru/admin'),HTTP_VERSION, 0, 0, 1, 1); - Здесь вылазит 122 

если я правильно понимаю, то www.l2r.ru - это имя сервера, а в HttpOpenRequest передается не имя сервера, а скрипт который должен выполнится на нем, т.е. admin, потом после HTTP_VERSION должны идти не 0 , а nil , после nil(первая 1 - там должны стоять флаги запроса к серверу), в статье, это все подробным образом описано,
про флаги
Код

procedure SetFlags(url : string; out Flags_connection,Flags_Request : Cardinal);
begin
  //Оприделяем на https или http
  if pos('https',url) > 0 then
    begin
      Flags_connection := INTERNET_DEFAULT_HTTPS_PORT;
      Flags_Request := INTERNET_FLAG_RELOAD or INTERNET_FLAG_IGNORE_CERT_CN_INVALID or INTERNET_FLAG_NO_CACHE_WRITE or INTERNET_FLAG_SECURE or INTERNET_FLAG_PRAGMA_NOCACHE or INTERNET_FLAG_KEEP_CONNECTION;
    end
  else
    begin
      Flags_connection := INTERNET_DEFAULT_HTTP_PORT;
      Flags_Request := INTERNET_FLAG_RELOAD or INTERNET_FLAG_IGNORE_CERT_CN_INVALID or INTERNET_FLAG_NO_CACHE_WRITE or INTERNET_FLAG_PRAGMA_NOCACHE or INTERNET_FLAG_KEEP_CONNECTION;
    end;
end;

Где Flags_Request и подставляется в HttpOpenRequest, и в конечном виде она будет такой:
Код

HttpOpenRequest(hConnect, 0,pchar('admin'),HTTP_VERSION, nil,nil, Flags_Request, 1); 


и про скрипты:
Код


б) Идем дальше)), в функцию 
HttpOpenRequest
 передается параметр
lpszObjectName
 - он же скрипт, также берется из полного url, из
http://www.delphisources.ru/pages/faq/base/inet_win32_api_functions.html  скрипт будет 
pages/faq/base/inet_win32_api_functions.html ,для его вытаскивания служит следующая функция :

function GetScriptName( url,hostname : string) : string;
begin
  result := '';
  delete(url,1,pos(hostname,url) + length(hostname));
  result := url;
end;




3. 
Код

InternetOpen(PChar('Adios!'),INTERNET_OPEN_TYPE_PRECONFIG,0,0,0); 
- это у вас
а надо так
Код

InternetOpen(PChar('Adios!'),INTERNET_OPEN_TYPE_PRECONFIG,nil,nil,0);

 прежде чем задавать вопрос, посмотрите статью и только после того как не найдете там ответа на свой вопрос, пишите его здесь.

Автор: darkmamba 25.10.2009, 20:23
На самом деле это абсолютно рабочий код, можете поверить или проверить(просто я неуспел обновить еще тот пост)! Одно НО отправляется 2 запроса с разницей в доли секунды, это не есть хорошо.... пока что незнаю почему можете присоединится!

По поводу NIL , делфи конвертирует 0 в NILы где надо.....

Код

var
  hRequest, hConnect, hInet : Pointer;
  BufferLength, Reserved, ReadedSize, Size : cardinal;
  Buff : ANSIString;
  headers : string;
begin

hInet := InternetOpen(PChar('Голактико Вопасносте!'),INTERNET_OPEN_TYPE_PRECONFIG,0,0,0);

hConnect := InternetConnect(hInet, PChar('www.l2r.ru'), 80, PChar('123123'),   //212.33.232.164
            PChar('123123'), INTERNET_SERVICE_HTTP, 0, 1);

hRequest := HttpOpenRequest(hConnect, 0,pchar('/admin'),
            HTTP_VERSION, 0, 0,
            INTERNET_FLAG_NO_COOKIES+
            INTERNET_FLAG_KEEP_CONNECTION, 1);

HttpSendRequest(hRequest, 0, 0, 0, 0);
InternetQueryDataAvailable(hRequest, size, 0, 0);
SetLength(Buff, 1024);
InternetReadFile(hRequest, @Buff[1], size, ReadedSize);
showmessage(buff);

Автор: MetalFan 25.10.2009, 21:16
darkmamba, может стоить создать отдельную тему по своим повросам? твои эксперименты, имхо, хоть со статьей и связаны, но не являются ни ее обсуждением, ни продолжением.

Автор: MetalFan 25.10.2009, 21:35
Цитата(Brausman @  25.10.2009,  19:55 Найти цитируемый пост)
1. На счет сертификатов, в статье написано, что прилагается программка моя через ,которую можно узнать Subject, своего сертификата, потом это полное subject, подставляешь в мою функцию FindCertificate, и далее указатель передаешь в InternetSetOption, вот в принципе и все и ни чего сложного smile 
что значит "свой" сертификат? откуда он взялся? зачем он может понадобится серверу? код то я посмотрел, что он делает в целом ясно. но вот предпосылок к его использованию я не понял.

Цитата(Brausman @  25.10.2009,  19:55 Найти цитируемый пост)
2. На счет грамматике русской - ет да признаю она у меня плоха, но какое оно имеет отношение к статье?
такое, что материал на порядок хуже воспринимается с грамматическими и синтаксическими ошибками, чем без них.

Цитата(Brausman @  25.10.2009,  19:55 Найти цитируемый пост)
3. Я писал что код не претендует на оптимальность, нро все же объясните почему вам так не нравится переход goto,там ни какого дубляжа нет, так как в любом случае надо вызывать функцию HttpSendRequest? 

goto усложняет восприятие кода, запутывает его. лично я против использования этого атавизма. но не будем затевать здесь холивар)
дубляж. в функции FindCertificate два практически одинаковых блока с exit'ами. мелочь, но на глаза попалась.
так же нет ни одного блока try..finally...

Цитата(Brausman @  25.10.2009,  19:55 Найти цитируемый пост)
4. В чем проявляется плохая читаемость кода?? Если не сложно приведите ссылку или напишите фрагмент  хорошо читаемого кода. 

бросилось в глаза, что тело цикла repeat..until написано без отступа...
ну и таких мелких ляпов можно набрать еще несколько штук.
я не претендую на идеального оформителя кода, но можешь посмотреть пример http://forum.vingrad.ru/index.php?showtopic=186678.

Цитата(Brausman @  25.10.2009,  19:55 Найти цитируемый пост)
5. Ну и скажите что причесывать, чтоб можно было привести статью к завершенному виду, так как опыта в написании статей у меня не было. 

прогони текст статьи через ворд. хоть грамматику чуть поправишь)
ну и код переписать в более удобоваримый вид. имхо.
а вообще все конечно на твое усмотрение. кому надо, и так разберутся)

з.ы. ну и можно я думаю на "ты". мы же с вами культурные люди)

Автор: Brausman 25.10.2009, 23:37
В целом нарекания понятны, твою обертку над wininet видел,сделано не дурно, нет try ...finally.. так как делал просто примеры, без учета обработки всякого рода глюков.
На счет "своего" сертификата, это когда(я кстати с этим сам встретился 1 раз) тебе, например налоговая дает на руки индивидуальный сертификат для доступа в их базу данных по налогоплательщикам(ет из практики),сервер каждую сессию обращается к тебе сначала за подтверждением сертификата, а уж потом за логином/паролем, этот сертификат как раз через IE(или другой браузер) добавляется в хранилище "MY" сертификатов откуда я его и использую, по данной теме инфы в интернете вообще не нашел, так что посчитал правильным добавить его в статью.

Ну а статью на недели когда время будет поправлю.

Автор: Brausman 25.10.2009, 23:58
darkmamba, как можно быть таким не внимательным или вы статью не читали?????
Код

hRequest := HttpOpenRequest(hConnect, 0,pchar('/admin'),
HTTP_VERSION, 0, 0,
INTERNET_FLAG_NO_COOKIES+
INTERNET_FLAG_KEEP_CONNECTION, 1);

Скрип передается без "/" ,если у вас www.l2r.ru/admin, то скрипт будет adminбез "/"!!!
Код

hRequest := HttpOpenRequest(hConnect, 0,pchar('admin'),
            HTTP_VERSION, 0, 0,
            INTERNET_FLAG_NO_COOKIES+
            INTERNET_FLAG_KEEP_CONNECTION, 1);

 И проверьте метод передачи, я вижу у вас метод "GET", там точно этот метод??

Автор: MetalFan 26.10.2009, 11:45
Brausman, спасибо, про "свой" сертификат прояснилось) ни разу сам с таким не сталкивался, теперь буду знать. хотя эту тему можно осветить вообще отдельно.

в любом случае ты молодец, что решился написать такую полезную статью!
после небольшого "причесывания" цены ей не будет)
с почином, так держать!

Автор: Brausman 26.10.2009, 12:56
Цитата(MetalFan @ 26.10.2009,  11:45)
Brausman, спасибо, про "свой" сертификат прояснилось) ни разу сам с таким не сталкивался, теперь буду знать. хотя эту тему можно осветить вообще отдельно.

в любом случае ты молодец, что решился написать такую полезную статью!
после небольшого "причесывания" цены ей не будет)
с почином, так держать!

Спасибо, в принципе можно написать статью, как делать/регистрировать в хранилищах/использовать свои сертификаты тоже, хотя думаю такая статья отклика в массах не получит smile 

Автор: darkmamba 26.10.2009, 13:36
Цитата(Brausman @ 25.10.2009,  23:58)
darkmamba, как можно быть таким не внимательным или вы статью не читали?????
Код

hRequest := HttpOpenRequest(hConnect, 0,pchar('/admin'),
HTTP_VERSION, 0, 0,
INTERNET_FLAG_NO_COOKIES+
INTERNET_FLAG_KEEP_CONNECTION, 1);

Скрип передается без "/" ,если у вас www.l2r.ru/admin, то скрипт будет adminбез "/"!!!
Код

hRequest := HttpOpenRequest(hConnect, 0,pchar('admin'),
            HTTP_VERSION, 0, 0,
            INTERNET_FLAG_NO_COOKIES+
            INTERNET_FLAG_KEEP_CONNECTION, 1);

 И проверьте метод передачи, я вижу у вас метод "GET", там точно этот метод??

метод GET, по дефолту выставляется если поставить 0 (mdsn).

В общем все работает, только отправляется по 2 запроса (одинаковых), только первый без аутенфикации (без пароля и логина), они приходят во втором с разницей в доли секунды.. т.е сразу же на ответ от сервера как я понимаю... почему не сразу - хз.

Код

15:40:00:421  0,016 s      GET     401     651       text/html  http://www.l2r.ru/admin               
GET /admin HTTP/1.1
User-Agent: Голактико Вопасносте!
Host: www.l2r.ru
Connection: Keep-Alive

15:40:00:437  0,015 s      GET     401     651       text/html  http://www.l2r.ru/admin               
GET /admin HTTP/1.1
User-Agent: Голактико Вопасносте!
Host: www.l2r.ru
Connection: Keep-Alive
Authorization: Basic TWluaWJ1a2E6MTIzMTIzMTIzMTIz


Можно сказать, что проблему решил, используя собственые хедеры, в которых сам кодирую пароль и логин в базе64, только вот есть ли разница между MTIzNDU2OjY1NDMyMQ== и MTIzNDU2OjY1NDMyMQ (это 123456:654321)? При раскодировке нету  smile 

Автор: Brausman 26.10.2009, 20:22
А что тут удивительного, если идет аутетификация то сервер ждет когда вы ему подсунете нужный сертификат(это первый GET), потом так как у нас включен редирект, он сразу (наш WinInet) посылает серверу запрос ответ авторизации(ваш закодированный логин/пароль) - это 2 GET.

А на счет пароля отсылаемые данные серверу должны быть идентичны.
И зачем кодировать самому, если через InternetConnection, логин/пароль сами кодируются WinInet'ом.

Автор: darkmamba 27.10.2009, 14:06
Чтобы не было лишнего запроса.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)