Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- { *************************************************************************** }
- { }
- { Delphi MVC Framework }
- { }
- { Copyright (c) 2010-2015 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 Middleware.JwtAuthentication;
- interface
- uses
- MVCFramework,
- MVCFramework.Commons,
- MVCFramework.Logger,
- MVCFramework.JWT,
- System.Generics.Collections,
- System.DateUtils;
- type
- TMVCJwtAuthenticationMiddleware = class(TInterfacedObject, IMVCMiddleware)
- strict private
- FMVCAuthenticationHandler: IMVCAuthenticationHandler;
- procedure Render(const AErrorCode: UInt16; const AErrorMessage: string; Context: TWebContext;
- const AErrorClassName: string = ''); overload;
- protected
- FSecret: string;
- procedure OnBeforeRouting(Context: TWebContext; var Handled: Boolean);
- procedure OnAfterControllerAction(Context: TWebContext;
- const AActionName: string; const Handled: Boolean);
- procedure OnBeforeControllerAction(Context: TWebContext;
- const AControllerQualifiedClassName: string; const AActionName: string;
- var Handled: Boolean);
- public
- constructor Create(AMVCAuthenticationHandler: IMVCAuthenticationHandler;
- ASecret: string = 'DelphiMVCFramework'); virtual;
- end;
- implementation
- uses
- System.SysUtils, MVCFramework.Session
- {$IF CompilerVersion < 27}
- , Data.DBXJSON
- {$ELSE}
- , System.JSON, Web.ApacheHTTP
- {$ENDIF}
- {$IF CompilerVersion >= 21}
- , System.NetEncoding
- {$ELSE}
- , Soap.EncdDecd
- {$ENDIF};
- { TMVCSalutationMiddleware }
- constructor TMVCJwtAuthenticationMiddleware.Create(AMVCAuthenticationHandler
- : IMVCAuthenticationHandler; ASecret: string);
- begin
- inherited Create;
- FMVCAuthenticationHandler := AMVCAuthenticationHandler;
- FSecret := ASecret;
- end;
- procedure TMVCJwtAuthenticationMiddleware.OnAfterControllerAction
- (Context: TWebContext; const AActionName: string; const Handled: Boolean);
- begin
- // do nothing
- end;
- procedure TMVCJwtAuthenticationMiddleware.OnBeforeControllerAction
- (Context: TWebContext; const AControllerQualifiedClassName,
- AActionName: string; var Handled: Boolean);
- var
- lAuthRequired: Boolean;
- lIsAuthorized: Boolean;
- lIsValid: Boolean;
- lJWT: TJWT;
- lAuthHeader: string;
- lToken: string;
- lUserName: string;
- lPassWord: string;
- lRoles: TList<string>;
- lSessionData: TSessionData;
- lPair: TPair<String, String>;
- begin
- // check if the resource is protected
- FMVCAuthenticationHandler.OnRequest(AControllerQualifiedClassName,
- AActionName, LAuthRequired);
- if not LAuthRequired then
- begin
- Handled := False;
- Exit;
- end;
- if SameText(AActionName, 'Login') and (Context.Request.HTTPMethod = httpPOST) then
- begin
- lUserName:= Context.Request.Headers['UserName'];
- lPassWord:= Context.Request.Headers['PassWord'];
- if (lUserName.IsEmpty) or
- (lPassWord.IsEmpty) then
- begin
- Render(http_status.Unauthorized, 'UserName and PassWord Required', Context);
- Handled := True;
- Exit;
- end;
- // check the authorization for the requested resource
- lRoles := TList<string>.Create;
- try
- lSessionData := TSessionData.Create;
- try
- FMVCAuthenticationHandler.OnAuthentication(lUserName, lPassWord,
- lRoles, lIsValid, lSessionData);
- if LIsValid then
- begin
- lJWT := TJWT.Create(FSecret);
- try
- lJWT.Claims.Issuer := 'AraCrav app';
- lJWT.Claims.ExpirationTime := Now + OneHour;
- lJWT.Claims.NotBefore := Now - OneMinute * 5;
- lJWT.CustomClaims['username'] := lUserName;
- // Render(lJWT.GetToken);
- InternalRender(lJWT.GetToken, TMVCConstants.DEFAULT_CONTENT_TYPE, TMVCConstants.DEFAULT_CONTENT_CHARSET, Context);
- Exit;
- finally
- lJWT.Free;
- end;
- Context.LoggedUser.Roles.AddRange(LRoles);
- Context.LoggedUser.UserName := lUserName;
- Context.LoggedUser.LoggedSince := Now;
- // Context.LoggedUser.Realm := FRealm;
- Context.LoggedUser.SaveToSession(Context.Session);
- // save sessiondata to the actual session
- for LPair in lSessionData do
- begin
- Context.Session[LPair.Key] := LPair.Value;
- end;
- end;
- finally
- lSessionData.Free;
- end;
- finally
- LRoles.Free;
- end;
- end;
- lJWT := TJWT.Create(FSecret);
- try
- lAuthHeader := Context.Request.Headers['Authentication'];
- if lAuthHeader.IsEmpty then
- begin
- Render(http_status.Unauthorized, 'Authentication Required', Context);
- Handled := True;
- Exit;
- end;
- if lAuthHeader.StartsWith('bearer', True) then
- begin
- lToken := lAuthHeader.Remove(0, 'bearer'.Length).Trim;
- end;
- if not lJWT.IsValidToken(lToken) then
- begin
- Render(http_status.Unauthorized, 'Invalid Token, Authentication Required', Context);
- Handled := True;
- end
- else
- begin
- lJWT.LoadToken(lToken);
- if lJWT.CustomClaims['username'].IsEmpty then
- begin
- Render(http_status.Unauthorized, 'Invalid Token, Authentication Required', Context);
- Handled := True;
- end
- else
- begin
- lIsAuthorized:= False;
- FMVCAuthenticationHandler.OnAuthorization(Context.LoggedUser.Roles,
- AControllerQualifiedClassName, AActionName, lIsAuthorized);
- if lIsAuthorized then
- begin
- Handled := False;
- end
- else
- begin
- Render(http_status.Forbidden, 'Authorization Forbidden', Context);
- Handled := True;
- end;
- end;
- end;
- finally
- lJWT.Free;
- end;
- end;
- procedure TMVCJwtAuthenticationMiddleware.OnBeforeRouting
- (Context: TWebContext; var Handled: Boolean);
- begin
- // do nothing
- end;
- procedure TMVCJwtAuthenticationMiddleware.Render(const AErrorCode: UInt16; const AErrorMessage: string; Context: TWebContext;
- const AErrorClassName: string);
- var
- j: TJSONObject;
- status: string;
- begin
- Context.Response.StatusCode := AErrorCode;
- Context.Response.ReasonString := AErrorMessage;
- status := 'error';
- if (AErrorCode div 100) = 2 then
- status := 'ok';
- j := TJSONObject.Create;
- j.AddPair('status', status);
- if AErrorClassName = '' then
- j.AddPair('classname', TJSONNull.Create)
- else
- j.AddPair('classname', AErrorClassName);
- j.AddPair('message', AErrorMessage);
- InternalRender(j, TMVCConstants.DEFAULT_CONTENT_TYPE, TMVCConstants.DEFAULT_CONTENT_CHARSET, Context);
- end;
- end.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement