This example uses our free .NET App Security & Web API Service to implement authentication and role-based data access. We ran a built-in wizard to generate a ready-to-use authentication service. This service uses Entity Framework Core to access a database. A .NET MAUI application sends requests to the Web API Service to obtain or modify data.
If you are new to the DevExpress .NET App Security & Web API Service, you may want to review the following resources:
Create a Standalone Web API Application
A 1-Click Solution for CRUD Web API with Role-based Access Control via EF Core & ASP.NET
SQL Server, if you run this solution on Windows.
-
Run Visual Studio as Administrator and open the solution. Administrator privileges allow the IDE to create a database when you run the Web Service project.
-
Select WebApi in the debug drop-down menu. This choice enables Kestrel as the web server for debug runs.
If you prefer IIS Express to Kestrel, select IIS Express in the debug drop-down menu. Use an external text editor to add the following code to
.vs\MAUI_WebAPI\config\applicationhost.config
:<sites> <site name="WebSite1" id="1" serverAutoStart="true"> <!-* ... --> <bindings> <binding protocol="http" bindingInformation="*:65201:*" /> <binding protocol="https" bindingInformation="*:44317:*" /> <binding protocol="https" bindingInformation="*:44317:localhost" /> <binding protocol="http" bindingInformation="*:65201:localhost" /> </bindings> </site> <!-* ... --> </sites>
-
Right-click the
MAUI
project, chooseSet as Startup Project
, and select your emulator. Note that physical devices that are attached over USB cannot access your machine's localhost. -
Right-click the
WebAPI
project and selectDebug > Start new instance
. -
Right-click the
MAUI
project and selectDebug > Start new instance
.
-
DevExpress Web API Service uses JSON Web Tokens (JWT) to authorize users. To obtain a token, pass username and password to the Authenticate endpoint. In this example, token generation logic is implemented in the
WebAPIService.RequestTokenAsync
method:private async Task<HttpResponseMessage> RequestTokenAsync(string userName, string password) { return await HttpClient.PostAsync($"{ApiUrl}Authentication/Authenticate", new StringContent(JsonSerializer.Serialize(new { userName, password = $"{password}" }), Encoding.UTF8, ApplicationJson)); }
Include the token in HttpClient.DefaultRequestHeaders.Authorization. All subsequent requests can then access private endpoints and data:
HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", await tokenResponse.Content.ReadAsStringAsync());
File to Look At: WebAPIService.cs
-
We implemented the following custom endpoints in the
WebApi
service:-
The CanDeletePost endpoint allows you to send a request from a mobile device to the service and check whether the current user can delete posts. This allows you to show/hide the delete button in the UI.
File to Look At: Updater.cs
-
The CurrentUser endpoint returns information about the authenticated user.
File to Look At: Updater.cs
-
The GetAuthorImage endpoint retrieves an author image by user ID.
File to Look At: Updater.cs
-
The GetPostImage endpoint retrieves an image by post ID.
File to Look At: Updater.cs
-
-
The
Updater.UpdateDatabaseAfterUpdateSchema
method generates users and specifies their login credentials. You can modify a user's password directly in the database. Note: Our cross-platform .NET Application Framework (XAF UI) allows you to quickly build a desktop or web UI that accesses the same database.File to Look At: Updater.cs
-
PermissionPolicyRole
objects in theUpdater
class add user permissions. The following code snippet calls theAddObjectPermissionFromLambda
method to configure the "Viewer" role (allow the user to read published posts):role.AddObjectPermissionFromLambda(SecurityOperations.Read, p => p.IsPublished, SecurityPermissionState.Allow);
File to Look At: Updater.cs
-
The
AddTypePermissionsRecursively
method modifies privileges for the "Editor" role (Alex, Antony, and Dennis). The method adds CRUD permissions (create, read, update, delete) for thePost
type:role.AddTypePermissionsRecursively<Post>(SecurityOperations.Read | SecurityOperations.Write | SecurityOperations.Create | SecurityOperations.DeleteObject, SecurityPermissionState.Allow);
File to Look At: Updater.cs
-
Use TextEdit.StartIcon and PasswordEdit.StartIcon properties to display icons in TextEdit and PasswordEdit controls.
<dxe:TextEdit LabelText="Login" StartIcon="editorsname" .../> <dxe:PasswordEdit LabelText="Password" StartIcon="editorspassword" .../>
File to Look At: LoginPage.xaml
-
To validate user input in the PasswordEdit control, use EditBase.HasError and EditBase.ErrorText inherited properties.
<dxe:PasswordEdit ... HasError="{Binding HasError}" ErrorText="{Binding ErrorText}"/>
File to Look At: LoginPage.xaml
public class LoginViewModel : BaseViewModel { // ... string errorText; bool hasError; // ... public string ErrorText { get => errorText; set => SetProperty(ref errorText, value); } public bool HasError { get => hasError; set => SetProperty(ref hasError, value); } async void OnLoginClicked() { /// ... string response = await DataStore.Authenticate(userName, password); if (!string.IsNullOrEmpty(response)) { ErrorText = response; HasError = true; return; } HasError = false; await Navigation.NavigateToAsync<SuccessViewModel>(); } }
File to Look At: LoginViewModel.cs
-
Specify the TextEdit.ReturnType inherited property to focus the PasswordEdit control after the TextEdit control's value is edited.
-
Use the PasswordEdit.ReturnCommand property to specify a command (Login) that runs when a user enters the password:
<dxe:PasswordEdit ReturnCommand="{Binding LoginCommand}"/>
File to Look At: LoginPage.xaml
public class LoginViewModel : BaseViewModel { // ... public LoginViewModel() { LoginCommand = new Command(OnLoginClicked); SignUpCommand = new Command(OnSignUpClicked); PropertyChanged += (_, __) => LoginCommand.ChangeCanExecute(); } // ... public Command LoginCommand { get; } public Command SignUpCommand { get; } // ... }
File to Look At: LoginViewModel.cs
-
We enabled image caching in this project. To achieve that, we needed to identify images by their Uri. To create a Uri, we use a MultiBinding that obtains the host name and the author/post ID. For additional information on image caching, refer to MAUI documentation.
<dx:DXImage> <dx:DXImage.Source> <MultiBinding StringFormat="{}{0}PublicEndpoint/PostImage/{1}"> <Binding Source="{x:Static webService:WebAPIService.ApiUrl}"/> <Binding Path="PostId"/> </MultiBinding> </dx:DXImage.Source> </dx:DXImage>
File to Look At: ItemsPage.xaml
Android emulator and iOS simulator request a certificate to access a service over HTTPS. In this example, we switch to HTTP in debug mode:
#if !DEBUG
app.UseHttpsRedirection();
#endif
<network-security-config>
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">10.0.2.2</domain>
</domain-config>
</network-security-config>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
This allows you to bypass the certificate check without the need to create a development certificate or implement HttpClient handlers.
For more information, please refer to Connect to local web services from Android emulators and iOS simulators.
We recommend that you use HTTP only when you develop/debug your application. In production, use HTTPS for security reasons.
- Featured Scenario: Role-Based Data Access
- Featured Scenarios
- Create a Standalone Web API Application
- How to Create a Web API Service Backend for a .NET MAUI Application
- Authenticate Users with the Web API Service
- DevExpress Mobile UI for .NET MAUI
(you will be redirected to DevExpress.com to submit your response)