Building a React & ASP.NET Core app and deploying to Azure is rather straight forward. However building one ready ready for production can become quite complicated because you might want to:
- Use additional services like Azure Storage, Azure Search, Azure Redis cache and therefore need a scalable way to add the service APIs to your application code.
- Implement best practices for accessing these services from your app, such as Azure Managed Service Identity(MSI) and Azure Key Vault.
- Implement Authentication using Azure AD, Single Sign On(SSO), OpenId Connect, OAuth 2.0, MFA etc.
- Fully automate provisioning of Azure resources.
- Implement CI/CD.
This is a template app, created with the intent of solving some of these problems, helpful for quick starting React & ASP.NET development in Azure. The core domain is kept as plain CRUD, so that it can be refactored to into your app quickly. Key features are :
- Single Page Application using React UI and ASP.NET Core API.
- Entity Framework Core and code first migrations.
- Capable of performing basic CRUD operations against Azure SQL Server Database and Azure Blob Storage. i.e creating, listing, updating, and deleting a bunch of items with an attached file.
- Azure Search is used for searching items and Azure Redis Cache for server side caching.
- Services and dependency injection is used in the .NET Core API for encapsulating storage, search and cache features.
- Client side state management using React hooks, custom hook for Azure Blob Storage.
- No secrets, keys, passwords are stored in config files. API accesses Azure SQL Db and Storage Account using MSI. Azure Search and Redis Cache are accessed by key retrieved from Azure Key Vault which in turn is accessed using MSI. Client app access the Azure Blob Storage using SAS token provided by the API.
- Azure Active Directory, OpenId Connect, OAuth 2.0 and implicit grant flow is used for authentication.
- Azure AD Application Roles as used for assigning permission to uses.
- Deployment is fully automated using Github actions. In around 30 mins, you will a working app with all the above features.
Fork this repo by clicking the fork button on the top-right of the repository page.
Create a resource group for holding Azure resources required for the app. You can do this by running below Azure CLI command in Azure Cloud Shell.
az group create --location {location} --name {resource group name}
example :
az group create --location southeastasia --name starter-app
Run below command to create a Service Principal scoped to the resource group created in step 2.
az ad sp create-for-rbac --name "StarterAppSP" \
--role contributor \
--scopes /subscriptions/{subscription id}/resourceGroups/{resource group name} \
--sdk-auth
example :
az ad sp create-for-rbac --name "StarterAppSP" \
--role contributor \
--scopes /subscriptions/1ee5ed92-933d-4c51-ac9f-96329a4273f7/resourceGroups/starter-app-rg
--sdk-auth
output will be like :
{
"clientId": "<GUID>",
"clientSecret": "<GUID>",
"subscriptionId": "<GUID>",
"tenantId": "<GUID>",
(...)
}
hold on to this, you will need this in step 6.
Grant Global Administrator
role to the Service Principal by following Azure Active Directory -> Roles and administrators -> Global Administrator -> Add assignments in Azure Portal.
Global Administrator
role is required for the workflow - Create Azure Ad App Registrations which creates and configures the Azure AD app registrations. This workflow needs to be run only once; so you can remove the role assignment after it completes successfully. Conversely, If you don't have necessary privileges to assign the role, or you prefer not to do so for security reasons, you can run the Azure CLI commands in the workflow file directly.
Run the following command to get the Azure Active Directory object id of the user who should have admin access to the Azure SQL database.
az ad user show --id {User Principal Name} --query objectId --out tsv
example :
az ad user show --id myuser@mydomain.com --query objectId --out tsv
You can find this by following Azure Active Directory -> Users in Azure Portal or running below command.
Create the following secrets variables under your repository - Settings -> Secrets. The secret names should match exactly what is given below.
# | Secret Name | Description |
---|---|---|
1 | APP_NAME_PREFIX | Application name prefix. This will be used as a prefix for Azure resource names e.g. Starter |
2 | AZURE_CREDENTIALS | Service Principal Details for deployment, output of step 3 |
3 | AZURE_DB_ADMIN_AAD_OBJECT_ID | Azure AD Object Id of the Azure database admin user, output of step 5 |
4 | AZURE_DB_ADMIN_USER | User name of the Azure SQL database admin user e.g. myuser@mydomain.com |
5 | AZURE_DB_ADMIN_PASSWORD | Password of the Azure database admin user |
Under Actions
in your forked repository, you will find following workflows. Run them manually by clicking workflow name -> run workflow, in the sequence given below.
# | Workflow | Description | Sequence | Triggers |
---|---|---|---|---|
1 | Create Azure Resources | Provisions Azure resources | run first | Manual |
2 | Create Azure Ad App Registrations | Registers AD Apps for API and Client in Azure AD | run after 1 | Manual |
3 | Deploy Web App | Deploys the web app to Azure App Service | run after 1 | Manual and web app code changes |
4 | Deploy Database Migrations | Applies database migrations to Azure Sql database | run after 1 | Manual and DB migration code changes |
You will get the url of the app from the output of step 1.
By default users can only view items but cannot create, modify or delete. Adding, updating and deleting items needs Item Manager role. You can assign this role by following Azure Active Directory -> Enterprise Applications( select Application Type "All Applications") -> Enter the API app name e.g. "Starter API App"> -> User and groups -> Add user -> Add assignment in Azure portal.
You can also do this by running following PowerShell command from Azure Cloud Shell.
New-AzureADUserAppRoleAssignment `
-ObjectId {Object id of the Users Service Principal} `
-Id {Object id of ItemManager Role} `
-PrincipalId {Object id of the Users Principal} `
-ResourceId {Object Id of the API App Service Principal}
Clone this repo locally. e.g. git clone git@github.com:bablulawrence/starter-react-dotnetcore.git
.
You need below software and tools for ideal development experience :
- .NET Core 3.1
- Node.js and npm
- Create React App
- Entity Framework Core
- SQL Server or SQL Express
- Azure Storage Explorer
- Visual Studio Code or Visual Studio
The .env.development file holds the Azure AD details for the Client App. Similarly appsettings.json and appsettings.development.json together hold the values for the API app. Update all three files with Azure AD and Azure Resource details.
Execute dotnet run
from folder /src/Web
to run the API app and npm start
from folder /src/Web/ClientApp
to run the Client App. You can also run them together from VS Code or Visual Studio.
To test the API app operations, you can use Postman, SoapUI, VS Code REST Client extension etc. Preferable way for generating an access token with necessary permissions for the API is to create a Daemon app to represent tool you want to use. Make sure to assign ItemManager role to the Daemon app by following step 8. You might also be able to use user identities if you tool supports implicit grant flow.
Alternatively, you can also generate the access token by following Azure CLI command.
az account get-access-token --resource {App id URI of the API app}
example:
az account get-access-token --resource https://starter-lgjsmbvlver5g-web-app.azurewebsites.net
. Subsequently you can use Curl, Postman etc. to invoke API operations by providing the access token in the call header.
By default Azure CLI wont have permission for the API. You will need to pre-authorize the Azure CLI on the API app to provide access. This can be done by following Azure Active Directory -> App registrations -> Enter the API app name e.g. "Starter API App"> -> Expose an API -> Authorized client applications -> Add a client application -> Enter Client ID of Azure CLI in Azure Active Directory i.e 04b07795-8ddb-461a-bbee-02f9e1bf7b46 -> Select the scope StarterApp.ReadWrite in Azure portal.