diff --git a/.gitignore b/.gitignore index ff598549..ece8529a 100644 --- a/.gitignore +++ b/.gitignore @@ -96,3 +96,4 @@ unittests/serializer/jsondataobjects/Win32/CI/dunitx-results.xml unittests/serializer/jsondataobjects/Win32/Debug/dunitx-results.xml unittests/general/Several/Win32/CI/sqlitetest.db unittests/general/Several/Win32/CONSOLE/sqlitetest.db +unittests/general/Several/Win32/GUI/sqlitetest.db diff --git a/README.md b/README.md index 8eaa5834..e0629e28 100644 --- a/README.md +++ b/README.md @@ -305,12 +305,16 @@ end; - Fixed! [issue336](https://github.com/danieleteti/delphimvcframework/issues/336) +- Fixed! [issue337](https://github.com/danieleteti/delphimvcframework/issues/337) + - Fixed! [issue338](https://github.com/danieleteti/delphimvcframework/issues/338) - Fixed! [issue345](https://github.com/danieleteti/delphimvcframework/issues/345) - Fixed! [issue349](https://github.com/danieleteti/delphimvcframework/issues/349) +- Fixed! [issue350](https://github.com/danieleteti/delphimvcframework/issues/350) + - **Breaking Change!** In `MVCActiveRecord` attribute `MVCPrimaryKey` has been removed and merged with `MVCTableField`, so now `TMVCActiveRecordFieldOption` is a set of `foPrimaryKey`, `foAutoGenerated`, `foTransient` (check `activerecord_showcase.dproj` sample). - **Breaking Change!** Middleware `OnAfterControllerAction` are now invoked in the same order of `OnBeforeControllerAction` (previously were invoked in reversed order). diff --git a/samples/jsonwebtoken/vclclient/MainClientFormU.dfm b/samples/jsonwebtoken/vclclient/MainClientFormU.dfm index 1cf67002..c181d5cd 100644 --- a/samples/jsonwebtoken/vclclient/MainClientFormU.dfm +++ b/samples/jsonwebtoken/vclclient/MainClientFormU.dfm @@ -74,9 +74,9 @@ object Form5: TForm5 TabOrder = 0 object btnGet: TButton AlignWithMargins = True - Left = 171 + Left = 223 Top = 4 - Width = 161 + Width = 154 Height = 41 Align = alLeft Caption = 'Get a protected resource' @@ -87,18 +87,18 @@ object Form5: TForm5 AlignWithMargins = True Left = 4 Top = 4 - Width = 161 + Width = 101 Height = 41 Align = alLeft - Caption = 'Login' + Caption = 'Login (mode 1)' TabOrder = 0 OnClick = btnLOGINClick end object btnLoginWithException: TButton AlignWithMargins = True - Left = 464 + Left = 512 Top = 4 - Width = 179 + Width = 131 Height = 41 Align = alRight Caption = 'Custom Exception in OnAuthenticate' @@ -106,6 +106,17 @@ object Form5: TForm5 WordWrap = True OnClick = btnLoginWithExceptionClick end + object btnLoginJsonObject: TButton + AlignWithMargins = True + Left = 111 + Top = 4 + Width = 106 + Height = 41 + Align = alLeft + Caption = 'Login (mode 2)' + TabOrder = 3 + OnClick = btnLoginJsonObjectClick + end end object Memo3: TMemo Left = 0 diff --git a/samples/jsonwebtoken/vclclient/MainClientFormU.pas b/samples/jsonwebtoken/vclclient/MainClientFormU.pas index c5a09afa..6c6de04e 100644 --- a/samples/jsonwebtoken/vclclient/MainClientFormU.pas +++ b/samples/jsonwebtoken/vclclient/MainClientFormU.pas @@ -27,9 +27,11 @@ type Memo3: TMemo; Splitter2: TSplitter; btnLoginWithException: TButton; + btnLoginJsonObject: TButton; procedure btnGetClick(Sender: TObject); procedure btnLOGINClick(Sender: TObject); procedure btnLoginWithExceptionClick(Sender: TObject); + procedure btnLoginJsonObjectClick(Sender: TObject); private FJWT: string; procedure SetJWT(const Value: string); @@ -139,6 +141,37 @@ begin end; end; +procedure TForm5.btnLoginJsonObjectClick(Sender: TObject); +var + lClient: TRESTClient; + lRest: IRESTResponse; + lJSON: TJSONObject; +begin + lClient := TRESTClient.Create('localhost', 8080); + try + lClient.ReadTimeOut(0); + lRest := lClient.doPOST('/login', [], '{"jwtusername":"user1","jwtpassword":"user1"}'); + if lRest.HasError then + begin + ShowMessage( + 'HTTP ERROR: ' + lRest.Error.HTTPError.ToString + sLineBreak + + 'APPLICATION ERROR CODE: ' + lRest.Error.ErrorNumber.ToString + sLineBreak + + 'EXCEPTION MESSAGE: ' + lRest.Error.ExceptionMessage); + + Exit; + end; + + lJSON := TSystemJSON.StringAsJSONObject(lRest.BodyAsString); + try + JWT := lJSON.GetValue('token').Value; + finally + lJSON.Free; + end; + finally + lClient.Free; + end; +end; + procedure TForm5.btnLoginWithExceptionClick(Sender: TObject); var lClient: TRESTClient; diff --git a/samples/jsonwebtoken_livevaliditywindow/vclclient/MainClientFormU.dfm b/samples/jsonwebtoken_livevaliditywindow/vclclient/MainClientFormU.dfm index 0b54d071..3361eb4f 100644 --- a/samples/jsonwebtoken_livevaliditywindow/vclclient/MainClientFormU.dfm +++ b/samples/jsonwebtoken_livevaliditywindow/vclclient/MainClientFormU.dfm @@ -3,7 +3,7 @@ object MainForm: TMainForm Top = 0 Caption = 'JWT with LiveValidityWindow feature' ClientHeight = 379 - ClientWidth = 721 + ClientWidth = 908 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText @@ -16,7 +16,7 @@ object MainForm: TMainForm object Splitter1: TSplitter Left = 0 Top = 179 - Width = 721 + Width = 908 Height = 3 Cursor = crVSplit Align = alTop @@ -26,7 +26,7 @@ object MainForm: TMainForm object Memo1: TMemo Left = 0 Top = 81 - Width = 721 + Width = 908 Height = 98 Align = alTop Font.Charset = ANSI_CHARSET @@ -37,11 +37,12 @@ object MainForm: TMainForm ParentFont = False ReadOnly = True TabOrder = 0 + ExplicitWidth = 721 end object Memo2: TMemo Left = 0 Top = 182 - Width = 721 + Width = 908 Height = 197 Align = alClient Font.Charset = ANSI_CHARSET @@ -52,19 +53,21 @@ object MainForm: TMainForm ParentFont = False ReadOnly = True TabOrder = 1 + ExplicitWidth = 721 end object Panel1: TPanel Left = 0 Top = 0 - Width = 721 + Width = 908 Height = 81 Align = alTop TabOrder = 2 + ExplicitWidth = 721 object Label1: TLabel AlignWithMargins = True - Left = 417 + Left = 540 Top = 4 - Width = 300 + Width = 364 Height = 73 Align = alClient Caption = @@ -74,13 +77,13 @@ object MainForm: TMainForm 'alidityWindowInSeconds seconds. It is useful to mimic the classi' + 'c session cookie with the semplicity of the JWT.' WordWrap = True - ExplicitLeft = 338 - ExplicitWidth = 368 - ExplicitHeight = 65 + ExplicitLeft = 417 + ExplicitWidth = 298 + ExplicitHeight = 78 end object btnGet: TButton AlignWithMargins = True - Left = 250 + Left = 373 Top = 4 Width = 161 Height = 73 @@ -89,7 +92,7 @@ object MainForm: TMainForm TabOrder = 0 WordWrap = True OnClick = btnGetClick - ExplicitLeft = 171 + ExplicitLeft = 250 end object btnLOGIN: TButton AlignWithMargins = True @@ -115,5 +118,19 @@ object MainForm: TMainForm WordWrap = True OnClick = btnLoginWithHeaderBasicClick end + object Button1: TButton + AlignWithMargins = True + Left = 250 + Top = 4 + Width = 117 + Height = 73 + Align = alLeft + Caption = 'Login (with JSON Object)' + TabOrder = 3 + WordWrap = True + OnClick = Button1Click + ExplicitLeft = 311 + ExplicitTop = 2 + end end end diff --git a/samples/jsonwebtoken_livevaliditywindow/vclclient/MainClientFormU.pas b/samples/jsonwebtoken_livevaliditywindow/vclclient/MainClientFormU.pas index a66c5a89..f55af52e 100644 --- a/samples/jsonwebtoken_livevaliditywindow/vclclient/MainClientFormU.pas +++ b/samples/jsonwebtoken_livevaliditywindow/vclclient/MainClientFormU.pas @@ -17,9 +17,11 @@ type Splitter1: TSplitter; Label1: TLabel; btnLoginWithHeaderBasic: TButton; + Button1: TButton; procedure btnGetClick(Sender: TObject); procedure btnLOGINClick(Sender: TObject); procedure btnLoginWithHeaderBasicClick(Sender: TObject); + procedure Button1Click(Sender: TObject); private FJWT: string; procedure SetJWT(const Value: string); @@ -35,13 +37,14 @@ implementation {$R *.dfm} + uses MVCFramework.RESTClient, MVCFramework.Middleware.JWT, MVCFramework.Serializer.JSONDataObjects, MVCFramework.SystemJSONUtils, System.NetEncoding, - JsonDataObjects; + JSONDataObjects; procedure TMainForm.btnGetClick(Sender: TObject); var @@ -129,6 +132,28 @@ begin end; end; +procedure TMainForm.Button1Click(Sender: TObject); +var + lClient: TRESTClient; + lRest: IRESTResponse; + lJSON: TJSONObject; +begin + lClient := TRESTClient.Create('localhost', 8080); + try + lClient.ReadTimeOut(0); + lRest := lClient.doPOST('/login', [], '{"jwtusername":"user1","jwtpassword":"user1"}'); + lJSON := StrToJSONObject(lRest.BodyAsString); + try + JWT := lJSON.S['token']; + finally + lJSON.Free; + end; + finally + lClient.Free; + end; + +end; + procedure TMainForm.SetJWT(const Value: string); begin FJWT := Value; diff --git a/sources/MVCFramework.Middleware.JWT.pas b/sources/MVCFramework.Middleware.JWT.pas index 7ac82509..54312361 100644 --- a/sources/MVCFramework.Middleware.JWT.pas +++ b/sources/MVCFramework.Middleware.JWT.pas @@ -285,8 +285,8 @@ begin // read from content if LUsername.IsEmpty then begin - LUsername := AContext.Request.ContentFields[FUserNameHeaderName]; - LPassword := AContext.Request.ContentFields[FPasswordHeaderName]; + LUsername := AContext.Request.ContentParam(FUserNameHeaderName); + LPassword := AContext.Request.ContentParam(FPasswordHeaderName); end; // read from json content diff --git a/sources/MVCFramework.pas b/sources/MVCFramework.pas index cac19a4e..d429699c 100644 --- a/sources/MVCFramework.pas +++ b/sources/MVCFramework.pas @@ -1324,7 +1324,8 @@ begin FContentFields := TDictionary.Create; for I := 0 to Pred(FWebRequest.ContentFields.Count) do begin - FContentFields.Add(LowerCase(FWebRequest.ContentFields.Names[I]), FWebRequest.ContentFields.ValueFromIndex[I]); + FContentFields.AddOrSetValue(LowerCase(FWebRequest.ContentFields.Names[I]), + FWebRequest.ContentFields.ValueFromIndex[I]); end; end; Result := FContentFields;