Authentication and Authorization
Go Up to Developing DataSnap Applications
Once you have a server created with some server methods, you may want to add in some logic to control who can invoke those methods. For this you can use the new and improved functionality in the TDSAuthenticationManager component.
To get started, you simply drop this component onto your form and set it as the authentication manager to use in the TDSHTTPWebDispatcher, TDHTTPService, or TDSTCPServerTransport component, depending on your server configuration.
The authentication manager has two events: OnUserAuthenticate and OnUserAuthorize. It also has a Roles collection.
This event is called when a user tries to connect (invoke a method) for the first time, and takes as input parameters connection information such as the user name and password, and allows you to set a value for the in/out parameter
valid. By default, this is set to True, but you can decide, based on user information or any other information, if you want to set
valid to True or False. Setting it to False denies user connection, and therefore denies any invocation they may have attempted.
If you decide to set
valid to True, you can also choose to populate the 'UserRoles' collection that is passed in. You can, for example, do something like this:
if (User = 'tom') and (Password = 'tom') then UserRoles.Add('admin');
This means that, if a user logs in as 'tom' with the correct password, then a role called 'admin' is set to that user. These user roles can later be used in Authorization to eliminate the need to implement the OnUserAuthorize event.
You can define Roles in several different ways. You can go to your server method class and add a TRoleAuth attribute to the code (requires Datasnap.DSAuth unit). This attribute can either be added at class level or at method level, like this:
[TRoleAuth('admin')] TServerMethods1 = class(TComponent) public function EchoString(Value: string): string; function ReverseString(Value: string): string; end;
TServerMethods1 = class(TComponent) public [TRoleAuth('admin')] function EchoString(Value: string): string; function ReverseString(Value: string): string; end;
In the first example, both 'EchoString' and 'ReverseString' would require the user to have the 'admin' role to invoke the method. In the second example, only the 'EchoString' method has the 'admin' role associated with it. Note that the TRoleAuth attribute has an optional second parameter--the 'denied roles' list--which behaves as you would expect. Both of these parameters can be a comma-separated list of roles.
You can also define roles by using the 'Roles' collection on the AuthenticationManager component. This Roles property is a collection of role items, where each role item has a class or method it applies to, and a list of authorized and/or denied roles. In AppliesTo, you can specify a class name such as TServerMethods1, which will apply to all methods of that class. You can also specify a generic method name, such as 'EchoString', which would then apply to the 'EchoString' method of any server class. Alternatively, you can specify both 'TServerMethods1.EchoString' to apply to a specific method of a specific class.
If you choose, these roles can be populated at run time. Note that, if you want to modify the collection at run time to get the instance of the AuthenticationManager, you may need to move the component that uses it out onto a data module, if you are using the component set up by the DataSnap REST Application Wizard.
The OnUserAuthorize event is called whenever a user who has already been successfully authenticated tries to invoke a server method. You do not need to implement this event. If you add roles to the UserRoles list in the OnUserAuthenticate event, then those roles alone can be used to decide whether the user has permission to invoke any given server method. However, if you want to have more control over the process (such as allowing or denying invocation based on time of day), then you can implement this event. Passed into the event is an object containing information such as the user name, the UserRoles populated in the authentication event, and the allowed/denied roles for the method called. You can use this information, as well as anything else you like, to decide on whether you want to set the value of
valid to True or False, which will allow or deny the method invocation.