mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 07:45:54 +01:00
ADDED LiveValidityWindowsInSeconds to the JWT classes.
This commit is contained in:
parent
23b8c3c1af
commit
e52aacc391
@ -50,3 +50,4 @@ The memory allocated for the TJSONValue descendant (e.g. TJSONObject, TJSONArray
|
||||
```
|
||||
|
||||
- ```TMVCConfigKey.ISAPIPath``` has been substituted with ```TMVCConfigKey.PathPrefix``` and now is applicated to all kind of projects (not only ISAPI);
|
||||
- ```MapperSerializeAsString``` attribute is now ```MVCSerializeAsString```
|
@ -1,3 +1,6 @@
|
||||
11/07/2017
|
||||
- Added LiveValidityWindowsInSeconds in the JWT middleware.
|
||||
|
||||
02/10/2016
|
||||
- Added LoadViewFragment. The view fragment is appended to the ResponseStream verbatim. No processing happens.
|
||||
procedure LoadViewFragment(const ViewFragment: string);
|
||||
|
104
samples/jsonwebtoken_livevaliditywindow/AppControllerU.pas
Normal file
104
samples/jsonwebtoken_livevaliditywindow/AppControllerU.pas
Normal file
@ -0,0 +1,104 @@
|
||||
unit AppControllerU;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
MVCFramework,
|
||||
MVCFramework.Commons,
|
||||
MVCFramework.Logger,
|
||||
Web.HTTPApp;
|
||||
|
||||
type
|
||||
|
||||
[MVCPath('/')]
|
||||
TApp1MainController = class(TMVCController)
|
||||
public
|
||||
[MVCPath('/public')]
|
||||
[MVCHTTPMethod([httpGET])]
|
||||
procedure PublicSection(ctx: TWebContext);
|
||||
[MVCPath('/')]
|
||||
[MVCHTTPMethod([httpGET])]
|
||||
procedure Index(ctx: TWebContext);
|
||||
end;
|
||||
|
||||
[MVCPath('/admin')]
|
||||
TAdminController = class(TMVCController)
|
||||
public
|
||||
[MVCPath('/role1')]
|
||||
[MVCProduces('text/html')]
|
||||
[MVCHTTPMethod([httpGET])]
|
||||
procedure OnlyRole1(ctx: TWebContext);
|
||||
[MVCPath('/role1')]
|
||||
[MVCProduces('application/json')]
|
||||
[MVCHTTPMethod([httpGET])]
|
||||
procedure OnlyRole1EmittingJSON;
|
||||
[MVCPath('/role2')]
|
||||
[MVCProduces('text/html')]
|
||||
[MVCHTTPMethod([httpGET])]
|
||||
procedure OnlyRole2(ctx: TWebContext);
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses
|
||||
System.SysUtils, System.JSON, System.Classes;
|
||||
|
||||
{ TApp1MainController }
|
||||
|
||||
procedure TApp1MainController.Index(ctx: TWebContext);
|
||||
begin
|
||||
Redirect('/index.html');
|
||||
end;
|
||||
|
||||
procedure TApp1MainController.PublicSection(ctx: TWebContext);
|
||||
begin
|
||||
Render('This is a public section');
|
||||
end;
|
||||
|
||||
{ TAdminController }
|
||||
|
||||
procedure TAdminController.OnlyRole1(ctx: TWebContext);
|
||||
begin
|
||||
ContentType := TMVCMediaType.TEXT_PLAIN;
|
||||
ResponseStream.AppendLine('Hey! Hello ' + ctx.LoggedUser.UserName +
|
||||
', now you are a logged user and this is a protected content!');
|
||||
ResponseStream.AppendLine('As logged user you have the following roles: ' +
|
||||
sLineBreak + string.Join(sLineBreak, Context.LoggedUser.Roles.ToArray));
|
||||
RenderResponseStream;
|
||||
end;
|
||||
|
||||
procedure TAdminController.OnlyRole1EmittingJSON;
|
||||
var
|
||||
lJObj: TJSONObject;
|
||||
lJArr: TJSONArray;
|
||||
lQueryParams: TStrings;
|
||||
I: Integer;
|
||||
begin
|
||||
ContentType := TMVCMediaType.APPLICATION_JSON;
|
||||
lJObj := TJSONObject.Create;
|
||||
lJObj.AddPair('message', 'This is protected content accessible only by user1');
|
||||
lJArr := TJSONArray.Create;
|
||||
lJObj.AddPair('querystringparameters', lJArr);
|
||||
|
||||
lQueryParams := Context.Request.QueryStringParams;
|
||||
for I := 0 to lQueryParams.Count - 1 do
|
||||
begin
|
||||
lJArr.AddElement(TJSONObject.Create(TJSONPair.Create(
|
||||
lQueryParams.Names[I],
|
||||
lQueryParams.ValueFromIndex[I])));
|
||||
end;
|
||||
|
||||
Render(lJObj);
|
||||
end;
|
||||
|
||||
procedure TAdminController.OnlyRole2(ctx: TWebContext);
|
||||
begin
|
||||
ContentType := TMVCMediaType.TEXT_PLAIN;
|
||||
ResponseStream.AppendLine('Hey! Hello ' + ctx.LoggedUser.UserName +
|
||||
', now you are a logged user and this is a protected content!');
|
||||
ResponseStream.AppendLine('As logged user you have the following roles: ' +
|
||||
sLineBreak + string.Join(sLineBreak, Context.LoggedUser.Roles.ToArray));
|
||||
RenderResponseStream;
|
||||
end;
|
||||
|
||||
end.
|
78
samples/jsonwebtoken_livevaliditywindow/AuthenticationU.pas
Normal file
78
samples/jsonwebtoken_livevaliditywindow/AuthenticationU.pas
Normal file
@ -0,0 +1,78 @@
|
||||
unit AuthenticationU;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils, MVCFramework.Commons, System.Generics.Collections,
|
||||
MVCFramework;
|
||||
|
||||
type
|
||||
TAuthenticationSample = class(TInterfacedObject, IMVCAuthenticationHandler)
|
||||
protected
|
||||
procedure OnRequest(const ControllerQualifiedClassName: string;
|
||||
const ActionName: string; var AuthenticationRequired: Boolean);
|
||||
procedure OnAuthentication(const UserName: string; const Password: string;
|
||||
UserRoles: System.Generics.Collections.TList<System.string>;
|
||||
var IsValid: Boolean; const SessionData: TSessionData);
|
||||
procedure OnAuthorization(UserRoles
|
||||
: System.Generics.Collections.TList<System.string>;
|
||||
const ControllerQualifiedClassName: string; const ActionName: string;
|
||||
var IsAuthorized: Boolean);
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TMVCAuthorization }
|
||||
|
||||
procedure TAuthenticationSample.OnAuthentication(const UserName,
|
||||
Password: string; UserRoles: System.Generics.Collections.TList<System.string>;
|
||||
var IsValid: Boolean; const SessionData: TSessionData);
|
||||
begin
|
||||
IsValid := UserName.Equals(Password); // hey!, this is just a demo!!!
|
||||
if IsValid then
|
||||
begin
|
||||
if UserName = 'user1' then
|
||||
begin
|
||||
UserRoles.Add('role1');
|
||||
end;
|
||||
if UserName = 'user2' then
|
||||
begin
|
||||
UserRoles.Add('role2');
|
||||
end;
|
||||
if UserName = 'user3' then // all the roles
|
||||
begin
|
||||
UserRoles.Add('role1');
|
||||
UserRoles.Add('role2');
|
||||
end;
|
||||
end
|
||||
else
|
||||
begin
|
||||
UserRoles.Clear;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TAuthenticationSample.OnAuthorization
|
||||
(UserRoles: System.Generics.Collections.TList<System.string>;
|
||||
const ControllerQualifiedClassName, ActionName: string;
|
||||
var IsAuthorized: Boolean);
|
||||
begin
|
||||
IsAuthorized := False;
|
||||
if ActionName = 'Logout' then
|
||||
IsAuthorized := True; // you can always call logout
|
||||
if ActionName = 'OnlyRole2' then
|
||||
IsAuthorized := UserRoles.Contains('role2');
|
||||
if ActionName = 'OnlyRole1' then
|
||||
IsAuthorized := UserRoles.Contains('role1');
|
||||
if ActionName = 'OnlyRole1EmittingJSON' then
|
||||
IsAuthorized := UserRoles.Contains('role1');
|
||||
end;
|
||||
|
||||
procedure TAuthenticationSample.OnRequest(const ControllerQualifiedClassName,
|
||||
ActionName: string; var AuthenticationRequired: Boolean);
|
||||
begin
|
||||
AuthenticationRequired := ControllerQualifiedClassName =
|
||||
'AppControllerU.TAdminController';
|
||||
|
||||
end;
|
||||
|
||||
end.
|
50
samples/jsonwebtoken_livevaliditywindow/JWTServer.dpr
Normal file
50
samples/jsonwebtoken_livevaliditywindow/JWTServer.dpr
Normal file
@ -0,0 +1,50 @@
|
||||
program JWTServer;
|
||||
|
||||
{$APPTYPE CONSOLE}
|
||||
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
Winapi.Windows,
|
||||
Winapi.ShellAPI,
|
||||
Web.WebReq,
|
||||
Web.WebBroker,
|
||||
IdHTTPWebBrokerBridge,
|
||||
WebModuleUnit1 in 'WebModuleUnit1.pas' {WebModule1: TWebModule},
|
||||
AppControllerU in 'AppControllerU.pas',
|
||||
AuthenticationU in 'AuthenticationU.pas';
|
||||
|
||||
{$R *.res}
|
||||
|
||||
|
||||
procedure RunServer(APort: Integer);
|
||||
var
|
||||
LServer: TIdHTTPWebBrokerBridge;
|
||||
begin
|
||||
Writeln(Format('Starting HTTP Server or port %d', [APort]));
|
||||
LServer := TIdHTTPWebBrokerBridge.Create(nil);
|
||||
try
|
||||
LServer.DefaultPort := APort;
|
||||
LServer.Active := True;
|
||||
Writeln('THIS SERVER USES JWT WITH LIVEVALIDITYWINDOWS FEATURE');
|
||||
Writeln('Press RETURN to stop the server');
|
||||
// ShellExecute(0, 'open', PChar('http://localhost:' + IntToStr(APort)), nil, nil, SW_SHOW);
|
||||
ReadLn;
|
||||
finally
|
||||
LServer.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
begin
|
||||
ReportMemoryLeaksOnShutdown := True;
|
||||
try
|
||||
if WebRequestHandler <> nil then
|
||||
WebRequestHandler.WebModuleClass := WebModuleClass;
|
||||
WebRequestHandlerProc.MaxConnections := 1024;
|
||||
RunServer(8080);
|
||||
except
|
||||
on E: Exception do
|
||||
Writeln(E.ClassName, ': ', E.Message);
|
||||
end
|
||||
|
||||
end.
|
648
samples/jsonwebtoken_livevaliditywindow/JWTServer.dproj
Normal file
648
samples/jsonwebtoken_livevaliditywindow/JWTServer.dproj
Normal file
@ -0,0 +1,648 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{7B54055A-5749-4136-9FE2-35FDBEEA874C}</ProjectGuid>
|
||||
<ProjectVersion>18.2</ProjectVersion>
|
||||
<FrameworkType>VCL</FrameworkType>
|
||||
<MainSource>JWTServer.dpr</MainSource>
|
||||
<Base>True</Base>
|
||||
<Config Condition="'$(Config)'==''">Debug</Config>
|
||||
<Platform Condition="'$(Platform)'==''">Win32</Platform>
|
||||
<TargetedPlatforms>1</TargetedPlatforms>
|
||||
<AppType>Console</AppType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Android' and '$(Base)'=='true') or '$(Base_Android)'!=''">
|
||||
<Base_Android>true</Base_Android>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='iOSDevice32' and '$(Base)'=='true') or '$(Base_iOSDevice32)'!=''">
|
||||
<Base_iOSDevice32>true</Base_iOSDevice32>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='iOSDevice64' and '$(Base)'=='true') or '$(Base_iOSDevice64)'!=''">
|
||||
<Base_iOSDevice64>true</Base_iOSDevice64>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='iOSSimulator' and '$(Base)'=='true') or '$(Base_iOSSimulator)'!=''">
|
||||
<Base_iOSSimulator>true</Base_iOSSimulator>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
|
||||
<Base_Win32>true</Base_Win32>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
|
||||
<Base_Win64>true</Base_Win64>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
|
||||
<Cfg_1>true</Cfg_1>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
|
||||
<Cfg_1_Win32>true</Cfg_1_Win32>
|
||||
<CfgParent>Cfg_1</CfgParent>
|
||||
<Cfg_1>true</Cfg_1>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
|
||||
<Cfg_2>true</Cfg_2>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
|
||||
<Cfg_2_Win32>true</Cfg_2_Win32>
|
||||
<CfgParent>Cfg_2</CfgParent>
|
||||
<Cfg_2>true</Cfg_2>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base)'!=''">
|
||||
<DCC_SYMBOL_PLATFORM>false</DCC_SYMBOL_PLATFORM>
|
||||
<Icns_MainIcns>$(BDS)\bin\delphi_PROJECTICNS.icns</Icns_MainIcns>
|
||||
<SanitizedProjectName>JWTServer</SanitizedProjectName>
|
||||
<DCC_UnitSearchPath>..\..\sources;..\..\lib\delphistompclient;..\..\lib\loggerpro;..\..\lib\dmustache;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
|
||||
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
|
||||
<Manifest_File>None</Manifest_File>
|
||||
<VerInfo_Locale>1040</VerInfo_Locale>
|
||||
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
|
||||
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
|
||||
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
|
||||
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
|
||||
<DCC_E>false</DCC_E>
|
||||
<DCC_N>false</DCC_N>
|
||||
<DCC_S>false</DCC_S>
|
||||
<DCC_F>false</DCC_F>
|
||||
<DCC_K>false</DCC_K>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Android)'!=''">
|
||||
<Android_LauncherIcon48>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_48x48.png</Android_LauncherIcon48>
|
||||
<AUP_WRITE_CALENDAR>true</AUP_WRITE_CALENDAR>
|
||||
<Android_LauncherIcon144>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_144x144.png</Android_LauncherIcon144>
|
||||
<AUP_READ_CALENDAR>true</AUP_READ_CALENDAR>
|
||||
<Android_SplashImage470>$(BDS)\bin\Artwork\Android\FM_SplashImage_470x320.png</Android_SplashImage470>
|
||||
<Android_LauncherIcon36>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_36x36.png</Android_LauncherIcon36>
|
||||
<AUP_WRITE_EXTERNAL_STORAGE>true</AUP_WRITE_EXTERNAL_STORAGE>
|
||||
<Android_SplashImage640>$(BDS)\bin\Artwork\Android\FM_SplashImage_640x480.png</Android_SplashImage640>
|
||||
<Android_SplashImage960>$(BDS)\bin\Artwork\Android\FM_SplashImage_960x720.png</Android_SplashImage960>
|
||||
<AUP_CAMERA>true</AUP_CAMERA>
|
||||
<AUP_READ_PHONE_STATE>true</AUP_READ_PHONE_STATE>
|
||||
<Android_LauncherIcon96>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_96x96.png</Android_LauncherIcon96>
|
||||
<AUP_INTERNET>true</AUP_INTERNET>
|
||||
<AUP_ACCESS_COARSE_LOCATION>true</AUP_ACCESS_COARSE_LOCATION>
|
||||
<EnabledSysJars>android-support-v4.dex.jar;apk-expansion.dex.jar;cloud-messaging.dex.jar;fmx.dex.jar;google-analytics-v2.dex.jar;google-play-billing.dex.jar;google-play-licensing.dex.jar;google-play-services.dex.jar</EnabledSysJars>
|
||||
<Android_LauncherIcon72>$(BDS)\bin\Artwork\Android\FM_LauncherIcon_72x72.png</Android_LauncherIcon72>
|
||||
<VerInfo_Keys>package=com.embarcadero.$(MSBuildProjectName);label=$(MSBuildProjectName);versionCode=1;versionName=1.0.0;persistent=False;restoreAnyVersion=False;installLocation=auto;largeHeap=False;theme=TitleBar;hardwareAccelerated=true;apiKey=</VerInfo_Keys>
|
||||
<Android_SplashImage426>$(BDS)\bin\Artwork\Android\FM_SplashImage_426x320.png</Android_SplashImage426>
|
||||
<AUP_READ_EXTERNAL_STORAGE>true</AUP_READ_EXTERNAL_STORAGE>
|
||||
<BT_BuildType>Debug</BT_BuildType>
|
||||
<AUP_CALL_PHONE>true</AUP_CALL_PHONE>
|
||||
<AUP_ACCESS_FINE_LOCATION>true</AUP_ACCESS_FINE_LOCATION>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_iOSDevice32)'!=''">
|
||||
<iPad_Launch1024x768>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png</iPad_Launch1024x768>
|
||||
<iPad_AppIcon152>$(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png</iPad_AppIcon152>
|
||||
<iPad_Launch1536x2048>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png</iPad_Launch1536x2048>
|
||||
<iPhone_Spotlight40>$(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png</iPhone_Spotlight40>
|
||||
<iPad_SpotLight80>$(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png</iPad_SpotLight80>
|
||||
<iPad_SpotLight40>$(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png</iPad_SpotLight40>
|
||||
<iPhone_Spotlight80>$(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png</iPhone_Spotlight80>
|
||||
<iPad_AppIcon76>$(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png</iPad_AppIcon76>
|
||||
<iPhone_AppIcon120>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png</iPhone_AppIcon120>
|
||||
<VerInfo_Keys>CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes=</VerInfo_Keys>
|
||||
<BT_BuildType>Debug</BT_BuildType>
|
||||
<iPhone_AppIcon60>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png</iPhone_AppIcon60>
|
||||
<VerInfo_BundleId>$(MSBuildProjectName)</VerInfo_BundleId>
|
||||
<VerInfo_UIDeviceFamily>iPhoneAndiPad</VerInfo_UIDeviceFamily>
|
||||
<iPad_Launch2048x1536>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png</iPad_Launch2048x1536>
|
||||
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
|
||||
<iPad_Launch768x1024>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png</iPad_Launch768x1024>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_iOSDevice64)'!=''">
|
||||
<iPad_Launch1024x768>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png</iPad_Launch1024x768>
|
||||
<iPad_AppIcon152>$(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png</iPad_AppIcon152>
|
||||
<iPad_Launch1536x2048>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png</iPad_Launch1536x2048>
|
||||
<iPhone_Spotlight40>$(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png</iPhone_Spotlight40>
|
||||
<iPad_SpotLight80>$(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png</iPad_SpotLight80>
|
||||
<iPad_SpotLight40>$(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png</iPad_SpotLight40>
|
||||
<iPhone_Spotlight80>$(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png</iPhone_Spotlight80>
|
||||
<iPad_AppIcon76>$(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png</iPad_AppIcon76>
|
||||
<iPhone_AppIcon120>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png</iPhone_AppIcon120>
|
||||
<VerInfo_Keys>CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes=</VerInfo_Keys>
|
||||
<BT_BuildType>Debug</BT_BuildType>
|
||||
<iPhone_AppIcon60>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png</iPhone_AppIcon60>
|
||||
<VerInfo_BundleId>$(MSBuildProjectName)</VerInfo_BundleId>
|
||||
<VerInfo_UIDeviceFamily>iPhoneAndiPad</VerInfo_UIDeviceFamily>
|
||||
<iPad_Launch2048x1536>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png</iPad_Launch2048x1536>
|
||||
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
|
||||
<iPad_Launch768x1024>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png</iPad_Launch768x1024>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_iOSSimulator)'!=''">
|
||||
<iPad_AppIcon152>$(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_152x152.png</iPad_AppIcon152>
|
||||
<iPad_Launch1024x768>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_1024x768.png</iPad_Launch1024x768>
|
||||
<iPhone_Spotlight40>$(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_40x40.png</iPhone_Spotlight40>
|
||||
<iPhone_Spotlight80>$(BDS)\bin\Artwork\iOS\iPhone\FM_SpotlightSearchIcon_80x80.png</iPhone_Spotlight80>
|
||||
<iPad_SpotLight40>$(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_40x40.png</iPad_SpotLight40>
|
||||
<iPad_SpotLight80>$(BDS)\bin\Artwork\iOS\iPad\FM_SpotlightSearchIcon_80x80.png</iPad_SpotLight80>
|
||||
<iPad_AppIcon76>$(BDS)\bin\Artwork\iOS\iPad\FM_ApplicationIcon_76x76.png</iPad_AppIcon76>
|
||||
<iPad_Launch1536x2048>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_1536x2048.png</iPad_Launch1536x2048>
|
||||
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
|
||||
<VerInfo_Keys>CFBundleName=$(MSBuildProjectName);CFBundleDevelopmentRegion=en;CFBundleDisplayName=$(MSBuildProjectName);CFBundleIdentifier=$(MSBuildProjectName);CFBundleInfoDictionaryVersion=7.1;CFBundleVersion=1.0.0.0;CFBundlePackageType=APPL;CFBundleSignature=????;LSRequiresIPhoneOS=true;CFBundleAllowMixedLocalizations=YES;CFBundleExecutable=$(MSBuildProjectName);UIDeviceFamily=iPhone & iPad;CFBundleResourceSpecification=ResourceRules.plist;NSLocationAlwaysUsageDescription=The reason for accessing the location information of the user;NSLocationWhenInUseUsageDescription=The reason for accessing the location information of the user;FMLocalNotificationPermission=false;UIBackgroundModes=</VerInfo_Keys>
|
||||
<iPhone_AppIcon60>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_60x60.png</iPhone_AppIcon60>
|
||||
<iPad_Launch768x1024>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImagePortrait_768x1024.png</iPad_Launch768x1024>
|
||||
<iPhone_AppIcon120>$(BDS)\bin\Artwork\iOS\iPhone\FM_ApplicationIcon_120x120.png</iPhone_AppIcon120>
|
||||
<iPad_Launch2048x1536>$(BDS)\bin\Artwork\iOS\iPad\FM_LaunchImageLandscape_2048x1536.png</iPad_Launch2048x1536>
|
||||
<VerInfo_UIDeviceFamily>iPhoneAndiPad</VerInfo_UIDeviceFamily>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Win32)'!=''">
|
||||
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
|
||||
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||
<DCC_UsePackage>cxPivotGridChartRS17;JvMM;dxSkinSevenRS17;dxSkinBlueprintRS17;dxSkinHighContrastRS17;dxSkinOffice2007BlackRS17;dxCoreRS17;cxPageControldxBarPopupMenuRS17;dxSkinXmas2008BlueRS17;dxPSDBTeeChartRS17;JvCrypt;dxPSTeeChartRS17;dxSkinSummer2008RS17;dxPScxSchedulerLnkRS17;dxSkinBlueRS17;dxSkinDarkRoomRS17;DBXInterBaseDriver;DataSnapServer;DataSnapCommon;dxPScxTLLnkRS17;JvNet;JvDotNetCtrls;dxRibbonRS17;DbxCommonDriver;cxDataRS17;vclimg;dxSkinsdxBarPainterRS17;dxPSdxDBTVLnkRS17;dbxcds;DatasnapConnectorsFreePascal;NxDBGridDsgn_dxe3;JvXPCtrls;dxSkinMoneyTwinsRS17;vcldb;cxExportRS17;dxPSCoreRS17;dxBarExtItemsRS17;dxGDIPlusRS17;FMXfrx17;dxNavBarRS17;CustomIPTransport;cxLibraryRS17;cxGridRS17;dxSkinOffice2010BlackRS17;dsnap;IndyIPServer;IndyCore;dxSkinMcSkinRS17;CloudService;dxPScxCommonRS17;FmxTeeUI;frxDB17;AnyDAC_PhysDb2_D17;dxSkinsdxDLPainterRS17;dxSkiniMaginaryRS17;JvDB;JvRuntimeDesign;dxPScxVGridLnkRS17;JclDeveloperTools;dxSkinSevenClassicRS17;dxPScxExtCommonRS17;MyFrameTestPackage;dxPScxSSLnkRS17;NxGridRun_dxe3;dxSkinLilianRS17;fs17;dxPSdxLCLnkRS17;dxSkinOffice2010BlueRS17;NxCommonRun_dxe3;bindcompfmx;DataBindingsVCL170;dxSkinOffice2010SilverRS17;vcldbx;cxSchedulerGridRS17;dbrtl;bindcomp;inetdb;JvPluginSystem;dxBarRS17;DataBindings;DBXOdbcDriver;IcsCommonDXE3Run;JvCmp;dxBarDBNavRS17;dxSkinWhiteprintRS17;JvTimeFramework;xmlrtl;dxSkinsdxRibbonPainterRS17;ibxpress;dxDockingRS17;vclactnband;bindengine;soaprtl;FMXTee;dxADOServerModeRS17;bindcompvcl;dxBarExtDBItemsRS17;dxPSPrVwRibbonRS17;Jcl;vclie;dxSkinOffice2007PinkRS17;cxPageControlRS17;dxSkinscxPCPainterRS17;AnyDAC_PhysADS_D17;AnyDAC_PhysIB_D17;dxmdsRS17;dxSkinTheAsphaltWorldRS17;DBXInformixDriver;Intraweb;dxPsPrVwAdvRS17;NxInspectorRun_dxe3;dxSkinSilverRS17;dxdborRS17;dsnapcon;DBXFirebirdDriver;fsDB17;inet;dorm_runtime_xe3;JvPascalInterpreter;vclx;dxSkinStardustRS17;cxEditorsRS17;DBXSybaseASADriver;NxInspectorDsgn_dxe3;dbexpress;IndyIPClient;AnyDAC_PhysMySQL_D17;cxTreeListdxBarPopupMenuRS17;dxSkinVS2010RS17;NxGridDsgn_dxe3;dxThemeRS17;DBXSqliteDriver;dxPScxGridLnkRS17;fmx;JvDlgs;IndySystem;TeeDB;dxSkinValentineRS17;vclib;inetdbbde;DataSnapClient;dxSkinDevExpressStyleRS17;DataSnapProviderClient;DBXSybaseASEDriver;cxBarEditItemRS17;AnyDAC_PhysMSAcc_D17;dxServerModeRS17;cxPivotGridOLAPRS17;cxSchedulerRS17;MetropolisUILiveTile;AnyDAC_PhysSQLITE_D17;dxPSLnksRS17;dxSkinPumpkinRS17;dxPSdxDBOCLnkRS17;cxVerticalGridRS17;dxSkinSpringTimeRS17;vcldsnap;dxSkinDevExpressDarkStyleRS17;DBXDb2Driver;AnyDAC_ComI_D17;DBXOracleDriver;AnyDAC_PhysMSSQL_D17;JvCore;NxDBGridRun_dxe3;vclribbon;AnyDAC_Comp_D17;cxSpreadSheetRS17;dxSkinLiquidSkyRS17;AnyDAC_PhysODBC_D17;fmxase;vcl;dxSkinOffice2007SilverRS17;AnyDAC_PhysPg_D17;IndyIPCommon;DBXMSSQLDriver;CodeSiteExpressPkg;dxPSdxOCLnkRS17;dcldxSkinsCoreRS17;JvAppFrm;AnyDAC_PhysASA_D17;inetdbxpress;webdsnap;NxCollectionRun_dxe3;AnyDAC_PhysOracle_D17;dxSkinCoffeeRS17;JvDocking;adortl;dxSkinscxSchedulerPainterRS17;JvWizards;NxCollectionDsgn_dxe3;frx17;NxCommonDsgn_dxe3;dxtrmdRS17;dxPScxPCProdRS17;AnyDAC_GUIxForms_D17;JvBands;rtl;DbxClientDriver;AnyDAC_PhysTDBX_D17;dxTabbedMDIRS17;dxComnRS17;dxSkinSharpPlusRS17;dxSkinsCoreRS17;dxSkinLondonLiquidSkyRS17;dxdbtrRS17;Tee;JclContainers;NxAddonsRun_dxe3;CPortLibDXE;JvSystem;dxorgcRS17;svnui;dxSkinBlackRS17;JvControls;NxSheetRun_dxe3;IndyProtocols;DBXMySQLDriver;dxLayoutControlRS17;bindcompdbx;TeeUI;JvJans;JvPrintPreview;JvPageComps;JvStdCtrls;JvCustom;dxSkinOffice2007BlueRS17;dxPScxPivotGridLnkRS17;dxSpellCheckerRS17;vcltouch;dxSkinOffice2007GreenRS17;dxSkinSharpRS17;websnap;dxSkinFoggyRS17;dxTileControlRS17;VclSmp;FMXfrxDB17;dxSkinDarkSideRS17;cxPivotGridRS17;DataSnapConnectors;AnyDAC_Phys_D17;fmxobj;SynEdit_RXE3;JclVcl;cxTreeListRS17;dxPSdxFCLnkRS17;dxSkinGlassOceansRS17;frxe17;svn;dxFlowChartRS17;fmxdae;dxSkinsdxNavBarPainterRS17;bdertl;VirtualTreesR;DataSnapIndy10ServerTransport;dxDBXServerModeRS17;dxSkinCaramelRS17;$(DCC_UsePackage)</DCC_UsePackage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Win64)'!=''">
|
||||
<DCC_UsePackage>cxPivotGridChartRS17;JvMM;dxSkinSevenRS17;dxSkinBlueprintRS17;dxSkinHighContrastRS17;dxSkinOffice2007BlackRS17;dxCoreRS17;cxPageControldxBarPopupMenuRS17;dxSkinXmas2008BlueRS17;dxPSDBTeeChartRS17;JvCrypt;dxPSTeeChartRS17;dxSkinSummer2008RS17;dxPScxSchedulerLnkRS17;dxSkinBlueRS17;dxSkinDarkRoomRS17;DBXInterBaseDriver;DataSnapServer;DataSnapCommon;dxPScxTLLnkRS17;JvNet;dxRibbonRS17;DbxCommonDriver;cxDataRS17;vclimg;dxSkinsdxBarPainterRS17;dxPSdxDBTVLnkRS17;dbxcds;DatasnapConnectorsFreePascal;NxDBGridDsgn_dxe3;dxSkinMoneyTwinsRS17;vcldb;cxExportRS17;dxPSCoreRS17;dxBarExtItemsRS17;dxGDIPlusRS17;dxNavBarRS17;CustomIPTransport;cxLibraryRS17;cxGridRS17;dxSkinOffice2010BlackRS17;dsnap;IndyIPServer;IndyCore;dxSkinMcSkinRS17;dxPScxCommonRS17;AnyDAC_PhysDb2_D17;dxSkinsdxDLPainterRS17;dxSkiniMaginaryRS17;JvDB;dxPScxVGridLnkRS17;dxSkinSevenClassicRS17;dxPScxExtCommonRS17;dxPScxSSLnkRS17;NxGridRun_dxe3;dxSkinLilianRS17;dxPSdxLCLnkRS17;dxSkinOffice2010BlueRS17;NxCommonRun_dxe3;bindcompfmx;dxSkinOffice2010SilverRS17;cxSchedulerGridRS17;dbrtl;bindcomp;inetdb;JvPluginSystem;dxBarRS17;DBXOdbcDriver;JvCmp;dxBarDBNavRS17;dxSkinWhiteprintRS17;JvTimeFramework;xmlrtl;dxSkinsdxRibbonPainterRS17;ibxpress;dxDockingRS17;vclactnband;bindengine;soaprtl;dxADOServerModeRS17;bindcompvcl;dxBarExtDBItemsRS17;dxPSPrVwRibbonRS17;vclie;dxSkinOffice2007PinkRS17;cxPageControlRS17;dxSkinscxPCPainterRS17;AnyDAC_PhysADS_D17;AnyDAC_PhysIB_D17;dxmdsRS17;dxSkinTheAsphaltWorldRS17;DBXInformixDriver;dxPsPrVwAdvRS17;NxInspectorRun_dxe3;dxSkinSilverRS17;dxdborRS17;dsnapcon;DBXFirebirdDriver;inet;JvPascalInterpreter;vclx;dxSkinStardustRS17;cxEditorsRS17;DBXSybaseASADriver;NxInspectorDsgn_dxe3;dbexpress;IndyIPClient;AnyDAC_PhysMySQL_D17;cxTreeListdxBarPopupMenuRS17;dxSkinVS2010RS17;NxGridDsgn_dxe3;dxThemeRS17;DBXSqliteDriver;dxPScxGridLnkRS17;fmx;JvDlgs;IndySystem;TeeDB;dxSkinValentineRS17;vclib;DataSnapClient;dxSkinDevExpressStyleRS17;DataSnapProviderClient;DBXSybaseASEDriver;cxBarEditItemRS17;AnyDAC_PhysMSAcc_D17;dxServerModeRS17;cxPivotGridOLAPRS17;cxSchedulerRS17;AnyDAC_PhysSQLITE_D17;dxPSLnksRS17;dxSkinPumpkinRS17;dxPSdxDBOCLnkRS17;cxVerticalGridRS17;dxSkinSpringTimeRS17;vcldsnap;dxSkinDevExpressDarkStyleRS17;DBXDb2Driver;AnyDAC_ComI_D17;DBXOracleDriver;AnyDAC_PhysMSSQL_D17;JvCore;NxDBGridRun_dxe3;AnyDAC_Comp_D17;cxSpreadSheetRS17;dxSkinLiquidSkyRS17;AnyDAC_PhysODBC_D17;fmxase;vcl;dxSkinOffice2007SilverRS17;AnyDAC_PhysPg_D17;IndyIPCommon;DBXMSSQLDriver;dxPSdxOCLnkRS17;dcldxSkinsCoreRS17;JvAppFrm;AnyDAC_PhysASA_D17;inetdbxpress;webdsnap;NxCollectionRun_dxe3;AnyDAC_PhysOracle_D17;dxSkinCoffeeRS17;adortl;dxSkinscxSchedulerPainterRS17;JvWizards;NxCollectionDsgn_dxe3;NxCommonDsgn_dxe3;dxtrmdRS17;dxPScxPCProdRS17;AnyDAC_GUIxForms_D17;JvBands;rtl;DbxClientDriver;AnyDAC_PhysTDBX_D17;dxTabbedMDIRS17;dxComnRS17;dxSkinSharpPlusRS17;dxSkinsCoreRS17;dxSkinLondonLiquidSkyRS17;dxdbtrRS17;Tee;NxAddonsRun_dxe3;JvSystem;dxorgcRS17;dxSkinBlackRS17;JvControls;NxSheetRun_dxe3;IndyProtocols;DBXMySQLDriver;dxLayoutControlRS17;bindcompdbx;TeeUI;JvJans;JvPrintPreview;JvPageComps;JvStdCtrls;JvCustom;dxSkinOffice2007BlueRS17;dxPScxPivotGridLnkRS17;dxSpellCheckerRS17;vcltouch;dxSkinOffice2007GreenRS17;dxSkinSharpRS17;websnap;dxSkinFoggyRS17;dxTileControlRS17;VclSmp;dxSkinDarkSideRS17;cxPivotGridRS17;DataSnapConnectors;AnyDAC_Phys_D17;fmxobj;SynEdit_RXE3;cxTreeListRS17;dxPSdxFCLnkRS17;dxSkinGlassOceansRS17;dxFlowChartRS17;fmxdae;dxSkinsdxNavBarPainterRS17;DataSnapIndy10ServerTransport;dxDBXServerModeRS17;dxSkinCaramelRS17;$(DCC_UsePackage)</DCC_UsePackage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_1)'!=''">
|
||||
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
|
||||
<DCC_DebugDCUs>true</DCC_DebugDCUs>
|
||||
<DCC_Optimize>false</DCC_Optimize>
|
||||
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
|
||||
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
|
||||
<DCC_RemoteDebug>true</DCC_RemoteDebug>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
|
||||
<DCC_MapFile>3</DCC_MapFile>
|
||||
<DCC_ConsoleTarget>true</DCC_ConsoleTarget>
|
||||
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||
<DCC_RemoteDebug>false</DCC_RemoteDebug>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2)'!=''">
|
||||
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
|
||||
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
|
||||
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
|
||||
<DCC_DebugInformation>0</DCC_DebugInformation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
|
||||
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<DelphiCompile Include="$(MainSource)">
|
||||
<MainSource>MainSource</MainSource>
|
||||
</DelphiCompile>
|
||||
<DCCReference Include="WebModuleUnit1.pas">
|
||||
<Form>WebModule1</Form>
|
||||
<DesignClass>TWebModule</DesignClass>
|
||||
</DCCReference>
|
||||
<DCCReference Include="AppControllerU.pas"/>
|
||||
<DCCReference Include="AuthenticationU.pas"/>
|
||||
<BuildConfiguration Include="Release">
|
||||
<Key>Cfg_2</Key>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</BuildConfiguration>
|
||||
<BuildConfiguration Include="Base">
|
||||
<Key>Base</Key>
|
||||
</BuildConfiguration>
|
||||
<BuildConfiguration Include="Debug">
|
||||
<Key>Cfg_1</Key>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</BuildConfiguration>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
|
||||
<Borland.ProjectType/>
|
||||
<BorlandProject>
|
||||
<Delphi.Personality>
|
||||
<VersionInfo>
|
||||
<VersionInfo Name="IncludeVerInfo">False</VersionInfo>
|
||||
<VersionInfo Name="AutoIncBuild">False</VersionInfo>
|
||||
<VersionInfo Name="MajorVer">1</VersionInfo>
|
||||
<VersionInfo Name="MinorVer">0</VersionInfo>
|
||||
<VersionInfo Name="Release">0</VersionInfo>
|
||||
<VersionInfo Name="Build">0</VersionInfo>
|
||||
<VersionInfo Name="Debug">False</VersionInfo>
|
||||
<VersionInfo Name="PreRelease">False</VersionInfo>
|
||||
<VersionInfo Name="Special">False</VersionInfo>
|
||||
<VersionInfo Name="Private">False</VersionInfo>
|
||||
<VersionInfo Name="DLL">False</VersionInfo>
|
||||
<VersionInfo Name="Locale">1040</VersionInfo>
|
||||
<VersionInfo Name="CodePage">1252</VersionInfo>
|
||||
</VersionInfo>
|
||||
<VersionInfoKeys>
|
||||
<VersionInfoKeys Name="CompanyName"/>
|
||||
<VersionInfoKeys Name="FileDescription"/>
|
||||
<VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys>
|
||||
<VersionInfoKeys Name="InternalName"/>
|
||||
<VersionInfoKeys Name="LegalCopyright"/>
|
||||
<VersionInfoKeys Name="LegalTrademarks"/>
|
||||
<VersionInfoKeys Name="OriginalFilename"/>
|
||||
<VersionInfoKeys Name="ProductName"/>
|
||||
<VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys>
|
||||
<VersionInfoKeys Name="Comments"/>
|
||||
<VersionInfoKeys Name="CFBundleName"/>
|
||||
<VersionInfoKeys Name="CFBundleDisplayName"/>
|
||||
<VersionInfoKeys Name="CFBundleIdentifier"/>
|
||||
<VersionInfoKeys Name="CFBundleVersion"/>
|
||||
<VersionInfoKeys Name="CFBundlePackageType"/>
|
||||
<VersionInfoKeys Name="CFBundleSignature"/>
|
||||
<VersionInfoKeys Name="CFBundleAllowMixedLocalizations"/>
|
||||
<VersionInfoKeys Name="CFBundleExecutable"/>
|
||||
</VersionInfoKeys>
|
||||
<Source>
|
||||
<Source Name="MainSource">JWTServer.dpr</Source>
|
||||
</Source>
|
||||
<Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k240.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp240.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k240.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\dclofficexp240.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||
</Excluded_Packages>
|
||||
</Delphi.Personality>
|
||||
<Deployment Version="3">
|
||||
<DeployFile LocalName="Win32\Debug\JWTServer.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>JWTServer.exe</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployClass Name="AdditionalDebugSymbols">
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidClassesDexFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>classes</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidGDBServer">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidLibnativeArmeabiFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidLibnativeMipsFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\mips</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidLibnativeX86File"/>
|
||||
<DeployClass Name="AndroidServiceOutput">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidSplashImageDef">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidSplashStyles">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\values</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_DefaultAppIcon">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon144">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon36">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-ldpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon48">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-mdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon72">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-hdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon96">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage426">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-small</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage470">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-normal</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage640">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-large</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage960">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xlarge</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="DebugSymbols">
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="DependencyFramework">
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.framework</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="DependencyModule">
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
<Extensions>.dll;.bpl</Extensions>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Required="true" Name="DependencyPackage">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
<Extensions>.bpl</Extensions>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="File">
|
||||
<Platform Name="Android">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1024">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1536">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2048">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch768">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch320">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch640">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch640x1136">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectAndroidManifest">
|
||||
<Platform Name="Android">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSDeviceDebug">
|
||||
<Platform Name="iOSDevice32">
|
||||
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSDeviceResourceRules"/>
|
||||
<DeployClass Name="ProjectiOSEntitlements"/>
|
||||
<DeployClass Name="ProjectiOSInfoPList"/>
|
||||
<DeployClass Name="ProjectiOSResource">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectOSXEntitlements"/>
|
||||
<DeployClass Name="ProjectOSXInfoPList"/>
|
||||
<DeployClass Name="ProjectOSXResource">
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\Resources</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Required="true" Name="ProjectOutput">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Linux64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectUWPManifest">
|
||||
<Platform Name="Win32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="UWP_DelphiLogo150">
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win64">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="UWP_DelphiLogo44">
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win64">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
|
||||
</Deployment>
|
||||
<Platforms>
|
||||
<Platform value="Android">False</Platform>
|
||||
<Platform value="iOSDevice32">False</Platform>
|
||||
<Platform value="iOSDevice64">False</Platform>
|
||||
<Platform value="iOSSimulator">False</Platform>
|
||||
<Platform value="Win32">True</Platform>
|
||||
<Platform value="Win64">False</Platform>
|
||||
</Platforms>
|
||||
</BorlandProject>
|
||||
<ProjectFileVersion>12</ProjectFileVersion>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
|
||||
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
|
||||
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
|
||||
</Project>
|
BIN
samples/jsonwebtoken_livevaliditywindow/JWTServer.res
Normal file
BIN
samples/jsonwebtoken_livevaliditywindow/JWTServer.res
Normal file
Binary file not shown.
12
samples/jsonwebtoken_livevaliditywindow/WebModuleUnit1.dfm
Normal file
12
samples/jsonwebtoken_livevaliditywindow/WebModuleUnit1.dfm
Normal file
@ -0,0 +1,12 @@
|
||||
object WebModule1: TWebModule1
|
||||
OldCreateOrder = False
|
||||
OnCreate = WebModuleCreate
|
||||
Actions = <
|
||||
item
|
||||
Default = True
|
||||
Name = 'DefaultHandler'
|
||||
PathInfo = '/'
|
||||
end>
|
||||
Height = 230
|
||||
Width = 415
|
||||
end
|
71
samples/jsonwebtoken_livevaliditywindow/WebModuleUnit1.pas
Normal file
71
samples/jsonwebtoken_livevaliditywindow/WebModuleUnit1.pas
Normal file
@ -0,0 +1,71 @@
|
||||
unit WebModuleUnit1;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.Classes,
|
||||
Web.HTTPApp,
|
||||
MVCFramework,
|
||||
MVCFramework.Commons;
|
||||
|
||||
type
|
||||
TWebModule1 = class(TWebModule)
|
||||
procedure WebModuleCreate(Sender: TObject);
|
||||
|
||||
private
|
||||
MVC: TMVCEngine;
|
||||
|
||||
public
|
||||
{ Public declarations }
|
||||
end;
|
||||
|
||||
var
|
||||
WebModuleClass: TComponentClass = TWebModule1;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
|
||||
uses
|
||||
AppControllerU,
|
||||
System.Generics.Collections,
|
||||
AuthenticationU,
|
||||
MVCFramework.Middleware.JWT,
|
||||
MVCFramework.JWT,
|
||||
System.DateUtils;
|
||||
|
||||
procedure TWebModule1.WebModuleCreate(Sender: TObject);
|
||||
var
|
||||
lClaimsSetup: TJWTClaimsSetup;
|
||||
begin
|
||||
lClaimsSetup := procedure(const JWT: TJWT)
|
||||
begin
|
||||
JWT.Claims.Issuer := 'Delphi MVC Framework JWT Middleware Sample';
|
||||
JWT.Claims.NotBefore := Now - OneMinute * 5; // valid since 5 minutes ago
|
||||
JWT.Claims.IssuedAt := Now;
|
||||
JWT.CustomClaims['mycustomvalue'] := 'hello there';
|
||||
// Here we dont use a fixed ExpirationTime but a LiveValidityWindowInSeconds
|
||||
// to make the ExpirationTime dynamic, incrementing the
|
||||
// ExpirationTime by LiveValidityWindowInSeconds seconds at each request
|
||||
JWT.LiveValidityWindowInSeconds := 5; //60 * 60; // 1 hour
|
||||
end;
|
||||
|
||||
MVC := TMVCEngine.Create(Self);
|
||||
MVC.Config[TMVCConfigKey.DocumentRoot] := '..\..\www';
|
||||
MVC.Config[TMVCConfigKey.SessionTimeout] := '30';
|
||||
MVC.Config[TMVCConfigKey.DefaultContentType] := 'text/html';
|
||||
MVC.AddController(TApp1MainController).AddController(TAdminController)
|
||||
.AddMiddleware(TMVCJWTAuthenticationMiddleware.Create(
|
||||
TAuthenticationSample.Create,
|
||||
lClaimsSetup,
|
||||
'mys3cr37',
|
||||
[
|
||||
TJWTCheckableClaim.ExpirationTime,
|
||||
TJWTCheckableClaim.NotBefore,
|
||||
TJWTCheckableClaim.IssuedAt
|
||||
], 0));
|
||||
end;
|
||||
|
||||
end.
|
48
samples/jsonwebtoken_livevaliditywindow/pgJWT.groupproj
Normal file
48
samples/jsonwebtoken_livevaliditywindow/pgJWT.groupproj
Normal file
@ -0,0 +1,48 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{517F9067-355C-443F-9B0D-95E2E904C708}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Projects Include="JWTServer.dproj">
|
||||
<Dependencies/>
|
||||
</Projects>
|
||||
<Projects Include="vclclient\JWTClient.dproj">
|
||||
<Dependencies/>
|
||||
</Projects>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<Borland.Personality>Default.Personality.12</Borland.Personality>
|
||||
<Borland.ProjectType/>
|
||||
<BorlandProject>
|
||||
<Default.Personality/>
|
||||
</BorlandProject>
|
||||
</ProjectExtensions>
|
||||
<Target Name="JWTServer">
|
||||
<MSBuild Projects="JWTServer.dproj"/>
|
||||
</Target>
|
||||
<Target Name="JWTServer:Clean">
|
||||
<MSBuild Projects="JWTServer.dproj" Targets="Clean"/>
|
||||
</Target>
|
||||
<Target Name="JWTServer:Make">
|
||||
<MSBuild Projects="JWTServer.dproj" Targets="Make"/>
|
||||
</Target>
|
||||
<Target Name="JWTClient">
|
||||
<MSBuild Projects="vclclient\JWTClient.dproj"/>
|
||||
</Target>
|
||||
<Target Name="JWTClient:Clean">
|
||||
<MSBuild Projects="vclclient\JWTClient.dproj" Targets="Clean"/>
|
||||
</Target>
|
||||
<Target Name="JWTClient:Make">
|
||||
<MSBuild Projects="vclclient\JWTClient.dproj" Targets="Make"/>
|
||||
</Target>
|
||||
<Target Name="Build">
|
||||
<CallTarget Targets="JWTServer;JWTClient"/>
|
||||
</Target>
|
||||
<Target Name="Clean">
|
||||
<CallTarget Targets="JWTServer:Clean;JWTClient:Clean"/>
|
||||
</Target>
|
||||
<Target Name="Make">
|
||||
<CallTarget Targets="JWTServer:Make;JWTClient:Make"/>
|
||||
</Target>
|
||||
<Import Project="$(BDS)\Bin\CodeGear.Group.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Group.Targets')"/>
|
||||
</Project>
|
@ -0,0 +1,14 @@
|
||||
program JWTClient;
|
||||
|
||||
uses
|
||||
Vcl.Forms,
|
||||
MainClientFormU in 'MainClientFormU.pas' {MainForm};
|
||||
|
||||
{$R *.res}
|
||||
|
||||
begin
|
||||
Application.Initialize;
|
||||
Application.MainFormOnTaskbar := True;
|
||||
Application.CreateForm(TMainForm, MainForm);
|
||||
Application.Run;
|
||||
end.
|
@ -0,0 +1,574 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{E7317702-64D3-4A65-8734-030F3AE3DBBC}</ProjectGuid>
|
||||
<ProjectVersion>18.2</ProjectVersion>
|
||||
<FrameworkType>VCL</FrameworkType>
|
||||
<MainSource>JWTClient.dpr</MainSource>
|
||||
<Base>True</Base>
|
||||
<Config Condition="'$(Config)'==''">Debug</Config>
|
||||
<Platform Condition="'$(Platform)'==''">Win32</Platform>
|
||||
<TargetedPlatforms>1</TargetedPlatforms>
|
||||
<AppType>Application</AppType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
|
||||
<Base_Win32>true</Base_Win32>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win64' and '$(Base)'=='true') or '$(Base_Win64)'!=''">
|
||||
<Base_Win64>true</Base_Win64>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
|
||||
<Cfg_1>true</Cfg_1>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
|
||||
<Cfg_1_Win32>true</Cfg_1_Win32>
|
||||
<CfgParent>Cfg_1</CfgParent>
|
||||
<Cfg_1>true</Cfg_1>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
|
||||
<Cfg_2>true</Cfg_2>
|
||||
<CfgParent>Base</CfgParent>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
|
||||
<Cfg_2_Win32>true</Cfg_2_Win32>
|
||||
<CfgParent>Cfg_2</CfgParent>
|
||||
<Cfg_2>true</Cfg_2>
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base)'!=''">
|
||||
<VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys>
|
||||
<VerInfo_Locale>1040</VerInfo_Locale>
|
||||
<DCC_UnitSearchPath>..\..\..\sources;..\..\..\lib\delphistompclient;..\..\..\lib\loggerpro;..\..\..\lib\dmustache;$(DCC_UnitSearchPath)</DCC_UnitSearchPath>
|
||||
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
|
||||
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
|
||||
<SanitizedProjectName>JWTClient</SanitizedProjectName>
|
||||
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
|
||||
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
|
||||
<DCC_E>false</DCC_E>
|
||||
<DCC_N>false</DCC_N>
|
||||
<DCC_S>false</DCC_S>
|
||||
<DCC_F>false</DCC_F>
|
||||
<DCC_K>false</DCC_K>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Win32)'!=''">
|
||||
<UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
|
||||
<UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
|
||||
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
|
||||
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
|
||||
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
|
||||
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||
<DCC_UsePackage>DBXSqliteDriver;DBXDb2Driver;dxCoreRS23;vclactnband;frxe23;vclFireDAC;dxPSLnksRS23;dxPSdxLCLnkRS23;tethering;cxDataRS23;dxPSdxOCLnkRS23;dxTabbedMDIRS23;FireDACADSDriver;dxSkinBlackRS23;dxSkinLondonLiquidSkyRS23;JvPluginSystem;dxDBXServerModeRS23;dxHttpIndyRequestRS23;dxPScxGridLnkRS23;cxSchedulerRS23;FireDACMSSQLDriver;dclRBDBE1723;vcltouch;JvBands;vcldb;rbDB1723;svn;dxWizardControlRS23;dxSkinMcSkinRS23;dxPScxCommonRS23;JvJans;Intraweb;dxSkinOffice2007BlueRS23;rbIBE1723;dxBarRS23;cxSchedulerRibbonStyleEventEditorRS23;dxSkinOffice2013WhiteRS23;JvDotNetCtrls;dxPSTeeChartRS23;cxLibraryRS23;dxSkinVisualStudio2013LightRS23;vclib;cxPivotGridChartRS23;rbDBE1723;dxSkinSummer2008RS23;dxPSdxDBOCLnkRS23;dxGDIPlusRS23;dxSkinDarkSideRS23;FireDACDBXDriver;dxSkinFoggyRS23;dxSkinSevenRS23;vclx;rbCIDE1723;dxSkinOffice2010SilverRS23;dxdborRS23;RESTBackendComponents;dxLayoutControlRS23;dxPSPrVwRibbonRS23;VCLRESTComponents;dxSkinDevExpressStyleRS23;dxSkinWhiteprintRS23;vclie;bindengine;CloudService;rbRAP1723;JvHMI;FireDACMySQLDriver;dxSkinOffice2013DarkGrayRS23;DataSnapClient;dxPScxPCProdRS23;bindcompdbx;DBXSybaseASEDriver;IndyIPServer;dxSkinPumpkinRS23;IndySystem;dsnapcon;cxTreeListdxBarPopupMenuRS23;dclRBIBE1723;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;dxSkinLilianRS23;Jcl;rbADO1723;dxBarDBNavRS23;dxFlowChartRS23;dxSkinOffice2016ColorfulRS23;rbUSER1723;DBXOdbcDriver;FireDACTDataDriver;FMXTee;ipstudiowinclient;soaprtl;DbxCommonDriver;dxSpreadSheetRS23;AsyncProDR;JvManagedThreads;dxSkinOffice2007PinkRS23;dxPSdxSpreadSheetLnkRS23;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;DTKANPRPackage;dxSkinHighContrastRS23;rtl;dxSkinSevenClassicRS23;DbxClientDriver;dxSkinDevExpressDarkStyleRS23;DBXSybaseASADriver;dxNavBarRS23;dxSkinMetropolisDarkRS23;CodeSiteExpressPkg;dxSkinTheAsphaltWorldRS23;JvSystem;SampleListViewMultiDetailAppearancePackage;dxRichEditControlRS23;JvStdCtrls;JvTimeFramework;ipstudiowin;appanalytics;cxPivotGridRS23;rbUSERDesign1723;dxSkinsdxDLPainterRS23;IndyIPClient;dxRibbonRS23;dxPScxVGridLnkRS23;bindcompvcl;frxDB23;vcldbx;dxSkinOffice2007SilverRS23;dxPScxTLLnkRS23;dxMapControlRS23;TeeUI;rbDIDE1723;JvPascalInterpreter;JvDocking;VclSmp;dxPScxSchedulerLnkRS23;cxTreeListRS23;FireDACODBCDriver;JclVcl;DataSnapIndy10ServerTransport;dxRibbonCustomizationFormRS23;dxPSRichEditControlLnkRS23;dxBarExtDBItemsRS23;DataSnapProviderClient;FireDACMongoDBDriver;dxSkiniMaginaryRS23;frx23;dxSpellCheckerRS23;JvControls;dxSkinsdxBarPainterRS23;JvPrintPreview;dxSkinCoffeeRS23;DataSnapServerMidas;RESTComponents;DBXInterBaseDriver;rbRTL1723;dxADOServerModeRS23;emsclientfiredac;DataSnapFireDAC;svnui;dxmdsRS23;dxSkinLiquidSkyRS23;dxdbtrRS23;dxSkinSpringTimeRS23;dxPSDBTeeChartRS23;JvGlobus;dxSkinscxPCPainterRS23;dxPSCoreRS23;DBXMSSQLDriver;JvMM;dxSkinXmas2008BlueRS23;rbDAD1723;DatasnapConnectorsFreePascal;bindcompfmx;JvNet;DBXOracleDriver;dxSkinSilverRS23;dxSkinValentineRS23;inetdb;JvAppFrm;ipstudiowinwordxp;rbTC1723;FmxTeeUI;dxBarExtItemsRS23;FireDACIBDriver;fmx;fmxdae;DelphiCookbookListViewAppearance;dxServerModeRS23;dxPsPrVwAdvRS23;dxSkinOffice2010BlackRS23;JvWizards;cxPageControlRS23;dxSkinStardustRS23;cxSchedulerGridRS23;dbexpress;IndyCore;dxSkinSharpPlusRS23;UIBD21Win32R;JvPageComps;dsnap;DataSnapCommon;emsclient;FireDACCommon;dxSkinOffice2010BlueRS23;bdertl;JvDB;dxSkinVS2010RS23;dxSkinMetropolisRS23;DataSnapConnectors;cxVerticalGridRS23;soapserver;dxSkinCaramelRS23;frxTee23;dxTileControlRS23;JclDeveloperTools;cxGridRS23;CPortLibDXE;FireDACOracleDriver;DBXMySQLDriver;JvCmp;rbFireDAC1723;DBXFirebirdDriver;FireDACCommonDriver;rbTCUI1723;LockBoxDR;inet;IndyIPCommon;JvCustom;dxSkinDarkRoomRS23;dxDockingRS23;vcl;dxSkinOffice2007GreenRS23;dxPScxExtCommonRS23;JvXPCtrls;dxSkinsCoreRS23;FireDACDb2Driver;dxThemeRS23;dxSkinsdxRibbonPainterRS23;dxSkinVisualStudio2013BlueRS23;rbRest1723;TSG5201;dxSkinMoneyTwinsRS23;dxPSdxFCLnkRS23;dxtrmdRS23;TeeDB;FireDAC;cxSchedulerTreeBrowserRS23;JvCore;dxFireDACServerModeRS23;dxSkinBlueRS23;OverbyteIcsD10SRun;JvCrypt;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;cxEditorsRS23;dxSkinGlassOceansRS23;JvDlgs;JvRuntimeDesign;dxSkinsdxNavBarPainterRS23;dxGaugeControlRS23;ibxpress;Tee;dxSkinSharpRS23;DataSnapServer;ibxbindings;cxPivotGridOLAPRS23;rbIDE1723;vclwinx;FireDACDSDriver;dxSkinBlueprintRS23;dxSkinOffice2007BlackRS23;CustomIPTransport;vcldsnap;rbBDE1723;dxSkinOffice2013LightGrayRS23;bindcomp;DBXInformixDriver;officeXPrt;dxPSdxGaugeControlLnkRS23;dxPScxPivotGridLnkRS23;dxorgcRS23;dxPSdxDBTVLnkRS23;dclRBADO1723;vclribbon;dbxcds;KernowSoftwareFMX;adortl;dclRBFireDAC1723;dclRBE1723;dxComnRS23;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;cxExportRS23;dxSkinOffice2016DarkRS23;JclContainers;dxSkinVisualStudio2013DarkRS23;rbRCL1723;dxSkinscxSchedulerPainterRS23;rbRIDE1723;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
|
||||
<VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(ModuleName);FileDescription=$(ModuleName);ProductName=$(ModuleName)</VerInfo_Keys>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base_Win64)'!=''">
|
||||
<UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
|
||||
<UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
|
||||
<DCC_UsePackage>DBXSqliteDriver;DBXDb2Driver;dxCoreRS23;vclactnband;vclFireDAC;dxPSLnksRS23;dxPSdxLCLnkRS23;tethering;cxDataRS23;dxPSdxOCLnkRS23;dxTabbedMDIRS23;FireDACADSDriver;dxSkinBlackRS23;dxSkinLondonLiquidSkyRS23;dxDBXServerModeRS23;dxHttpIndyRequestRS23;dxPScxGridLnkRS23;cxSchedulerRS23;FireDACMSSQLDriver;vcltouch;vcldb;dxWizardControlRS23;dxSkinMcSkinRS23;dxPScxCommonRS23;Intraweb;dxSkinOffice2007BlueRS23;dxBarRS23;cxSchedulerRibbonStyleEventEditorRS23;dxSkinOffice2013WhiteRS23;dxPSTeeChartRS23;cxLibraryRS23;dxSkinVisualStudio2013LightRS23;vclib;cxPivotGridChartRS23;dxSkinSummer2008RS23;dxPSdxDBOCLnkRS23;dxGDIPlusRS23;dxSkinDarkSideRS23;FireDACDBXDriver;dxSkinFoggyRS23;dxSkinSevenRS23;vclx;dxSkinOffice2010SilverRS23;dxdborRS23;RESTBackendComponents;dxLayoutControlRS23;dxPSPrVwRibbonRS23;VCLRESTComponents;dxSkinDevExpressStyleRS23;dxSkinWhiteprintRS23;vclie;bindengine;CloudService;FireDACMySQLDriver;dxSkinOffice2013DarkGrayRS23;DataSnapClient;dxPScxPCProdRS23;bindcompdbx;DBXSybaseASEDriver;IndyIPServer;dxSkinPumpkinRS23;IndySystem;dsnapcon;cxTreeListdxBarPopupMenuRS23;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;dxSkinLilianRS23;dxBarDBNavRS23;dxFlowChartRS23;dxSkinOffice2016ColorfulRS23;DBXOdbcDriver;FireDACTDataDriver;FMXTee;ipstudiowinclient;soaprtl;DbxCommonDriver;dxSpreadSheetRS23;AsyncProDR;dxSkinOffice2007PinkRS23;dxPSdxSpreadSheetLnkRS23;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;dxSkinHighContrastRS23;rtl;dxSkinSevenClassicRS23;DbxClientDriver;dxSkinDevExpressDarkStyleRS23;DBXSybaseASADriver;dxNavBarRS23;dxSkinMetropolisDarkRS23;dxSkinTheAsphaltWorldRS23;dxRichEditControlRS23;ipstudiowin;appanalytics;cxPivotGridRS23;dxSkinsdxDLPainterRS23;IndyIPClient;dxRibbonRS23;dxPScxVGridLnkRS23;bindcompvcl;dxSkinOffice2007SilverRS23;dxPScxTLLnkRS23;dxMapControlRS23;TeeUI;VclSmp;dxPScxSchedulerLnkRS23;cxTreeListRS23;FireDACODBCDriver;DataSnapIndy10ServerTransport;dxRibbonCustomizationFormRS23;dxPSRichEditControlLnkRS23;dxBarExtDBItemsRS23;DataSnapProviderClient;FireDACMongoDBDriver;dxSkiniMaginaryRS23;dxSpellCheckerRS23;dxSkinsdxBarPainterRS23;dxSkinCoffeeRS23;DataSnapServerMidas;RESTComponents;DBXInterBaseDriver;dxADOServerModeRS23;emsclientfiredac;DataSnapFireDAC;dxmdsRS23;dxSkinLiquidSkyRS23;dxdbtrRS23;dxSkinSpringTimeRS23;dxPSDBTeeChartRS23;dxSkinscxPCPainterRS23;dxPSCoreRS23;DBXMSSQLDriver;dxSkinXmas2008BlueRS23;DatasnapConnectorsFreePascal;bindcompfmx;DBXOracleDriver;dxSkinSilverRS23;dxSkinValentineRS23;inetdb;FmxTeeUI;dxBarExtItemsRS23;FireDACIBDriver;fmx;fmxdae;dxServerModeRS23;dxPsPrVwAdvRS23;dxSkinOffice2010BlackRS23;cxPageControlRS23;dxSkinStardustRS23;cxSchedulerGridRS23;dbexpress;IndyCore;dxSkinSharpPlusRS23;dsnap;DataSnapCommon;emsclient;FireDACCommon;dxSkinOffice2010BlueRS23;dxSkinVS2010RS23;dxSkinMetropolisRS23;DataSnapConnectors;cxVerticalGridRS23;soapserver;dxSkinCaramelRS23;dxTileControlRS23;cxGridRS23;FireDACOracleDriver;DBXMySQLDriver;DBXFirebirdDriver;FireDACCommonDriver;LockBoxDR;inet;IndyIPCommon;dxSkinDarkRoomRS23;dxDockingRS23;vcl;dxSkinOffice2007GreenRS23;dxPScxExtCommonRS23;dxSkinsCoreRS23;FireDACDb2Driver;dxThemeRS23;dxSkinsdxRibbonPainterRS23;dxSkinVisualStudio2013BlueRS23;dxSkinMoneyTwinsRS23;dxPSdxFCLnkRS23;dxtrmdRS23;TeeDB;FireDAC;cxSchedulerTreeBrowserRS23;dxFireDACServerModeRS23;dxSkinBlueRS23;OverbyteIcsD10SRun;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;cxEditorsRS23;dxSkinGlassOceansRS23;dxSkinsdxNavBarPainterRS23;dxGaugeControlRS23;ibxpress;Tee;dxSkinSharpRS23;DataSnapServer;ibxbindings;cxPivotGridOLAPRS23;vclwinx;FireDACDSDriver;dxSkinBlueprintRS23;dxSkinOffice2007BlackRS23;CustomIPTransport;vcldsnap;dxSkinOffice2013LightGrayRS23;bindcomp;DBXInformixDriver;officeXPrt;dxPSdxGaugeControlLnkRS23;dxPScxPivotGridLnkRS23;dxorgcRS23;dxPSdxDBTVLnkRS23;vclribbon;dbxcds;adortl;dxComnRS23;dsnapxml;dbrtl;inetdbxpress;IndyProtocols;cxExportRS23;dxSkinOffice2016DarkRS23;dxSkinVisualStudio2013DarkRS23;dxSkinscxSchedulerPainterRS23;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_1)'!=''">
|
||||
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
|
||||
<DCC_DebugDCUs>true</DCC_DebugDCUs>
|
||||
<DCC_Optimize>false</DCC_Optimize>
|
||||
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
|
||||
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
|
||||
<DCC_RemoteDebug>true</DCC_RemoteDebug>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
|
||||
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
|
||||
<VerInfo_Keys>CompanyName=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductVersion=1.0.0.0;Comments=;ProgramID=com.embarcadero.$(MSBuildProjectName);FileDescription=$(MSBuildProjectName);ProductName=$(MSBuildProjectName)</VerInfo_Keys>
|
||||
<VerInfo_Locale>1033</VerInfo_Locale>
|
||||
<BT_BuildType>Debug</BT_BuildType>
|
||||
<AppEnableHighDPI>true</AppEnableHighDPI>
|
||||
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
|
||||
<DCC_RemoteDebug>false</DCC_RemoteDebug>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2)'!=''">
|
||||
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
|
||||
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
|
||||
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
|
||||
<DCC_DebugInformation>0</DCC_DebugInformation>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
|
||||
<AppEnableHighDPI>true</AppEnableHighDPI>
|
||||
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<DelphiCompile Include="$(MainSource)">
|
||||
<MainSource>MainSource</MainSource>
|
||||
</DelphiCompile>
|
||||
<DCCReference Include="MainClientFormU.pas">
|
||||
<Form>MainForm</Form>
|
||||
<FormType>dfm</FormType>
|
||||
</DCCReference>
|
||||
<BuildConfiguration Include="Release">
|
||||
<Key>Cfg_2</Key>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</BuildConfiguration>
|
||||
<BuildConfiguration Include="Base">
|
||||
<Key>Base</Key>
|
||||
</BuildConfiguration>
|
||||
<BuildConfiguration Include="Debug">
|
||||
<Key>Cfg_1</Key>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</BuildConfiguration>
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
|
||||
<Borland.ProjectType>Application</Borland.ProjectType>
|
||||
<BorlandProject>
|
||||
<Delphi.Personality>
|
||||
<Source>
|
||||
<Source Name="MainSource">JWTClient.dpr</Source>
|
||||
</Source>
|
||||
<Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\bcboffice2k240.bpl">Embarcadero C++Builder Office 2000 Servers Package</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\bcbofficexp240.bpl">Embarcadero C++Builder Office XP Servers Package</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\dcloffice2k240.bpl">Microsoft Office 2000 Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDSBIN)\dclofficexp240.bpl">Microsoft Office XP Sample Automation Server Wrapper Components</Excluded_Packages>
|
||||
</Excluded_Packages>
|
||||
</Delphi.Personality>
|
||||
<Deployment Version="3">
|
||||
<DeployFile LocalName="Win32\Debug\JWTClient.exe" Configuration="Debug" Class="ProjectOutput">
|
||||
<Platform Name="Win32">
|
||||
<RemoteName>JWTClient.exe</RemoteName>
|
||||
<Overwrite>true</Overwrite>
|
||||
</Platform>
|
||||
</DeployFile>
|
||||
<DeployClass Name="AdditionalDebugSymbols">
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidClassesDexFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>classes</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidGDBServer">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidLibnativeArmeabiFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidLibnativeMipsFile">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\mips</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidLibnativeX86File"/>
|
||||
<DeployClass Name="AndroidServiceOutput">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidSplashImageDef">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="AndroidSplashStyles">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\values</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_DefaultAppIcon">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon144">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon36">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-ldpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon48">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-mdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon72">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-hdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_LauncherIcon96">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xhdpi</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage426">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-small</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage470">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-normal</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage640">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-large</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="Android_SplashImage960">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>res\drawable-xlarge</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="DebugSymbols">
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="DependencyFramework">
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.framework</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="DependencyModule">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
<Extensions>.dll;.bpl</Extensions>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Required="true" Name="DependencyPackage">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
<Extensions>.dylib</Extensions>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
<Extensions>.bpl</Extensions>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="File">
|
||||
<Platform Name="Android">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1024">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch1536">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch2048">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPad_Launch768">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch320">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch640">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="iPhone_Launch640x1136">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectAndroidManifest">
|
||||
<Platform Name="Android">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSDeviceDebug">
|
||||
<Platform Name="iOSDevice32">
|
||||
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSDeviceResourceRules">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSEntitlements">
|
||||
<Platform Name="iOSDevice32">
|
||||
<RemoteDir>..\</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<RemoteDir>..\</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSInfoPList">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectiOSResource">
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectOSXEntitlements">
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>..\</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectOSXInfoPList">
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectOSXResource">
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\Resources</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Required="true" Name="ProjectOutput">
|
||||
<Platform Name="Android">
|
||||
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSDevice64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="iOSSimulator">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Linux64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="OSX32">
|
||||
<RemoteDir>Contents\MacOS</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win32">
|
||||
<Operation>0</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="ProjectUWPManifest">
|
||||
<Platform Name="Win32">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win64">
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="UWP_DelphiLogo150">
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win64">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<DeployClass Name="UWP_DelphiLogo44">
|
||||
<Platform Name="Win32">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
<Platform Name="Win64">
|
||||
<RemoteDir>Assets</RemoteDir>
|
||||
<Operation>1</Operation>
|
||||
</Platform>
|
||||
</DeployClass>
|
||||
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
|
||||
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
|
||||
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
|
||||
</Deployment>
|
||||
<Platforms>
|
||||
<Platform value="Win32">True</Platform>
|
||||
<Platform value="Win64">False</Platform>
|
||||
</Platforms>
|
||||
</BorlandProject>
|
||||
<ProjectFileVersion>12</ProjectFileVersion>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
|
||||
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
|
||||
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
|
||||
</Project>
|
BIN
samples/jsonwebtoken_livevaliditywindow/vclclient/JWTClient.res
Normal file
BIN
samples/jsonwebtoken_livevaliditywindow/vclclient/JWTClient.res
Normal file
Binary file not shown.
@ -0,0 +1,110 @@
|
||||
object MainForm: TMainForm
|
||||
Left = 0
|
||||
Top = 0
|
||||
Caption = 'JWT with LiveValidityWindow feature'
|
||||
ClientHeight = 379
|
||||
ClientWidth = 721
|
||||
Color = clBtnFace
|
||||
Font.Charset = DEFAULT_CHARSET
|
||||
Font.Color = clWindowText
|
||||
Font.Height = -11
|
||||
Font.Name = 'Tahoma'
|
||||
Font.Style = []
|
||||
OldCreateOrder = False
|
||||
PixelsPerInch = 96
|
||||
TextHeight = 13
|
||||
object Splitter1: TSplitter
|
||||
Left = 0
|
||||
Top = 179
|
||||
Width = 721
|
||||
Height = 3
|
||||
Cursor = crVSplit
|
||||
Align = alTop
|
||||
ExplicitTop = 147
|
||||
ExplicitWidth = 30
|
||||
end
|
||||
object Memo1: TMemo
|
||||
Left = 0
|
||||
Top = 81
|
||||
Width = 721
|
||||
Height = 98
|
||||
Align = alTop
|
||||
Font.Charset = ANSI_CHARSET
|
||||
Font.Color = clWindowText
|
||||
Font.Height = -13
|
||||
Font.Name = 'Courier New'
|
||||
Font.Style = []
|
||||
ParentFont = False
|
||||
ReadOnly = True
|
||||
TabOrder = 0
|
||||
ExplicitTop = 49
|
||||
ExplicitWidth = 513
|
||||
end
|
||||
object Memo2: TMemo
|
||||
Left = 0
|
||||
Top = 182
|
||||
Width = 721
|
||||
Height = 197
|
||||
Align = alClient
|
||||
Font.Charset = ANSI_CHARSET
|
||||
Font.Color = clWindowText
|
||||
Font.Height = -13
|
||||
Font.Name = 'Courier New'
|
||||
Font.Style = []
|
||||
ParentFont = False
|
||||
ReadOnly = True
|
||||
TabOrder = 1
|
||||
ExplicitTop = 150
|
||||
ExplicitWidth = 513
|
||||
ExplicitHeight = 229
|
||||
end
|
||||
object Panel1: TPanel
|
||||
Left = 0
|
||||
Top = 0
|
||||
Width = 721
|
||||
Height = 81
|
||||
Align = alTop
|
||||
TabOrder = 2
|
||||
object Label1: TLabel
|
||||
AlignWithMargins = True
|
||||
Left = 338
|
||||
Top = 4
|
||||
Width = 379
|
||||
Height = 73
|
||||
Align = alClient
|
||||
Caption =
|
||||
'At each authenticated request, the server increments the "exp" p' +
|
||||
'roperty of the JWT of LiveValidityWindowInSeconds seconds. So th' +
|
||||
'at a JWT doesn'#39't expire never if used at least one time in LiveV' +
|
||||
'alidityWindowInSeconds seconds. It is useful to mimic the classi' +
|
||||
'c session cookie with the semplicity of the JWT.'
|
||||
WordWrap = True
|
||||
ExplicitWidth = 368
|
||||
ExplicitHeight = 65
|
||||
end
|
||||
object btnGet: TButton
|
||||
AlignWithMargins = True
|
||||
Left = 171
|
||||
Top = 4
|
||||
Width = 161
|
||||
Height = 73
|
||||
Align = alLeft
|
||||
Caption = 'Get a protected resource (with an updated JWT)'
|
||||
TabOrder = 0
|
||||
WordWrap = True
|
||||
OnClick = btnGetClick
|
||||
end
|
||||
object btnLOGIN: TButton
|
||||
AlignWithMargins = True
|
||||
Left = 4
|
||||
Top = 4
|
||||
Width = 161
|
||||
Height = 73
|
||||
Align = alLeft
|
||||
Caption = 'Login'
|
||||
TabOrder = 1
|
||||
OnClick = btnLOGINClick
|
||||
ExplicitHeight = 41
|
||||
end
|
||||
end
|
||||
end
|
@ -0,0 +1,114 @@
|
||||
unit MainClientFormU;
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
|
||||
System.Classes, Vcl.Graphics,
|
||||
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
|
||||
|
||||
type
|
||||
TMainForm = class(TForm)
|
||||
Memo1: TMemo;
|
||||
Memo2: TMemo;
|
||||
Panel1: TPanel;
|
||||
btnGet: TButton;
|
||||
btnLOGIN: TButton;
|
||||
Splitter1: TSplitter;
|
||||
Label1: TLabel;
|
||||
procedure btnGetClick(Sender: TObject);
|
||||
procedure btnLOGINClick(Sender: TObject);
|
||||
private
|
||||
FJWT: string;
|
||||
procedure SetJWT(const Value: string);
|
||||
property JWT: string read FJWT write SetJWT;
|
||||
public
|
||||
{ Public declarations }
|
||||
end;
|
||||
|
||||
var
|
||||
MainForm: TMainForm;
|
||||
|
||||
implementation
|
||||
|
||||
{$R *.dfm}
|
||||
|
||||
|
||||
uses
|
||||
MVCFramework.RESTClient,
|
||||
MVCFramework.SystemJSONUtils,
|
||||
MVCFramework.TypesAliases,
|
||||
System.NetEncoding;
|
||||
|
||||
procedure TMainForm.btnGetClick(Sender: TObject);
|
||||
var
|
||||
lClient: TRESTClient;
|
||||
lResp: IRESTResponse;
|
||||
lQueryStringParams: TStringList;
|
||||
tokenOld, tokenNew: string; // NEW CODE
|
||||
begin
|
||||
tokenOld := FJWT; // NEW CODE
|
||||
lClient := TRESTClient.Create('localhost', 8080);
|
||||
try
|
||||
lClient.ReadTimeOut(0);
|
||||
if not FJWT.IsEmpty then
|
||||
lClient.RequestHeaders.Values['Authentication'] := 'bearer ' + FJWT;
|
||||
lQueryStringParams := TStringList.Create;
|
||||
try
|
||||
lQueryStringParams.Values['firstname'] := 'Daniele';
|
||||
lQueryStringParams.Values['lastname'] := 'Teti';
|
||||
lResp := lClient.doGET('/admin/role1', [], lQueryStringParams);
|
||||
|
||||
if lResp.HasError then
|
||||
ShowMessage(lResp.Error.ExceptionMessage);
|
||||
|
||||
finally
|
||||
lQueryStringParams.Free;
|
||||
end;
|
||||
Memo2.Lines.Text := lResp.BodyAsString;
|
||||
|
||||
// NEW CODE
|
||||
tokenNew := lResp.HeaderValue('Authentication');
|
||||
if tokenNew.StartsWith('bearer', True) then
|
||||
begin
|
||||
tokenNew := tokenNew.Remove(0, 'bearer'.Length).Trim;
|
||||
tokenNew := TNetEncoding.URL.URLDecode(tokenNew).Trim;
|
||||
JWT := tokenNew;
|
||||
end; // END NEW CODE
|
||||
finally
|
||||
lClient.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.btnLOGINClick(Sender: TObject);
|
||||
var
|
||||
lClient: TRESTClient;
|
||||
lRest: IRESTResponse;
|
||||
lJSON: TJSONObject;
|
||||
begin
|
||||
lClient := TRESTClient.Create('localhost', 8080);
|
||||
try
|
||||
lClient.ReadTimeOut(0);
|
||||
lClient
|
||||
.Header('jwtusername', 'user1')
|
||||
.Header('jwtpassword', 'user1');
|
||||
lRest := lClient.doPOST('/login', []);
|
||||
lJSON := TSystemJSON.StringAsJSONObject(lRest.BodyAsString);
|
||||
try
|
||||
JWT := lJSON.GetValue('token').Value;
|
||||
finally
|
||||
lJSON.Free;
|
||||
end;
|
||||
finally
|
||||
lClient.Free;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMainForm.SetJWT(const Value: string);
|
||||
begin
|
||||
FJWT := Value;
|
||||
Memo1.Lines.Text := Value;
|
||||
|
||||
end;
|
||||
|
||||
end.
|
@ -44,13 +44,13 @@ type
|
||||
TJWTRegisteredClaimNames = class sealed
|
||||
public
|
||||
const
|
||||
Issuer: String = 'iss';
|
||||
Subject: String = 'sub';
|
||||
Audience: String = 'aud';
|
||||
ExpirationTime: String = 'exp';
|
||||
NotBefore: String = 'nbf';
|
||||
IssuedAt: String = 'iat';
|
||||
JWT_ID: String = 'jti';
|
||||
Issuer: string = 'iss';
|
||||
Subject: string = 'sub';
|
||||
Audience: string = 'aud';
|
||||
ExpirationTime: string = 'exp';
|
||||
NotBefore: string = 'nbf';
|
||||
IssuedAt: string = 'iat';
|
||||
JWT_ID: string = 'jti';
|
||||
Names: array [0 .. 6] of string = (
|
||||
'iss',
|
||||
'sub',
|
||||
@ -64,15 +64,15 @@ type
|
||||
TJWTDictionaryObject = class
|
||||
private
|
||||
FClaims: TDictionary<string, string>;
|
||||
function GetItem(const Index: String): String;
|
||||
procedure SetItem(const Index, Value: String);
|
||||
function GetItemAsDateTime(const Index: String): TDateTime;
|
||||
procedure SetItemAsDateTime(const Index: String; const Value: TDateTime);
|
||||
property ItemsAsDateTime[const Index: String]: TDateTime read GetItemAsDateTime write SetItemAsDateTime;
|
||||
property Items[const Index: String]: String read GetItem write SetItem; default;
|
||||
function GetItem(const Index: string): string;
|
||||
procedure SetItem(const Index, Value: string);
|
||||
function GetItemAsDateTime(const Index: string): TDateTime;
|
||||
procedure SetItemAsDateTime(const Index: string; const Value: TDateTime);
|
||||
property ItemsAsDateTime[const index: string]: TDateTime read GetItemAsDateTime write SetItemAsDateTime;
|
||||
property Items[const index: string]: string read GetItem write SetItem; default;
|
||||
protected
|
||||
function Contains(const Index: String): Boolean;
|
||||
function Keys: TArray<String>;
|
||||
function Contains(const Index: string): Boolean;
|
||||
function Keys: TArray<string>;
|
||||
public
|
||||
constructor Create; virtual;
|
||||
destructor Destroy; override;
|
||||
@ -83,20 +83,20 @@ type
|
||||
/// </summary>
|
||||
TJWTRegisteredClaims = class(TJWTDictionaryObject)
|
||||
private
|
||||
procedure SetAudience(const Value: String);
|
||||
procedure SetAudience(const Value: string);
|
||||
procedure SetExpirationTime(const Value: TDateTime);
|
||||
procedure SetIssuedAt(const Value: TDateTime);
|
||||
procedure SetISSUER(const Value: String);
|
||||
procedure SetJWT_ID(const Value: String);
|
||||
procedure SetISSUER(const Value: string);
|
||||
procedure SetJWT_ID(const Value: string);
|
||||
procedure SetNotBefore(const Value: TDateTime);
|
||||
procedure SetSubject(const Value: String);
|
||||
function GetAudience: String;
|
||||
procedure SetSubject(const Value: string);
|
||||
function GetAudience: string;
|
||||
function GetExpirationTime: TDateTime;
|
||||
function GetIssuedAt: TDateTime;
|
||||
function GetJWT_ID: String;
|
||||
function GetJWT_ID: string;
|
||||
function GetNotBefore: TDateTime;
|
||||
function GetSubject: String;
|
||||
function GetIssuer: String;
|
||||
function GetSubject: string;
|
||||
function GetIssuer: string;
|
||||
public
|
||||
/// <summary>
|
||||
/// "iss" (Issuer) Claim
|
||||
@ -105,7 +105,7 @@ type
|
||||
/// The " iss " value is a case-sensitive string containing a StringOrURI
|
||||
/// value.Use of this claim is OPTIONAL.
|
||||
/// </summary>
|
||||
property Issuer: String read GetIssuer write SetISSUER;
|
||||
property Issuer: string read GetIssuer write SetISSUER;
|
||||
/// <summary>
|
||||
/// "sub" (Subject) Claim
|
||||
/// The "sub" (subject) claim identifies the principal that is the
|
||||
@ -116,7 +116,7 @@ type
|
||||
/// "sub" value is a case-sensitive string containing a StringOrURI
|
||||
/// value. Use of this claim is OPTIONAL.
|
||||
/// </summary>
|
||||
property Subject: String read GetSubject write SetSubject;
|
||||
property Subject: string read GetSubject write SetSubject;
|
||||
/// <summary>
|
||||
/// "aud" (Audience) Claim
|
||||
/// The "aud" (audience) claim identifies the recipients that the JWT is
|
||||
@ -131,7 +131,7 @@ type
|
||||
/// interpretation of audience values is generally application specific.
|
||||
/// Use of this claim is OPTIONAL.
|
||||
/// </summary>
|
||||
property Audience: String read GetAudience write SetAudience;
|
||||
property Audience: string read GetAudience write SetAudience;
|
||||
/// <summary>
|
||||
/// "exp" (Expiration Time) Claim
|
||||
/// The "exp" (expiration time) claim identifies the expiration time on
|
||||
@ -173,7 +173,7 @@ type
|
||||
/// to prevent the JWT from being replayed. The "jti" value is a case-
|
||||
/// sensitive string. Use of this claim is OPTIONAL.
|
||||
/// </summary>
|
||||
property JWT_ID: String read GetJWT_ID write SetJWT_ID;
|
||||
property JWT_ID: string read GetJWT_ID write SetJWT_ID;
|
||||
end;
|
||||
|
||||
TJWTCustomClaims = class(TJWTDictionaryObject)
|
||||
@ -186,26 +186,33 @@ type
|
||||
FSecretKey: string;
|
||||
FRegisteredClaims: TJWTRegisteredClaims;
|
||||
FCustomClaims: TJWTCustomClaims;
|
||||
FHMACAlgorithm: String;
|
||||
FLeewaySeconds: Int64;
|
||||
FHMACAlgorithm: string;
|
||||
FRegClaimsToChecks: TJWTCheckableClaims;
|
||||
procedure SetHMACAlgorithm(const Value: String);
|
||||
procedure SetLeewaySeconds(const Value: Int64);
|
||||
FLiveValidityWindowInSeconds: Cardinal;
|
||||
FLeewaySeconds: Cardinal;
|
||||
procedure SetHMACAlgorithm(const Value: string);
|
||||
procedure SetChecks(const Value: TJWTCheckableClaims);
|
||||
function CheckExpirationTime(Payload: TJSONObject; out Error: String): Boolean;
|
||||
function CheckNotBefore(Payload: TJSONObject; out Error: String): Boolean;
|
||||
function CheckIssuedAt(Payload: TJSONObject; out Error: String): Boolean;
|
||||
function CheckExpirationTime(Payload: TJSONObject; out Error: string): Boolean;
|
||||
function CheckNotBefore(Payload: TJSONObject; out Error: string): Boolean;
|
||||
function CheckIssuedAt(Payload: TJSONObject; out Error: string): Boolean;
|
||||
procedure SetLiveValidityWindowInSeconds(const Value: Cardinal);
|
||||
function GetLiveValidityWindowInSeconds: Cardinal;
|
||||
public
|
||||
constructor Create(const SecretKey: String); virtual;
|
||||
constructor Create(const SecretKey: string; const ALeewaySeconds: Cardinal = 300); virtual;
|
||||
destructor Destroy; override;
|
||||
function GetToken: String;
|
||||
function IsValidToken(const Token: String; out Error: String): Boolean;
|
||||
procedure LoadToken(const Token: String);
|
||||
function GetToken: string;
|
||||
function IsValidToken(const Token: string; out Error: string): Boolean;
|
||||
procedure LoadToken(const Token: string);
|
||||
property Claims: TJWTRegisteredClaims read FRegisteredClaims;
|
||||
property CustomClaims: TJWTCustomClaims read FCustomClaims;
|
||||
property HMACAlgorithm: String read FHMACAlgorithm write SetHMACAlgorithm;
|
||||
property LeewaySeconds: Int64 read FLeewaySeconds write SetLeewaySeconds;
|
||||
property HMACAlgorithm: string read FHMACAlgorithm write SetHMACAlgorithm;
|
||||
property LeewaySeconds: Cardinal read FLeewaySeconds;
|
||||
property RegClaimsToChecks: TJWTCheckableClaims read FRegClaimsToChecks write SetChecks;
|
||||
/// <summary>
|
||||
/// Use LiveValidityWindowInSeconds to make the ExpirationTime dynamic at each request,
|
||||
/// incrementing the ExpirationTime by LiveValidityWindowInSeconds seconds at each request
|
||||
/// </summary>
|
||||
property LiveValidityWindowInSeconds: Cardinal read GetLiveValidityWindowInSeconds write SetLiveValidityWindowInSeconds;
|
||||
end;
|
||||
|
||||
implementation
|
||||
@ -218,7 +225,7 @@ uses
|
||||
|
||||
{ TJWTRegisteredClaims }
|
||||
|
||||
function TJWTRegisteredClaims.GetAudience: String;
|
||||
function TJWTRegisteredClaims.GetAudience: string;
|
||||
begin
|
||||
Result := Items[TJWTRegisteredClaimNames.Audience];
|
||||
end;
|
||||
@ -233,12 +240,12 @@ begin
|
||||
Result := ItemsAsDateTime[TJWTRegisteredClaimNames.IssuedAt];
|
||||
end;
|
||||
|
||||
function TJWTRegisteredClaims.GetIssuer: String;
|
||||
function TJWTRegisteredClaims.GetIssuer: string;
|
||||
begin
|
||||
Result := Items[TJWTRegisteredClaimNames.Issuer];
|
||||
end;
|
||||
|
||||
function TJWTRegisteredClaims.GetJWT_ID: String;
|
||||
function TJWTRegisteredClaims.GetJWT_ID: string;
|
||||
begin
|
||||
Result := Items[TJWTRegisteredClaimNames.JWT_ID];
|
||||
end;
|
||||
@ -248,12 +255,12 @@ begin
|
||||
Result := ItemsAsDateTime[TJWTRegisteredClaimNames.NotBefore];
|
||||
end;
|
||||
|
||||
function TJWTRegisteredClaims.GetSubject: String;
|
||||
function TJWTRegisteredClaims.GetSubject: string;
|
||||
begin
|
||||
Result := Items[TJWTRegisteredClaimNames.Subject];
|
||||
end;
|
||||
|
||||
procedure TJWTRegisteredClaims.SetAudience(const Value: String);
|
||||
procedure TJWTRegisteredClaims.SetAudience(const Value: string);
|
||||
begin
|
||||
Items[TJWTRegisteredClaimNames.Audience] := Value;
|
||||
end;
|
||||
@ -268,12 +275,12 @@ begin
|
||||
ItemsAsDateTime[TJWTRegisteredClaimNames.IssuedAt] := Value;
|
||||
end;
|
||||
|
||||
procedure TJWTRegisteredClaims.SetISSUER(const Value: String);
|
||||
procedure TJWTRegisteredClaims.SetISSUER(const Value: string);
|
||||
begin
|
||||
Items[TJWTRegisteredClaimNames.Issuer] := Value;
|
||||
end;
|
||||
|
||||
procedure TJWTRegisteredClaims.SetJWT_ID(const Value: String);
|
||||
procedure TJWTRegisteredClaims.SetJWT_ID(const Value: string);
|
||||
begin
|
||||
Items[TJWTRegisteredClaimNames.JWT_ID] := Value;
|
||||
end;
|
||||
@ -283,22 +290,22 @@ begin
|
||||
ItemsAsDateTime[TJWTRegisteredClaimNames.NotBefore] := Value;
|
||||
end;
|
||||
|
||||
procedure TJWTRegisteredClaims.SetSubject(const Value: String);
|
||||
procedure TJWTRegisteredClaims.SetSubject(const Value: string);
|
||||
begin
|
||||
Items[TJWTRegisteredClaimNames.Subject] := Value;
|
||||
end;
|
||||
|
||||
{ TJWTCustomClaims }
|
||||
|
||||
function TJWTDictionaryObject.Contains(const Index: String): Boolean;
|
||||
function TJWTDictionaryObject.Contains(const Index: string): Boolean;
|
||||
begin
|
||||
Result := FClaims.ContainsKey(Index);
|
||||
Result := FClaims.ContainsKey(index);
|
||||
end;
|
||||
|
||||
constructor TJWTDictionaryObject.Create;
|
||||
begin
|
||||
inherited;
|
||||
FClaims := TDictionary<String, String>.Create;
|
||||
FClaims := TDictionary<string, string>.Create;
|
||||
end;
|
||||
|
||||
destructor TJWTDictionaryObject.Destroy;
|
||||
@ -307,35 +314,35 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TJWTDictionaryObject.GetItem(const Index: String): String;
|
||||
function TJWTDictionaryObject.GetItem(const Index: string): string;
|
||||
begin
|
||||
if not FClaims.TryGetValue(Index, Result) then
|
||||
if not FClaims.TryGetValue(index, Result) then
|
||||
Result := '';
|
||||
end;
|
||||
|
||||
function TJWTDictionaryObject.GetItemAsDateTime(const Index: String): TDateTime;
|
||||
function TJWTDictionaryObject.GetItemAsDateTime(const Index: string): TDateTime;
|
||||
var
|
||||
lIntValue: Int64;
|
||||
begin
|
||||
if not TryStrToInt64(Items[Index], lIntValue) then
|
||||
if not TryStrToInt64(Items[index], lIntValue) then
|
||||
raise Exception.Create('Item cannot be converted as Unix Epoch');
|
||||
Result := UnixToDateTime(lIntValue, False);
|
||||
end;
|
||||
|
||||
function TJWTDictionaryObject.Keys: TArray<String>;
|
||||
function TJWTDictionaryObject.Keys: TArray<string>;
|
||||
begin
|
||||
Result := FClaims.Keys.ToArray;
|
||||
end;
|
||||
|
||||
procedure TJWTDictionaryObject.SetItem(const Index, Value: String);
|
||||
procedure TJWTDictionaryObject.SetItem(const Index, Value: string);
|
||||
begin
|
||||
FClaims.AddOrSetValue(Index, Value);
|
||||
FClaims.AddOrSetValue(index, Value);
|
||||
end;
|
||||
|
||||
procedure TJWTDictionaryObject.SetItemAsDateTime(const Index: String;
|
||||
procedure TJWTDictionaryObject.SetItemAsDateTime(const Index: string;
|
||||
const Value: TDateTime);
|
||||
begin
|
||||
Items[Index] := IntToStr(DateTimeToUnix(Value, False));
|
||||
Items[index] := IntToStr(DateTimeToUnix(Value, False));
|
||||
end;
|
||||
|
||||
{ TJWTCustomClaims }
|
||||
@ -348,11 +355,12 @@ end;
|
||||
{ TJWT }
|
||||
|
||||
function TJWT.CheckExpirationTime(Payload: TJSONObject;
|
||||
out Error: String): Boolean;
|
||||
out Error: string): Boolean;
|
||||
var
|
||||
lJValue: TJSONValue;
|
||||
lIntValue: Int64;
|
||||
lValue: string;
|
||||
lExpirationTimeAsDateTime: TDateTime;
|
||||
begin
|
||||
lJValue := Payload.GetValue(TJWTRegisteredClaimNames.ExpirationTime);
|
||||
if not Assigned(lJValue) then
|
||||
@ -368,7 +376,8 @@ begin
|
||||
Exit(False);
|
||||
end;
|
||||
|
||||
if UnixToDateTime(lIntValue, False) <= Now - FLeewaySeconds * OneSecond then
|
||||
lExpirationTimeAsDateTime := UnixToDateTime(lIntValue, False);
|
||||
if lExpirationTimeAsDateTime <= Now - FLeewaySeconds * OneSecond then
|
||||
begin
|
||||
Error := 'Token expired';
|
||||
Exit(False);
|
||||
@ -377,7 +386,7 @@ begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TJWT.CheckIssuedAt(Payload: TJSONObject; out Error: String): Boolean;
|
||||
function TJWT.CheckIssuedAt(Payload: TJSONObject; out Error: string): Boolean;
|
||||
var
|
||||
lJValue: TJSONValue;
|
||||
lIntValue: Int64;
|
||||
@ -406,7 +415,7 @@ begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
function TJWT.CheckNotBefore(Payload: TJSONObject; out Error: String): Boolean;
|
||||
function TJWT.CheckNotBefore(Payload: TJSONObject; out Error: string): Boolean;
|
||||
var
|
||||
lJValue: TJSONValue;
|
||||
lIntValue: Int64;
|
||||
@ -435,16 +444,17 @@ begin
|
||||
Result := True;
|
||||
end;
|
||||
|
||||
constructor TJWT.Create(const SecretKey: String);
|
||||
constructor TJWT.Create(const SecretKey: string; const ALeewaySeconds: Cardinal = 300);
|
||||
begin
|
||||
inherited Create;
|
||||
FSecretKey := SecretKey;
|
||||
FRegisteredClaims := TJWTRegisteredClaims.Create;
|
||||
FCustomClaims := TJWTCustomClaims.Create;
|
||||
FHMACAlgorithm := 'HS256';
|
||||
FLeewaySeconds := 300; // 5 minutes of leeway
|
||||
FLeewaySeconds := ALeewaySeconds;
|
||||
FRegClaimsToChecks := [TJWTCheckableClaim.ExpirationTime, TJWTCheckableClaim.NotBefore,
|
||||
TJWTCheckableClaim.IssuedAt];
|
||||
FLiveValidityWindowInSeconds := 0;
|
||||
end;
|
||||
|
||||
destructor TJWT.Destroy;
|
||||
@ -454,13 +464,18 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
function TJWT.GetToken: String;
|
||||
function TJWT.GetLiveValidityWindowInSeconds: Cardinal;
|
||||
begin
|
||||
Result := StrToIntDef(FCustomClaims.Items['lvw'], 0);
|
||||
end;
|
||||
|
||||
function TJWT.GetToken: string;
|
||||
var
|
||||
lHeader, lPayload: TJSONObject;
|
||||
lHeaderEncoded, lPayloadEncoded, lToken, lHash: String;
|
||||
lHeaderEncoded, lPayloadEncoded, lToken, lHash: string;
|
||||
lBytes: TBytes;
|
||||
lRegClaimName: String;
|
||||
lCustomClaimName: String;
|
||||
lRegClaimName: string;
|
||||
lCustomClaimName: string;
|
||||
begin
|
||||
lHeader := TJSONObject.Create;
|
||||
try
|
||||
@ -500,9 +515,9 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
function TJWT.IsValidToken(const Token: String; out Error: String): Boolean;
|
||||
function TJWT.IsValidToken(const Token: string; out Error: string): Boolean;
|
||||
var
|
||||
lPieces: TArray<String>;
|
||||
lPieces: TArray<string>;
|
||||
lJHeader: TJSONObject;
|
||||
lJAlg: TJSONString;
|
||||
lAlgName: string;
|
||||
@ -584,9 +599,9 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TJWT.LoadToken(const Token: String);
|
||||
procedure TJWT.LoadToken(const Token: string);
|
||||
var
|
||||
lPieces: TArray<String>;
|
||||
lPieces: TArray<string>;
|
||||
lJHeader: TJSONObject;
|
||||
lJPayload: TJSONObject;
|
||||
lJPair: TJSONPair;
|
||||
@ -595,7 +610,7 @@ var
|
||||
j: Integer;
|
||||
lIsRegistered: Boolean;
|
||||
lValue: string;
|
||||
lError: String;
|
||||
lError: string;
|
||||
begin
|
||||
if not IsValidToken(Token, lError) then
|
||||
raise EMVCJWTException.Create(lError);
|
||||
@ -620,7 +635,7 @@ begin
|
||||
lValue := lJPair.JsonValue.Value;
|
||||
|
||||
// if is a registered claim, load it in the proper dictionary...
|
||||
for j := 0 to High(TJWTRegisteredClaimNames.Names) do
|
||||
for j := 0 to high(TJWTRegisteredClaimNames.Names) do
|
||||
begin
|
||||
if lName = TJWTRegisteredClaimNames.Names[j] then
|
||||
begin
|
||||
@ -646,14 +661,14 @@ begin
|
||||
FRegClaimsToChecks := Value;
|
||||
end;
|
||||
|
||||
procedure TJWT.SetHMACAlgorithm(const Value: String);
|
||||
procedure TJWT.SetHMACAlgorithm(const Value: string);
|
||||
begin
|
||||
FHMACAlgorithm := Value;
|
||||
end;
|
||||
|
||||
procedure TJWT.SetLeewaySeconds(const Value: Int64);
|
||||
procedure TJWT.SetLiveValidityWindowInSeconds(const Value: Cardinal);
|
||||
begin
|
||||
FLeewaySeconds := Value;
|
||||
FCustomClaims.Items['lvw'] := Value.ToString;
|
||||
end;
|
||||
|
||||
end.
|
||||
|
@ -1,345 +0,0 @@
|
||||
// ***************************************************************************
|
||||
//
|
||||
// Delphi MVC Framework
|
||||
//
|
||||
// Copyright (c) 2010-2017 Daniele Teti and the DMVCFramework Team
|
||||
//
|
||||
// https://github.com/danieleteti/delphimvcframework
|
||||
//
|
||||
// ***************************************************************************
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// *************************************************************************** }
|
||||
|
||||
unit MVCFramework.MessagingController;
|
||||
|
||||
{$I dmvcframework.inc}
|
||||
|
||||
interface
|
||||
|
||||
uses
|
||||
System.SysUtils,
|
||||
System.DateUtils,
|
||||
System.SyncObjs,
|
||||
MVCFramework,
|
||||
MVCFramework.Commons,
|
||||
MVCFramework.Logger,
|
||||
MVCFramework.TypesAliases,
|
||||
StompClient;
|
||||
|
||||
type
|
||||
|
||||
[MVCPath('/messages')]
|
||||
TMVCBUSController = class(TMVCController)
|
||||
protected
|
||||
function GetUniqueDurableHeader(AClientId, ATopicName: string): string;
|
||||
|
||||
procedure InternalSubscribeUserToTopics(AClientId: string; AStompClient: IStompClient);
|
||||
procedure InternalSubscribeUserToTopic(AClientId: string; ATopicName: string; AStompClient: IStompClient);
|
||||
|
||||
procedure AddTopicToUserSubscriptions(const ATopic: string);
|
||||
procedure RemoveTopicFromUserSubscriptions(const ATopic: string);
|
||||
procedure OnBeforeAction(AContext: TWebContext; const AActionNAme: string; var AHandled: Boolean); override;
|
||||
public
|
||||
[MVCHTTPMethod([httpPOST])]
|
||||
[MVCPath('/clients/($clientid)')]
|
||||
procedure SetClientID(AContext: TWebContext);
|
||||
|
||||
[MVCPath('/subscriptions/($topicorqueue)/($name)')]
|
||||
[MVCHTTPMethod([httpPOST])]
|
||||
procedure SubscribeToTopic(AContext: TWebContext);
|
||||
|
||||
[MVCPath('/subscriptions/($topicorqueue)/($name)')]
|
||||
[MVCHTTPMethod([httpDELETE])]
|
||||
procedure UnSubscribeFromTopic(AContext: TWebContext);
|
||||
|
||||
[MVCHTTPMethod([httpGET])]
|
||||
[MVCPath]
|
||||
procedure ReceiveMessages(AContext: TWebContext);
|
||||
|
||||
[MVCHTTPMethod([httpPOST])]
|
||||
[MVCPath('/($type)/($topicorqueue)')]
|
||||
procedure EnqueueMessage(AContext: TWebContext);
|
||||
|
||||
[MVCHTTPMethod([httpGET])]
|
||||
[MVCPath('/subscriptions')]
|
||||
procedure CurrentlySubscribedTopics(AContext: TWebContext);
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
{ TMVCBUSController }
|
||||
|
||||
procedure TMVCBUSController.AddTopicToUserSubscriptions(const ATopic: string);
|
||||
var
|
||||
x: string;
|
||||
topics: TArray<string>;
|
||||
t: string;
|
||||
ToAdd: Boolean;
|
||||
begin
|
||||
x := Session['__subscriptions'];
|
||||
topics := x.Split([';']);
|
||||
ToAdd := true;
|
||||
for t in topics do
|
||||
if t.Equals(ATopic) then
|
||||
begin
|
||||
ToAdd := False;
|
||||
end;
|
||||
if ToAdd then
|
||||
begin
|
||||
SetLength(topics, length(topics) + 1);
|
||||
topics[length(topics) - 1] := ATopic;
|
||||
Session['__subscriptions'] := string.Join(';', topics);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCBUSController.CurrentlySubscribedTopics(AContext: TWebContext);
|
||||
begin
|
||||
ContentType := TMVCMediaType.TEXT_PLAIN;
|
||||
Render(Session['__subscriptions']);
|
||||
end;
|
||||
|
||||
procedure TMVCBUSController.EnqueueMessage(AContext: TWebContext);
|
||||
var
|
||||
topicname: string;
|
||||
queuetype: string;
|
||||
begin
|
||||
queuetype := AContext.Request.Params['type'].Trim.ToLower;
|
||||
if (queuetype <> 'topic') and (queuetype <> 'queue') then
|
||||
raise EMVCException.Create('Valid type are "queue" or "topic", got ' + queuetype);
|
||||
|
||||
topicname := AContext.Request.Params['topicorqueue'].Trim;
|
||||
if topicname.IsEmpty then
|
||||
raise EMVCException.Create('Invalid or empty topic');
|
||||
if not AContext.Request.ThereIsRequestBody then
|
||||
raise EMVCException.Create('Body request required');
|
||||
// EnqueueMessageOnTopicOrQueue(queuetype = 'queue', '/' + queuetype + '/' + topicname,
|
||||
// CTX.Request.BodyAsJSONObject.Clone as TJSONObject, true);
|
||||
// EnqueueMessage('/queue/' + topicname, CTX.Request.BodyAsJSONObject.Clone as TJSONObject, true);
|
||||
Render(200, 'Message sent to topic ' + topicname);
|
||||
end;
|
||||
|
||||
function TMVCBUSController.GetUniqueDurableHeader(AClientId, ATopicName: string): string;
|
||||
begin
|
||||
Result := AClientId + '___' + ATopicName.Replace('/', '_', [rfReplaceAll]);
|
||||
end;
|
||||
|
||||
procedure TMVCBUSController.ReceiveMessages(AContext: TWebContext);
|
||||
var
|
||||
Stomp: IStompClient;
|
||||
LClientID: string;
|
||||
frame: IStompFrame;
|
||||
obj, res: TJSONObject;
|
||||
LFrames: TArray<IStompFrame>;
|
||||
arr: TJSONArray;
|
||||
LLastReceivedMessageTS: TDateTime;
|
||||
LTimeOut: Boolean;
|
||||
const
|
||||
|
||||
{$IFDEF TEST}
|
||||
|
||||
RECEIVE_TIMEOUT = 5; // seconds
|
||||
|
||||
{$ELSE}
|
||||
|
||||
RECEIVE_TIMEOUT = 60 * 5; // 5 minutes
|
||||
|
||||
{$ENDIF}
|
||||
|
||||
begin
|
||||
LTimeOut := False;
|
||||
LClientID := GetClientID;
|
||||
Stomp := GetNewStompClient(LClientID);
|
||||
try
|
||||
InternalSubscribeUserToTopics(LClientID, Stomp);
|
||||
// StartReceiving := now;
|
||||
|
||||
LLastReceivedMessageTS := now;
|
||||
SetLength(LFrames, 0);
|
||||
while not IsShuttingDown do
|
||||
begin
|
||||
LTimeOut := False;
|
||||
frame := nil;
|
||||
Log.Info('/messages receive', ClassName);
|
||||
Stomp.Receive(frame, 100);
|
||||
if Assigned(frame) then
|
||||
// get 10 messages at max, and then send them to client
|
||||
begin
|
||||
LLastReceivedMessageTS := now;
|
||||
SetLength(LFrames, length(LFrames) + 1);
|
||||
LFrames[length(LFrames) - 1] := frame;
|
||||
Stomp.Ack(frame.MessageID);
|
||||
if length(LFrames) >= 10 then
|
||||
break;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (length(LFrames) > 0) then
|
||||
break;
|
||||
if SecondsBetween(now, LLastReceivedMessageTS) >= RECEIVE_TIMEOUT then
|
||||
begin
|
||||
LTimeOut := true;
|
||||
break;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
arr := TJSONArray.Create;
|
||||
res := TJSONObject.Create(TJSONPair.Create('messages', arr));
|
||||
for frame in LFrames do
|
||||
begin
|
||||
if Assigned(frame) then
|
||||
begin
|
||||
obj := TJSONObject.ParseJSONValue(frame.GetBody) as TJSONObject;
|
||||
if Assigned(obj) then
|
||||
begin
|
||||
arr.AddElement(obj);
|
||||
end
|
||||
else
|
||||
begin
|
||||
Log.Error(Format
|
||||
('Not valid JSON object in topic requested by user %s. The raw message is "%s"',
|
||||
[LClientID, frame.GetBody]), ClassName);
|
||||
end;
|
||||
end;
|
||||
end; // for in
|
||||
res.AddPair('_timestamp', FormatDateTime('yyyy-mm-dd hh:nn:ss', now));
|
||||
if LTimeOut then
|
||||
begin
|
||||
res.AddPair('_timeout', TJSONTrue.Create);
|
||||
// Render(http_status.RequestTimeout, res);
|
||||
end
|
||||
else
|
||||
begin
|
||||
res.AddPair('_timeout', TJSONFalse.Create);
|
||||
// Render(http_status.OK, res);
|
||||
end;
|
||||
|
||||
finally
|
||||
// Stomp.Disconnect;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCBUSController.RemoveTopicFromUserSubscriptions(const ATopic: string);
|
||||
var
|
||||
x: string;
|
||||
topics, afterremovaltopics: TArray<string>;
|
||||
IndexToRemove: Integer;
|
||||
i: Integer;
|
||||
begin
|
||||
x := Session['__subscriptions'];
|
||||
topics := x.Split([';']);
|
||||
IndexToRemove := 0;
|
||||
SetLength(afterremovaltopics, length(topics));
|
||||
for i := 0 to length(topics) - 1 do
|
||||
begin
|
||||
if not topics[i].Equals(ATopic) then
|
||||
begin
|
||||
afterremovaltopics[IndexToRemove] := topics[i];
|
||||
Inc(IndexToRemove);
|
||||
end;
|
||||
end;
|
||||
if IndexToRemove <> length(ATopic) - 1 then
|
||||
SetLength(afterremovaltopics, length(topics) - 1);
|
||||
|
||||
if length(afterremovaltopics) = 0 then
|
||||
Session['__subscriptions'] := ''
|
||||
else
|
||||
Session['__subscriptions'] := string.Join(';', afterremovaltopics);
|
||||
end;
|
||||
|
||||
procedure TMVCBUSController.SetClientID(AContext: TWebContext);
|
||||
begin
|
||||
Session[CLIENTID_KEY] := AContext.Request.Params['clientid'];
|
||||
end;
|
||||
|
||||
procedure TMVCBUSController.SubscribeToTopic(AContext: TWebContext);
|
||||
var
|
||||
LStomp: IStompClient;
|
||||
LClientID: string;
|
||||
LTopicName: string;
|
||||
LTopicOrQueue: string;
|
||||
begin
|
||||
LClientID := GetClientID;
|
||||
LTopicName := AContext.Request.Params['name'].ToLower;
|
||||
LTopicOrQueue := AContext.Request.Params['topicorqueue'].ToLower;
|
||||
LStomp := GetNewStompClient(LClientID);
|
||||
try
|
||||
LTopicName := '/' + LTopicOrQueue + '/' + LTopicName;
|
||||
InternalSubscribeUserToTopic(LClientID, LTopicName, LStomp);
|
||||
Render(200, 'Subscription OK for ' + LTopicName);
|
||||
finally
|
||||
// Stomp.Disconnect;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCBUSController.InternalSubscribeUserToTopics(AClientId: string; AStompClient: IStompClient);
|
||||
var
|
||||
x, t: string;
|
||||
topics: TArray<string>;
|
||||
begin
|
||||
x := Session['__subscriptions'];
|
||||
topics := x.Split([';']);
|
||||
for t in topics do
|
||||
InternalSubscribeUserToTopic(AClientId, t, AStompClient);
|
||||
end;
|
||||
|
||||
procedure TMVCBUSController.OnBeforeAction(AContext: TWebContext; const AActionNAme: string;
|
||||
var AHandled: Boolean);
|
||||
begin
|
||||
inherited;
|
||||
if not StrToBool(Config['messaging']) then
|
||||
begin
|
||||
AHandled := true;
|
||||
raise EMVCException.Create('Messaging extensions are not enabled');
|
||||
end;
|
||||
AHandled := False;
|
||||
end;
|
||||
|
||||
procedure TMVCBUSController.InternalSubscribeUserToTopic(AClientId, ATopicName: string;
|
||||
AStompClient: IStompClient);
|
||||
// var
|
||||
// LDurSubHeader: string;
|
||||
// LHeaders: IStompHeaders;
|
||||
begin
|
||||
raise EMVCException.Create('Not implemented');
|
||||
// LHeaders := TStompHeaders.Create;
|
||||
// LDurSubHeader := GetUniqueDurableHeader(clientid, topicname);
|
||||
// LHeaders.Add(TStompHeaders.NewDurableSubscriptionHeader(LDurSubHeader));
|
||||
//
|
||||
// if topicname.StartsWith('/topic') then
|
||||
// LHeaders.Add('id', clientid); //https://www.rabbitmq.com/stomp.html
|
||||
//
|
||||
// StompClient.Subscribe(topicname, amClient, LHeaders);
|
||||
// LogE('SUBSCRIBE TO ' + clientid + '@' + topicname + ' dursubheader:' + LDurSubHeader);
|
||||
// AddTopicToUserSubscriptions(topicname);
|
||||
end;
|
||||
|
||||
procedure TMVCBUSController.UnSubscribeFromTopic(AContext: TWebContext);
|
||||
var
|
||||
Stomp: IStompClient;
|
||||
clientid: string;
|
||||
thename: string;
|
||||
s: string;
|
||||
begin
|
||||
clientid := GetClientID;
|
||||
thename := AContext.Request.Params['name'].ToLower;
|
||||
Stomp := GetNewStompClient(clientid);
|
||||
s := '/queue/' + thename;
|
||||
Stomp.Unsubscribe(s);
|
||||
RemoveTopicFromUserSubscriptions(s);
|
||||
Render(200, 'UnSubscription OK for ' + s);
|
||||
end;
|
||||
|
||||
end.
|
@ -47,6 +47,7 @@ type
|
||||
FClaimsToChecks: TJWTCheckableClaims;
|
||||
FSetupJWTClaims: TJWTClaimsSetup;
|
||||
FSecret: string;
|
||||
FLeewaySeconds: Cardinal;
|
||||
protected
|
||||
procedure InternalRender(
|
||||
AJSONValue: TJSONValue;
|
||||
@ -88,23 +89,32 @@ type
|
||||
TJWTCheckableClaim.ExpirationTime,
|
||||
TJWTCheckableClaim.NotBefore,
|
||||
TJWTCheckableClaim.IssuedAt
|
||||
]); virtual;
|
||||
];
|
||||
ALeewaySeconds: Cardinal = 300); virtual;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses System.NetEncoding, System.DateUtils;
|
||||
|
||||
{ TMVCJWTAuthenticationMiddleware }
|
||||
|
||||
constructor TMVCJWTAuthenticationMiddleware.Create(
|
||||
AAuthenticationHandler: IMVCAuthenticationHandler;
|
||||
AConfigClaims: TJWTClaimsSetup; ASecret: string;
|
||||
AClaimsToCheck: TJWTCheckableClaims);
|
||||
constructor TMVCJWTAuthenticationMiddleware.Create(AAuthenticationHandler: IMVCAuthenticationHandler;
|
||||
AConfigClaims: TJWTClaimsSetup;
|
||||
ASecret: string = 'D3lph1MVCFram3w0rk';
|
||||
AClaimsToCheck: TJWTCheckableClaims = [
|
||||
TJWTCheckableClaim.ExpirationTime,
|
||||
TJWTCheckableClaim.NotBefore,
|
||||
TJWTCheckableClaim.IssuedAt
|
||||
];
|
||||
ALeewaySeconds: Cardinal = 300);
|
||||
begin
|
||||
inherited Create;
|
||||
FAuthenticationHandler := AAuthenticationHandler;
|
||||
FSetupJWTClaims := AConfigClaims;
|
||||
FClaimsToChecks := AClaimsToCheck;
|
||||
FSecret := ASecret;
|
||||
FLeewaySeconds := ALeewaySeconds;
|
||||
end;
|
||||
|
||||
procedure TMVCJWTAuthenticationMiddleware.InternalRender(
|
||||
@ -148,7 +158,7 @@ var
|
||||
JWTValue: TJWT;
|
||||
AuthHeader: string;
|
||||
AuthToken: string;
|
||||
ErrorMsg: String;
|
||||
ErrorMsg: string;
|
||||
begin
|
||||
// check if the resource is protected
|
||||
FAuthenticationHandler.OnRequest(AControllerQualifiedClassName, AActionName, AuthRequired);
|
||||
@ -161,7 +171,7 @@ begin
|
||||
|
||||
// Checking token in subsequent requests
|
||||
// ***************************************************
|
||||
JWTValue := TJWT.Create(FSecret);
|
||||
JWTValue := TJWT.Create(FSecret, FLeewaySeconds);
|
||||
try
|
||||
JWTValue.RegClaimsToChecks := Self.FClaimsToChecks;
|
||||
AuthHeader := AContext.Request.Headers['Authentication'];
|
||||
@ -177,6 +187,7 @@ begin
|
||||
if AuthHeader.StartsWith('bearer', True) then
|
||||
begin
|
||||
AuthToken := AuthHeader.Remove(0, 'bearer'.Length).Trim;
|
||||
AuthToken := Trim(TNetEncoding.URL.URLDecode(AuthToken));
|
||||
end;
|
||||
|
||||
// check the jwt
|
||||
@ -204,7 +215,14 @@ begin
|
||||
FAuthenticationHandler.OnAuthorization(AContext.LoggedUser.Roles, AControllerQualifiedClassName, AActionName, IsAuthorized);
|
||||
|
||||
if IsAuthorized then
|
||||
begin
|
||||
if JWTValue.LiveValidityWindowInSeconds > 0 then
|
||||
begin
|
||||
JWTValue.Claims.ExpirationTime := Now + JWTValue.LiveValidityWindowInSeconds * OneSecond;
|
||||
AContext.Response.SetCustomHeader('Authentication', 'bearer ' + JWTValue.GetToken);
|
||||
end;
|
||||
AHandled := False
|
||||
end
|
||||
else
|
||||
begin
|
||||
RenderError(HTTP_STATUS.Forbidden, 'Authorization Forbidden', AContext);
|
||||
@ -222,7 +240,7 @@ procedure TMVCJWTAuthenticationMiddleware.OnBeforeRouting(
|
||||
var
|
||||
UserName: string;
|
||||
Password: string;
|
||||
RolesList: TList<String>;
|
||||
RolesList: TList<string>;
|
||||
SessionData: TSessionData;
|
||||
IsValid: Boolean;
|
||||
JWTValue: TJWT;
|
||||
@ -246,9 +264,11 @@ begin
|
||||
FAuthenticationHandler.OnAuthentication(UserName, Password, RolesList, IsValid, SessionData);
|
||||
if IsValid then
|
||||
begin
|
||||
JWTValue := TJWT.Create(FSecret);
|
||||
JWTValue := TJWT.Create(FSecret, FLeewaySeconds);
|
||||
try
|
||||
// let's user config claims and custom claims
|
||||
if not Assigned(FSetupJWTClaims) then
|
||||
raise EMVCJWTException.Create('SetupJWTClaims not set');
|
||||
FSetupJWTClaims(JWTValue);
|
||||
|
||||
// these claims are mandatory and managed by the middleware
|
||||
@ -259,7 +279,12 @@ begin
|
||||
raise EMVCJWTException.Create('Custom claim "roles" is reserved and cannot be modified in the JWT setup');
|
||||
|
||||
JWTValue.CustomClaims['username'] := UserName;
|
||||
JWTValue.CustomClaims['roles'] := String.Join(',', RolesList.ToArray);
|
||||
JWTValue.CustomClaims['roles'] := string.Join(',', RolesList.ToArray);
|
||||
|
||||
if JWTValue.LiveValidityWindowInSeconds > 0 then
|
||||
begin
|
||||
JWTValue.Claims.ExpirationTime := Now + (JWTValue.LeewaySeconds + JWTValue.LiveValidityWindowInSeconds) * OneSecond;
|
||||
end;
|
||||
|
||||
// setup the current logged user from the JWT
|
||||
AContext.LoggedUser.Roles.AddRange(RolesList);
|
||||
|
Loading…
Reference in New Issue
Block a user