123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- unit Quick.OAuth;
- interface
- uses
- Quick.HttpClient,
- Quick.HttpServer.Request,
- Quick.HttpServer.Response,
- Quick.HttpServer,
- Quick.Threads,
- Quick.OAuth.Utils,
- SysUtils;
- type
- TOAuthToken = class
- private
- fAccessTokenExpiration: integer;
- fAccessToken: string;
- fRefreshToken: string;
- fRetrieveDateTime: TDateTime;
- public
- property AccessToken: string read fAccessToken write fAccessToken;
- property AccessTokenExpiration: integer read fAccessTokenExpiration write
- fAccessTokenExpiration;
- property RefreshToken: string read fRefreshToken write fRefreshToken;
- property RetrieveDateTime: TDateTime read fRetrieveDateTime write
- fRetrieveDateTime;
- end;
- TOnSaveToken = procedure (const aToken: TOAuthToken) of object;
- TOnLoadToken = procedure (var aToken: TOAuthToken) of object;
- TOnAuthorizationCompleted = reference to procedure (const aToken: TOAuthToken);
- TOnRefreshCompleted = reference to procedure (const aToken: TOAuthToken);
- {$M+}
- TOAuthBase = class
- private
- fToken: TOAuthToken;
- fOnAuthorizationCompleted: TOnAuthorizationCompleted;
- fOnRefreshCompleted: TOnRefreshCompleted;
- fAccessTokenParam: string;
- fAuthCodeParam: string;
- fAuthErrorParam: string;
- fExpirationParam: string;
- fRefreshTokenParam: string;
- fCallbackURL: string;
- fServer: THttpServer;
- fClient: TJsonHttpClient;
- fOnSaveToken: TOnSaveToken;
- fOnLoadToken: TOnLoadToken;
- procedure ExchangeAuthForAccessToken (const aAuthToken: string);
- procedure RefreshAccessToken (const aRefreshToken: string);
- function GetAccessToken: string;
- function IsTokenValid: boolean;
- protected
- // Abstract
- function CreateAuthorizationRequest: string; virtual; abstract;
- function CreateAuthToAccessRequest (const aAuthToken: string): string; virtual; abstract;
- function CreateRefreshRequest (const aRefreshToken: string): string; virtual; abstract;
- // Available
- function CreateAuthorizationHTMLPage (const aAuthorised: boolean): string; virtual;
- procedure OnProcessRequest(aRequest: IHttpRequest; aResponse: IHttpResponse); virtual;
- public
- constructor Create;
- destructor Destroy; override;
- // Methods
- procedure Authorize(const aOnAuthorizationCompleted: TOnAuthorizationCompleted = nil);
- procedure RefreshToken (const aOnRefreshCompleted: TOnRefreshCompleted = nil);
- // Properties
- property AccessTokenParam: string read fAccessTokenParam write
- fAccessTokenParam;
- property AuthCodeParam: string read fAuthCodeParam write fAuthCodeParam;
- property AuthErrorParam: string read fAuthErrorParam write fAuthErrorParam;
- property ExpirationParam: string read fExpirationParam write fExpirationParam;
- property RefreshTokenParam: string read fRefreshTokenParam write
- fRefreshTokenParam;
- property CallbackURL: string read fCallbackURL write fCallbackURL;
- property AccessToken: string read GetAccessToken;
- published
- // Events
- property OnSaveToken: TOnSaveToken read fOnSaveToken write fOnSaveToken;
- property OnLoadToken: TOnLoadToken read fOnLoadToken write fOnLoadToken;
- end;
- {$M-}
- EOAuthException = class (Exception);
- implementation
- uses
- System.JSON, System.DateUtils, System.Types;
- {$I QuickLib.INC}
- constructor TOAuthBase.Create;
- begin
- inherited Create;
- fClient:=TJsonHttpClient.Create;
- {$IFNDEF DELPHIRX101_UP}
- fServer:=nil;
- {$ENDIF}
- fToken:=TOAuthToken.Create;
- fToken.AccessToken:='';
- fToken.AccessTokenExpiration:=0;
- fToken.RefreshToken:='';
- fToken.RetrieveDateTime:=EncodeDateTime(1900, 1, 1, 23, 59, 00, 00);
- end;
- function TOAuthBase.CreateAuthorizationHTMLPage(
- const aAuthorised: boolean): string;
- begin
- if aAuthorised then
- result:='Access Authorised! You can now close this page and return to the application'
- else
- result:='Access Denied!';
- end;
- destructor TOAuthBase.Destroy;
- begin
- fClient.Free;
- fServer.Free;
- fToken.Free;
- inherited;
- end;
- procedure TOAuthBase.ExchangeAuthForAccessToken(const aAuthToken: string);
- var
- resp: IHttpRequestResponse;
- accToken: string;
- refrToken: string;
- expiry: integer;
- begin
- fToken.AccessToken:='';
- fToken.AccessTokenExpiration:=0;
- try
- case GetMethodFromRequest(CreateAuthToAccessRequest(aAuthToken)) of
- rmGET: resp:=fClient.Get(GetCleanRequest(CreateAuthToAccessRequest(aAuthToken)));
- rmPOST: resp:=fClient.Post(GetCleanRequest(CreateAuthToAccessRequest(aAuthToken)), '');
- end;
- if (assigned(resp)) and (resp.StatusCode = 200) then
- begin
- if Assigned(resp.Response) then
- begin
- if resp.Response.TryGetValue(AccessTokenParam, accToken) then
- fToken.AccessToken:=accToken;
- if resp.Response.TryGetValue(ExpirationParam, expiry) then
- fToken.AccessTokenExpiration:=expiry;
- if resp.Response.TryGetValue(RefreshTokenParam, refrToken) then
- fToken.RefreshToken:=refrToken;
- fToken.RetrieveDateTime:=Now;
- if Assigned(fOnSaveToken) then
- fOnSaveToken(fToken);
- if Assigned(fOnAuthorizationCompleted) then
- fOnAuthorizationCompleted(fToken);
- end;
- end
- else
- raise EOAuthException.Create('Something went wrong. Please try again');
- except
- raise EOAuthException.Create('Something went wrong. Please try again');
- end;
- end;
- procedure TOAuthBase.OnProcessRequest(aRequest: IHttpRequest;
- aResponse: IHttpResponse);
- begin
- fToken.AccessToken:='';
- fToken.AccessTokenExpiration:=0;
- if aRequest.UnparsedParams.Contains(AuthErrorParam) then
- aResponse.ContentText:= CreateAuthorizationHTMLPage(false)
- else
- if aRequest.UnparsedParams.Contains(AuthCodeParam) then
- begin
- ExchangeAuthForAccessToken(aRequest.Query[AuthCodeParam].AsString);
- aResponse.ContentText:= CreateAuthorizationHTMLPage(true);
- end;
- end;
- procedure TOAuthBase.RefreshAccessToken(const aRefreshToken: string);
- var
- resp: IHttpRequestResponse;
- accToken: string;
- expiry: integer;
- begin
- try
- case GetMethodFromRequest(CreateRefreshRequest(aRefreshToken)) of
- rmGET: resp:=fClient.Get(GetCleanRequest(CreateRefreshRequest(aRefreshToken)));
- rmPOST: resp:=fClient.Post(GetCleanRequest(CreateRefreshRequest(aRefreshToken)), '');
- end;
- if (assigned(resp)) and (resp.StatusCode = 200) then
- begin
- if Assigned(resp.Response) then
- begin
- if resp.Response.TryGetValue(AccessTokenParam, accToken) then
- fToken.AccessToken:=accToken;
- if resp.Response.TryGetValue(ExpirationParam, expiry) then
- fToken.AccessTokenExpiration:=expiry;
- fToken.RetrieveDateTime:=Now;
- if Assigned(fOnSaveToken) then
- fOnSaveToken(fToken);
- end;
- end
- else
- raise EOAuthException.Create('Something went wrong. Please try again');
- except
- raise EOAuthException.Create('Something went wrong. Please try again');
- end;
- end;
- procedure TOAuthBase.RefreshToken(const aOnRefreshCompleted:
- TOnRefreshCompleted = nil);
- begin
- fOnRefreshCompleted:=aOnRefreshCompleted;
- if Assigned(fOnLoadToken) then
- fOnLoadToken(fToken);
- if fToken.AccessToken = '' then
- Authorize(TOnAuthorizationCompleted(fOnRefreshCompleted))
- else
- begin
- GetAccessToken;
- if Assigned(fOnRefreshCompleted) then
- fOnRefreshCompleted(fToken);
- end;
- end;
- procedure TOAuthBase.Authorize(const aOnAuthorizationCompleted:
- TOnAuthorizationCompleted = nil);
- begin
- fOnAuthorizationCompleted:=aOnAuthorizationCompleted;
- if Assigned(fOnLoadToken) then
- fOnLoadToken(fToken);
- if IsTokenValid then
- Exit;
- fClient:=TJsonHttpClient.Create;
- if Assigned(fServer) then
- fServer.Stop;
- FreeAndNil(fServer);
- fServer:=THttpServer.Create(GetDomain(fCallbackURL), GetPort(fCallbackURL), false, nil);
- try
- fServer.OnNewRequest:=OnProcessRequest;
- fServer.Start;
- OpenURL(GetCleanRequest(CreateAuthorizationRequest));
- except
- fServer.Stop;
- FreeAndNil(fServer);
- end;
- end;
- function TOAuthBase.GetAccessToken: string;
- begin
- result:='';
- if IsTokenValid then
- result:=fToken.AccessToken
- else
- RefreshAccessToken(fToken.RefreshToken);
- end;
- function TOAuthBase.IsTokenValid: boolean;
- var
- expDate: TDateTime;
- begin
- expDate:=IncSecond(fToken.RetrieveDateTime, fToken.AccessTokenExpiration);
- result:= CompareDateTime(expDate, Now) = GreaterThanValue;
- end;
- end.
|