dotnet run
In this paragraph, we are removing the ‘shared Key authentication’ (the Azure Maps subscription key) and replacing this with a more secure and production ready managed identities for Azure Maps.
Managed identities for Azure resources provide Azure services with an automatically managed application-based security principal that can authenticate with Azure AD. With Azure role-based access control (Azure RBAC), the managed identity security principal can be authorized to access Azure Maps services.
This means that the web application can request a short-lived token to get access to Azure Maps from Azure Active Directory (AAD). Because this is managed, we do not need to know any passwords or create users. However, to get this token back to the client (the Azure Maps Web Controls runs in the users’ browser), we need to create a simple token proxy API in our web application to forward this token.
We start by creating an Azure Web App where our web application will be hosted and running. This Azure Web App then needs to have rights to get a token for Azure Maps, which we will forward using the token proxy API we create in the below steps.
2.1 Create an app service plan and web app, and change the unique name and the location for your needs.
az appservice plan create -g rg-azuremaps -n plan-azuremaps -l westeurope
az webapp create -g rg-azuremaps -p plan-azuremaps -n web-azuremaps -r "dotnet:6"
2.2 Next, we create a system-assigned identity for this web app. When finished, we are presented with the principalId
, we need this in the next step. To make it simple, you can see the system-assigned identity as an account Azure manages.
az webapp identity assign -n web-azuremaps -g rg-azuremaps
2.3 Now that we have the principalId
(use this in the below command) for this system-assigned identity, we can assign the role (what can this system-assigned identity do and access). In this step, we assign the role of Azure Maps Data Reader to this system-assigned identity, which means that this system-assigned identity can only read and not modify or delete data from your Azure Maps account. You already see this is way more secure than the plain Azure Maps key, which has all the rights to do everything. We also need the [YOUR_AZURE_SUBSCRIPTION_ID]
from the first step.
az role assignment create --assignee "[PRINCIPAL_ID]" --role "Azure Maps Data Reader" --scope "/subscriptions/[YOUR_AZURE_SUBSCRIPTION_ID]/resourceGroups/rg-azuremaps/providers/Microsoft.Maps/accounts/map-azuremaps"
Hint to get your Azure subscription Id use the following command: az account subscription list
2.4 To get the access token from Azure Active Directory (AAD) back to the client (the web browser), we will create a simple proxy API forwarding this access token. We start by creating an API controller in our web application and adding the GetAzureMapsToken()
method.
2.5 First, we must add the Azure Identity NuGet package to our web application.
dotnet add package Azure.Identity
2.6 Next, we create a new ApiController.cs
file under the folder Controllers. This new ApiController.cs
file will have a method GetAzureMapsToken()
that is acting like a proxy for our access token. Read here more about Controllers in a MVC web application.
using Azure.Core;
using Azure.Identity;
using Microsoft.AspNetCore.Mvc;
namespace AzureMapsDemo.Controllers;
public class ApiController : Controller
{
private static readonly DefaultAzureCredential tokenProvider = new();
public async Task<IActionResult> GetAzureMapsToken()
{
var accessToken = await tokenProvider.GetTokenAsync(
new TokenRequestContext(new[] { "https://atlas.microsoft.com/.default" })
);
return new OkObjectResult(accessToken.Token);
}
}
2.7 Now that we have our token API proxy, we only need to change the authentication options for the Azure Maps Web Control. Replace in the file Views/Home/index.cshtml
the authOptions with the following:
// Add authentication details for connecting to Azure Maps.
authOptions: {
// Use Azure Active Directory authentication.
authType: 'anonymous',
// Your Azure Maps client id for accessing your Azure Maps account.
clientId: '[YOUR_AZUREMAPS_CLIENT_ID]',
getToken: function(resolve, reject, map) {
// URL to your authentication service that retrieves
// an Azure Active Directory Token.
var tokenServiceUrl = "/api/GetAzureMapsToken";
fetch(tokenServiceUrl).then(r => r.text()).then(token => resolve(token));
}
}
2.8 We also need to update the clientId
we saved when we created the Azure Maps account. (Optional) To get the Azure Maps Client Id again, use the value of uniqueId
from:
az maps account show -n map-azuremaps -g rg-azuremaps
2.9 Now we can build and deploy our web application that uses managed identities for Azure Maps. We first build and create a release package.
dotnet publish --configuration Release
Compress-Archive -Path binReleasenet6.0publish* -DestinationPath release1.zip
2.10 Then we publish our release package to the Azure Web App.
az webapp deployment source config-zip -g rg-azuremaps -n web-azuremaps --src release1.zip
2.11 Open a web browser and navigate to the https://web-azuremaps.azurewebsites.net/ where the web-azuremaps subdomain is your unique name when creating the Azure Web App. The application looks like this:
2.12. (Optional) We can also navigate to the token proxy API https://web-azuremaps.azurewebsites.net/api/GetAzureMapsToken, copy the token, and past this in the https://jwt.ms/ tool to decode and inspect the token.
3. Protecting the web application and the Azure Maps token proxy API
The web application we built in the last paragraph uses managed identities, and the Azure Maps Web Control uses the access token. Unfortunately, the web application and token proxy API are still accessible to everybody. Therefore, in this paragraph, we are adding the Azure Active Directory (AAD) Authentication to the web application and the token proxy API, so that only authenticated users can view the web application and use the Azure Maps Web Control in a secure way.
3.1 We start by registering an application in the Azure Active Directory, and we need this application registration later to give access to the web application and token proxy API.
az ad app create --display-name "Azure Maps Demo App" --web-redirect-uris https://web-azuremaps.azurewebsites.net/signin-oidc --enable-access-token-issuance true --enable-id-token-issuance true --sign-in-audience AzureADMyOrg
3.2 We need to add four Identity and Authentication NuGet packages to our web application.
dotnet add package Microsoft.Identity.Web
dotnet add package Microsoft.Identity.Web.UI
dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package Microsoft.AspNetCore.Authentication.OpenIdConnect
3.3 Next, we need to add the [Authorize]
attribute to every controller in our web application. Below is our token API proxy controller as an example. Do not forget to do this also for the Home controller!
using Azure.Core;
using Azure.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
namespace AzureMapsDemo.Controllers;
[Authorize]
public class ApiController : Controller
{
3.4 In the program startup file Program.cs
we need to add the Authentication and Authentication logic. Replace all the default code in the Program.cs
file with the following:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = options.DefaultPolicy;
});
builder.Services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
builder.Services.AddRazorPages()
.AddMicrosoftIdentityUI();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.MapRazorPages();
app.MapControllers();
app.Run();
3.5 The last step before redeploying our secure web application is to add the details from our registered application in the Azure Active Directory into the configuration file. Open the appsettings.json
file and replace this with:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "[PUBLISHER_DOMAIN]",
"TenantId": "[AAD_TENANT_ID]",
"ClientId": "[APP_ID]",
"CallbackPath": "/signin-oidc"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
3.6 Replace the [PUBLISHER_DOMAIN]
and [APP_ID]
with the values we saved in step 1 when we registered the application. Your Azure Active Directory Tenant ID [AAD_TENANT_ID]
, you can get with the following command:
3.7 Now we can build and deploy our web application that uses Azure Active Directory to login. We first build and create a release package.
dotnet publish --configuration Release
Compress-Archive -Path binReleasenet6.0publish* -DestinationPath release2.zip
3.8 Then we publish our release package to the Azure Web App.
az webapp deployment source config-zip -g rg-azuremaps -n web-azuremaps --src release2.zip
3.9 Open a web browser and navigate to the https://web-azuremaps.azurewebsites.net/ where the web-azuremaps subdomain is your unique name when creating the Azure Web App. You are now prompted to log in with your work or school account (AAD) and give permissions.
3.10 A recommended last step is to disable the use of the Azure Maps Key authentication.
az maps account update -n map-azuremaps -g rg-azuremaps --disable-local-auth true -s "G2"
When we have done all the steps in this step-by-step article, you have a protected web application in combination with Azure Maps that uses of Azure Active Directory, Azure role-based access control (Azure RBAC), and Azure Maps tokens. I recommend that you read our Authentication best practices and Azure Maps documentation. As an example, the Azure Maps Samples website uses most of the steps described in this article. Happy coding.
Recent Comments