Program do logowania się na stronie

0

Witam wszystkich serdecznie :)

Otóż, mam stronę, do której chciałbym napisać program, przez który będę się logował. Strona ta jest stroną projektu w JIRA. I tu pojawia się moje pytanie - czy jest możliwe napisanie takiego programu? Chciałbym to zrobić w środowisku Borland Delphi. Szukałem na ten temat jakiś informacji, ale niestety nie udało mi się znaleźć za dużo.

Póki co mam formatkę, pola na login i hasło oraz przycisk, po naciśnięciu którego będę się łączył. Ale jakiego komponentu użyć do nawiązania połączenia?

2

Synapse, simpleTCP, indy albo wyrzeźbij sobie coś w WinAPI

0

@babubabu

A co polecasz najbardziej z podanych przez Ciebie rozwiązań?

0

To zależy co potrzebujesz. Poczytaj sobie na temat moich propozycji i dobierz najlepszą do tego co chcesz zrobić.

0

Jeśli się musisz posiłkować HTTPS i ewentualnie później potrzebować VCL i nie rzeźbić wszystkiego od zera. Do tego nie chcesz czekać zanim @kAzek pomoże z Indy, bo znowu ktoś dorwie 9tke i coś będzie nie działać jak w 10tce. To polecam Synapse.

Pod WinAPI szczerze polecam SimpleTCP. Tylko sobie musisz wtedy sam wszystko wyrzeźbić. Ale masz pełną kontrolę nad socketem TCP. I co najlepsze w razie potrzeby po HTTP możesz sobie łatwo w WinAPI napisać przyrostowe pobieranie pliku z tym komponentem. Gdy później będzie to potrzebne do czegoś. A wiadomo. Pod Synapse bez przerabiania źródeł się nie da. A Indy? Cóż, a jeśli @kAzek jest na wakacjach jeszcze? To wtedy będziesz się motał, bo kto inny tutaj Ci to ogarnie? ;P

Bo wróżbita maciej (celowa pisownia, bo mam brak szacunku dla oszustów) to tylko inkasuje słono za konsultacje na skajpaju, a z tarota nawinie Tobie pseudo bełkot i każe to zakodować z użyciem bałaganiarskich i dziwnych funkcji bazujących na silniku IE, których używają chyba tylko samobójcy i h4x0ry piszący "trojany", czyli na jedno wychodzi ;)

0

Najszybciej i najprościej (bo bez używania zewnętrznych komponentów / bibliotek) zrobisz to za pomocą Indy ale konkretnie nic nie można napisać nie wiedząc dokładnie o jaką stronę chodzi. Jedynie co mogę napisać to że prawdopodobnie musisz pobrać stronę GET (dlatego że mogą wtedy być ustawiane potrzebne ciasteczka) a później POST z danymi potrzebnymi do logowania. Jednak Indy jest taką trochę armatą na muchy i prawdopodobnie spokojnie mógłbyś to zrobić czym mniejszym ale trzeba konkretnie wiedzieć o co chodzi aby sensownie coś doradzić.

0

Aktualnie co chcę osiągnąć, to zalogować się na stronę mojego projektu JIRA poprzez program - wpisać login i hasło, nacisnąć przycisz "Połącz" i dostać wiadomość zwrotną "Połączono" :D.

Rozumiem, że wystarczy mi komponent IdTCPClient? Czy też do tego będzie potrzebny inny komponent?

0

Jak już Indy to korzystaj z komponentów do tego przeznaczonych wiec w tym przypadku IdHTTP.

0

@kAzek:

Czy oprócz IdHTTP będzie potrzebny jeszcze jakiś komponent? Np. do ciasteczek albo sesji?

Edit
Zastanawiam się jeszcze, czy nie będę potrzebował komponentu WebBrowser, bo po logowaniu chcę przechodzić na odpowiednią podstronę.

0

Nie wiem i teraz nie mam czasu się bawić w sprawdzanie jeżeli strona używa SSL (https) potrzebny będzie IdSSLIOHandlerSocketOpenSSL i biblioteki ssleay32dll i libeay32.dll (one z kolei w zależności od wersji używają msvcrX.dll) do zarządzania ciasteczkami wygodnie jest korzystać z IdCookieManager ale prawdopodobnie nie będziesz musiał tego robić (wszystko zrobi się "samo") a jeżeli byś chciał korzystać z gzip przyda się IdCompressorZLib.

Edit: WebBrowser? Do czego co chcesz konkretnie zrobić p zalogowaniu? Jeżeli chodzi tylko o pobranie czegoś ze strony to raczej nie chyba że strona korzysta z JavaScript i bez tego się nie obejdzie.

2

Z tego co pamiętam też używałem IdHTTP do tego w Delphi (do wywoływania serwisów HTTP).
Jeśli chodzi o sockety, to mamy 2014 rok i pora o nich zapomnieć.

Szukaj "REST Client Delphi".

Np:
http://www.redmine.org/projects/redmine/wiki/Rest_api_with_delphi

Tu przykład jak wykorzystać IdHTTP:
http://thundaxsoftware.blogspot.com/2014/07/delphi-rest-client-to-retrieve-flickr.html

Nowsze Delphi ma to wbudowane (gdyby niekoniecznie chodziło o D7):
http://docwiki.embarcadero.com/RADStudio/XE6/en/Tutorial:_Using_the_REST_Client_Library_to_Access_REST-based_Web_Services

http://blogs.embarcadero.com/amannarino/2013/11/09/using-the-new-rest-client-library-components-to-connect-to-web-cloud-services-part-2/

Tu rozwiązanie komercyjne:
http://www.habarisoft.com/habari_webcomponents.html

0

@kAzek

Chcę pobrać dane (dokładnie to kliknąć na przycisk, który jest za to odpowiedzialny na stronie projektu).

@vpiotr

Dziękuję za linki, na pewno przejrzę :)

1

Moze pomoze ten kod. Recznie to wygladalo tak ze po zalogowaniu na stronke twitcha mozna bylo sciagnac plik XML, jakis przycisk na stronce do pobrania byl.

function PobierzKluczTwitch(login, haslo: string): string;
var
  IdHTTP: TIdHTTP;
  IdSSL: TIdSSLIOHandlerSocketOpenSSL;
  HTML, authToken: string;
  Request: TStringList;
  poczatek, koniec: integer;
  aStream: TMemoryStream;
  rejestr: TRegistry;
  // XMLDocument1:TXMLDocument;
  XMLPobierzKluczTwitch: IXMLDOCUMENT;
  StartItemNode: IXMLNode;
  fLogin, fHaslo: string;
begin

  rejestr := TRegistry.Create((KEY_READ));
  rejestr.RootKey := HKEY_LOCAL_MACHINE;
  try
    rejestr.OpenKey('SOFTWARE\mca64Launcher', false);
    fLogin := login;
    fHaslo := haslo;
  finally
    rejestr.Free;
  end;

  try
    IdHTTP := TIdHTTP.Create;
    try
      XMLPobierzKluczTwitch := NewXMLDocument;
      IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
      IdHTTP.IOHandler := IdSSL;
      IdHTTP.AllowCookies := True;
      IdHTTP.CookieManager := Form1.IdCookieManager1;
      Form1.IdCookieManager1.CookieCollection.Clear;
      IdHTTP.HandleRedirects := True;
      HTML := IdHTTP.Get('http://www.twitch.tv/login');
      poczatek := Pos('"authenticity_token" type="hidden" value="', HTML) + Length('"authenticity_token" type="hidden" value="');
      koniec := PosEx('"', HTML, poczatek);
      authToken := copy(HTML, poczatek, koniec - poczatek);
      // showmessage(AuthToken);
      Request := TStringList.Create;
      try
        Request.Add('utf8=✓');
        Request.Add('authenticity_token=' + authToken);
        Request.Add('redirect_on_login=http://www.twitch.tv/broadcast/fmle3_config');
        // Request.Add('http://www.twitchapps.com/tmi/#access_token=oxxe76tsg92u3hi7bno2zsdm6yqfttc');
        Request.Add('embed_form=false');
        Request.Add('user[login]=' + login);
        Request.Add('user[password]=' + haslo);
        try
          aStream := TMemoryStream.Create;
          IdHTTP.Post('https://secure.twitch.tv/user/login', Request, aStream, IndyTextEncoding_UTF8());
          XMLPobierzKluczTwitch.LoadFromStream(aStream);
          StartItemNode := XMLPobierzKluczTwitch.DocumentElement.ChildNodes[5].ChildNodes[0];
          Result := StartItemNode.ChildNodes['stream'].Text
        except
        end;
      finally
        Request.Free;
        // IdSSL.Free;
        aStream.Free;
      end;
    finally
      IdHTTP.Free;
      // IdSSLOpenSSL.UnLoadOpenSSLLibrary()
    end;
  except
    on E: Exception do showmessage(E.message);
  end;
