In the previous section, I explained what a web token consists of and how you can generate it from your Delphi code. In this section, we will talk about how that token is sent to the client for further use and information sharing across different microservices.
Remember the unit we created for the token generation that had the method GetTokenFromData
? Well, we are going to use that unit in our micro services controller to generate a new token for the first time when then client logs in and pass it along to the client. We are also going to configure the message in a way that our token gets passed along to other microservices in the same group to give the user a unified login experience across multiple services.
Here’s what the code in the controller looks like followed by the explanation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
unit untAuthController;<code> interface uses MVCFramework, MVCFramework.Commons, MVCFramework.Serializer.Commons; type [MVCPath('/auth')] TAuthController = class(TMVCController) protected procedure OnBeforeAction(Context: TWebContext; const AActionName: string; var Handled: Boolean); override; procedure OnAfterAction(Context: TWebContext; const AActionName: string); override; public [MVCPath('/login')] [MVCHTTPMethod([httpGET])] procedure Login; end; implementation uses System.SysUtils, MVCFramework.Logger, System.StrUtils, wbmWebModule, System.JSON, Rest.Json, System.Generics.Collections, untTokenHelper, Web.HTTPApp, System.DateUtils; procedure TAuthController.Login; var B: Boolean; JO: TJSONObject; NC: TCookie; TK: string; begin B := untClasses.TSecurity.LoginUser(<login information such as username, password>); if not B then begin Render('{"response":"Login failed."}'); Exit; end; // the data JO := TJSONObject.Create; JO.AddPair('username', Session.Items['username']); JO.AddPair('fullname', Session.Items['fullname']); JO.AddPair('uid', Session.Items['uid']); JO.AddPair('userkind', Session.Items['userkind']); JO.AddPair('email', Session.Items['email']); // token prep TK := untTokenHelper.GetTokenFromData(JO.ToJSON, 'MySecretKeyForHashing'); // cookie configuration NC := Context.Response.Cookies.Add; NC.Expires := 0; NC.Domain := 'localhost'; NC.Name := 'authtoken'; NC.Path := '/'; NC.Value := TK; // response JO.AddPair('response', 'You are now logged in.'); Render(JO); end; |
I am going assume that you are familiar with Delphi MVC controllers so I am going to focus on explaining the code that connected with the token only.
1 2 3 4 5 6 7 8 9 10 |
// the data JO := TJSONObject.Create; JO.AddPair('username', Session.Items['username']); JO.AddPair('fullname', Session.Items['fullname']); JO.AddPair('uid', Session.Items['uid']); JO.AddPair('userkind', Session.Items['userkind']); JO.AddPair('email', Session.Items['email']); // token prep TK := untTokenHelper.GetTokenFromData(JO.ToJSON, 'MySecretKeyForHashing'); |
The above code simply prepares the data we want to send to the user and then generates the web token from it (already explained in the last section). Next is the cookie preparation:
1 2 3 4 5 6 7 |
// cookie configuration NC := Context.Response.Cookies.Add; NC.Expires := 0; NC.Domain := 'localhost'; NC.Name := 'authtoken'; NC.Path := '/'; NC.Value := TK; |
The above code adds a cookie to the response. This cookie will be stored by the browser and will be automatically be sent from the client to the server in the next request. At this point, lets delve into the cookie properties a bit. The Expires
property tell the client when the cookie will expire. In our case, the value of 0
ensure that the cookie is valid only for the session of the browser and will be removed once the browser is closed. The Domain
mentions the domain for which this cookie is set so the browser knows for which domain to send the cookie in the request. The Name
is well.. the name which is useful to identify the cookie on the server side. The Path
also specifies that the cookie only valid for a certain path within the domain. So if the request path doesn’t match the cookie path (even within the domain), the cookie will not be sent. Finally, the Value
is the actual data of the cookie, which in our case is the web token.
1 2 3 |
// response JO.AddPair('response', 'You are now logged in.'); Render(JO); |
Finally, we send response using the Render method. DMVC will automatically package the cookie in the response. Here’s what the client side response header looks like (after the server has responded). You can see that our token is present in the header and that the cookie has been set.
In the next section, I will show you how to use this token across other microservices.
One Reply on “Managing session information in web tokens in Delphi MVC Framework (Part 4)”
Un tema muy interesante y muy bien explicado, por lo menos para mi que apenas me inicio en el desarrollo web