end; 
0

A co ze stronami szyfrowanymi (HTTPS)? Rozumiem, że muszę ściągnąć jakieś biblioteki DLL, żeby używać tego:

IdSSL: TIdSSLIOHandlerSocketOpenSSL;

0

Mam pewien problem ze sprawdzeniem czy połączenie zostało nawiązane. Wygląda to u mnie tak:

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
  IdTCPClient, IdHTTP, IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack,
  IdSSL, IdSSLOpenSSL;

type
  TForm1 = class(TForm)
    IdHTTP1: TIdHTTP;
    Edit1: TEdit;
    Edit2: TEdit;
    Label1: TLabel;
    Button1: TButton;
    Memo1: TMemo;
    IdSSLIOHandlerSocketOpenSSL1: TIdSSLIOHandlerSocketOpenSSL;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
 post: TStringList;
 result: string;

begin
 post := TStringList.Create;
 IdHTTP1.HandleRedirects := True;

 try
  post.Add('username=User');
  post.Add('password=Password123');

  result := IdHTTP1.Post('https://id.atlassian.com/login', post);

if () then
 Label1.Caption := 'Connect'
else
 Label1.Caption := 'Disconnect';

 except
  post.Free;
 end;
end;
end.

I nie wiem co mam dać w warunku if, żeby sprawdzić czy połączenie zostało nawiązane.

Edit
Próbowałem użyć procedury ResponseCode, ale za każdym razem dostaję wiadomość "Connected", nawet gdy jest złe hasło.

0

Przecież nawet nie wysyłasz prawidłowych danych do logowania tam masz pole csrfToken które także musisz wysłać, poza tym nie sprawdzasz czy połączony (bo połaczenie w 90% się powiedzie chyba że nie masz neta lub serwer strony padł) tylko szukasz czegoś charakterystycznego (świadczącego o tym że jest zalogowany np. Wyloguj / Log Out) w pobranym kodzie strony.

0

@kAzek

Zmodyfikowałem kod, ale wynikiem próby łączenia jest błąd

Project Project1.exe raised exception class EIdHTTPProtocol with message 'HTTP/1.1 403 Forbidden'. Process stopped. Use Step or Run to continue.

Zmodyfikowany kod:

procedure TForm1.Button1Click(Sender: TObject);
var
 post: TStringList;
 result: string;
 res: string;

begin
 post := TStringList.Create;
 IdHTTP1.HandleRedirects := True;

 try
  post.Add('csrfToken=valuse');
  post.Add('username=User');
  post.Add('password=Password123');

  result := IdHTTP1.Post('https://id.atlassian.com/login/', post);

  IdHTTP1.Connect;

if Pos('logout.action', result)>0 then
 Label1.Caption := 'Connect'
else
 Label1.Caption := 'Disconnect';

 except
  post.Free;
 end;
end;
end.
0

csrfToken masz pobrać poprawny ze strony pobranej GET a ni9e że sobie wymyślisz csrfToken=value

0

Zmodyfikowałem kod do takiej postaci:

procedure TForm1.Button1Click(Sender: TObject);
var
 post: TStringList;
 result: string;
 poczatek, koniec: integer;
 aStream: TMemoryStream;
 HTML, authToken: string;
 fLogin, fHaslo: string;
 
begin
 post := TStringList.Create;
 IdHTTP1.HandleRedirects := True;
 
 fLogin := Edit1.Text;
 fHaslo := Edit2.Text;
 
 try
  HTML := IdHTTP1.Get('https://id.atlassian.com/login');
  poczatek := Pos('"csrfToken" type="hidden" value="', HTML) + 
  Length('"csrfToken" type="hidden" value="');
  koniec := PosEx('"', HTML, poczatek);
  authToken := copy(HTML, poczatek, koniec - poczatek);

  post := TStringList.Create;
  try
   post.Add('csrfToken=' + authToken);
   post.Add('username=' + fLogin);
   post.Add('password=' + fHaslo);
   try
    aStream := TMemoryStream.Create;
	IdHTTP1.Post('https://id.atlassian.com/login', post, aStream);
   except
   end;
  finally
   post.Free;
   aStream.Free;
  end;
 finally
  IdHTTP1.Free;
 end;
end;
end.

Ale przy próbie łączenia dalej mam błąd

Project Project1.exe raised exception class EIdHTTPProtocol with message 'HTTP/1.1 403 Forbidden'. Process stopped. Use Step or Run to continue.

Co robię źle? Wydaje mi się, że dane są przesyłane poprawnie.

0

a gdzie cookies i ssl? Na forme postaw sobie komponenty, doklanych nazw z pamieci ci nie powiem. Wpisz sobie wyszkuiwarce Delphi cookie a potem ssl

0

@mca64

To, co wykonuje ten kod:

 IdSSL := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
 IdHTTP.IOHandler := IdSSL;
 IdHTTP.AllowCookies := True;
 IdHTTP.CookieManager := Form1.IdCookieManager1;

Mam ustawione ręcznie we właściwościach obiektu IdHTTP1.

Reszta wygląda tak:

procedure TForm1.Button1Click(Sender: TObject);
var
 post: TStringList;
 result: string;
 poczatek, koniec: integer;
 aStream: TMemoryStream;
 HTML, authToken: string;
 fLogin, fHaslo: string;
 
begin
 post := TStringList.Create;
 Form1.IdCookieManager1.CookieCollection.Clear;
 IdHTTP1.HandleRedirects := True;
 
 fLogin := Edit1.Text;
 fHaslo := Edit2.Text;
 
 try
  HTML := IdHTTP1.Get('https://id.atlassian.com/login');
  poczatek := Pos('"csrfToken" type="hidden" value="', HTML) + 
  Length('"csrfToken" type="hidden" value="');
  koniec := PosEx('"', HTML, poczatek);
  authToken := copy(HTML, poczatek, koniec - poczatek);

  post := TStringList.Create;
  try
   post.Add('csrfToken=' + authToken);
   post.Add('username=' + fLogin);
   post.Add('password=' + fHaslo);
   try
    aStream := TMemoryStream.Create;
	IdHTTP1.Post('https://id.atlassian.com/login', post, aStream);
   except
   end;
  finally
   post.Free;
   // IdSSL.Free;
   aStream.Free;
  end;
 finally
  IdHTTP1.Free;
  // IdSSLOpenSSL.UnLoadOpenSSLLibrary()
 end;
end;
end.

Ale to nie niweluje błędu. Komponenty mam wstawione:

  • IdCookieManager1 dla ciastek
  • IdSSLIOHandlerSocketOpenSSL1
    Gdzie dokładnie powinienem umieścić SSL? Bo ciastka według mnie ustawione są już dobrze (ale pewnie się mylę).

Edit
Obie biblioteki mam w folderze z programem.

2

Przecież cały czas piszę że pobierasz źle token to nawet nie sprawdziłeś czy robisz to prawidłowo (oczywiście ze nie w moim kodzie jest ok). Coś takiego:

var
 post: TStringList;
 poczatek, koniec: integer;
 aStream: TMemoryStream;
 HTML, authToken: string;
 fLogin, fHaslo: string;
begin
 IdHTTP1.HandleRedirects := True;

 fLogin := Edit1.Text;
 fHaslo := Edit2.Text;

 HTML := IdHTTP1.Get('https://id.atlassian.com/login/login');
 poczatek := Pos('name="csrfToken" value="', HTML) +
 Length('name="csrfToken" value="');
 koniec := PosEx('"', HTML, poczatek);
 authToken := copy(HTML, poczatek, koniec - poczatek);

 post := TStringList.Create;
 try
   post.Add('csrfToken=' + authToken);
   post.Add('username=' + fLogin);
   post.Add('password=' + fHaslo);
 try
   IdHTTP1.Request.ContentType:= 'application/x-www-form-urlencoded';
   HTML:= IdHTTP1.Post('https://id.atlassian.com/login/login', post);
   Memo1.Text:= HTML;
 except
     if IdHTTP1.ResponseCode = 401 then
       ShowMessage('Niwprawidłowy login lub hasło.');
 end;
 finally
   post.Free;
 end;
end;

Na formie IdHTTP i IdSSLIOHandlerSocketOpenSSL (oczywiście IdSSLIOHandlerSocketOpenSSL ustawiony jako IOHandler w IdHTTP) no i w folderze programu lub systemowym muszą być biblioteki ssleay32.dll i libeay32.dll.

0

@kAzek @mca64

Dziękuję serdecznie za pomoc :) Już wiem, co robiłem źle :) Na razie zajmę się ćwiczeniami z Indy (jakieś pobieranie z FTP, program do wysyłania maili, komunikator).

Jeszcze raz serdecznie dziękuję za pomoc :)

Edit
Jeszcze jedno pytanie - w kodzie trzeba wstawić jeszcze warunek sprawdzający czy dane są poprawne, tak? Tzn. aktualnie dostaję informację "Połączono" niezależnie od tego, jakie dane wpiszę w pola tekstowe.

0

masz na mysli czy udalo sie zalogowac?
tutaj mozesz cos dac

   HTML:= IdHTTP1.Post('https://id.atlassian.com/login/login', post);
   Memo1.Text:= HTML;

polaczono := true;

 except
     if IdHTTP1.ResponseCode = 401 then
       ShowMessage('Niwprawidłowy login lub hasło.');
 end;
0

Jeszcze jedno, ostatnie pytanie - czy ten kod zadziała dla stron z rozszerzeniem *.jsp? Chodzi mi tylko o to, czy jest możliwe połączenie się z taką stroną poprzez IdHTTP (lub inny komponent) czy też jest to nie możliwe?

Edit
Próbowałem łączyć się za pomocą tego kodu ze stroną o rozszerzeniu *.jsp, ale za każdym razem uzyskuję kod. Przy łączeniu ze stronami o rozszerzeniu *.html nie ma problemu (przy dobrych danych łączy, przy złych wyświetla komunikat).

0

A ja myślę że nie bardzo ogarniasz co robisz i prawdopodobnie masz źle ustawiony nagłówek 'Content-Type' i powinieneś zmienić:

IdHTTP1.Request.ContentType:= 'application/x-www-form-urlencoded';

na:

IdHTTP1.Request.ContentType:= 'application/json';
0

@kAzek

Tylko, że w dalszym ciągu wyświetla kod strony, niezależnie od tego czy login i hasło są poprawne czy też błędne.

0

A co wg. ciebie miałoby wyświetlać? Browary?

0

Chodziło mi o to, że przy wpisywaniu błędnych danych powinien pojawiać się stosowny komunikat.

0

Jeżeli serwer zwróci kod 401 (u mnie tak zwracał) a jak to nie zawsze się sprawdza to musisz tak jak pisałem wcześniej sprawdzać czy istnieje jakiś charakterystyczny tekst w kodzie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1