Microservice Startup Template: Applications
There are 3 different applications presented in the microservice startup template;
- Authentication Server is located under apps/auth-server folder. This application is the single sign-on and single sign-out point of your application that also authenticates and authorizes your applications, gateways and microservices.
- Web (Back-office) application has Razor/MVC, Angular, Blazor WebAssembly and Blazor Server options. This is the main application of your solution and is located under the apps/web folder.
- Public Web (Landing page) application is located under apps/public-web folder. This is the front page application of your solution.
All applications have their respective solutions created already and can be developed further when required without opening the whole solution. The solutions are highlighted in the overall diagram shown below:
Authentication Server
The Authentication Server (named as AuthServer) is a web application that is used as the single sign-on authentication server. It hosts the public account pages such as login, register, forgot password, two-factor authentication, profile management... pages, OAuth endpoints, and authentication-related APIs. All applications and services use this application as a central authority for authentication. It is built upon OpenIddict library as from ABP v6.0.
AuthServer is the single sign-on and single sign-out server of the microservice template that handles authentication and authorization between applications. Consecutively, it is the most independent application that doesn't require any gateway or microservice to run. It only requires related databases up and running.
AuthServer makes directly database requests to these microservices to reach related data for operating successfully. Hence depends on IdentityService EntityFrameworkCore
, AdministrationService EntityFrameworkCore
and SaasService EntityFrameworkCore
modules and also has the configuration of related connection strings in the appsettings.json file.
Authentication & Authorization
OpenIddict Module is an implementation of the OpenIddict library that implements OpenId Connect and Oauth2.0 protocols that uses middleware for necessary protocol headers. Based on applications; different flows are used to authenticate the applications for the resources.
Single Sign-On
When logging in to an application, the user will be automatically redirected to AuthServer. If the user has already been logged in to one of the applications and tries to log in to another application, signing in will be immediately granted without prompting the login page.
Since login functionality is centralized, external logins like Azure, Google, Twitter, Facebook, etc must be implemented in AuthServerModule as well.
Data Seed
AuthServer needs an initial Openiddict and admin user data to operate. See IdentityService Data Seeding.
It is a good practice to keep your OpenIddictDataSeeder up to date whenever you expand your microservice solution with new API scopes and applications.
API Scopes
API Scopes are typically HTTP API endpoints that applications want to access. All the microservices are added as API Scopes
private async Task CreateApiScopesAsync()
{
...
await CreateScopesAsync("AccountService");
await CreateScopesAsync("IdentityService");
await CreateScopesAsync("AdministrationService");
await CreateScopesAsync("SaasService");
await CreateScopesAsync("ProductService");
}
These are the name of the scopes.
Since AuthServer itself exposes AccountManagement endpoints, it is also declared as a scope with the name AccountService.
Applications
Clients are the applications that want to reach API resources via allowed interactions (grant types) with the token server by representing a list (scopes) of what they request to do.
There are different clients seeded for the AuthServer application;
Swagger Client: There is a single swagger client named
WebGateway_Swagger
that usesauthorization_code
grant type. This swagger client is allowed for all the scopes as default and used in both gateways and all microservices for swagger authorization.Back-Office Clients:
- Web Client is the Razor/MVC application client using
hybrid
grant type. This client has all the scope allowance as default. - Angular is the spa application client using
authorization_code
grant type. This client has all the scope allowance as default. - Blazor Client is the Blazor WebAssembly application client using
authorization_code
grant type. This client has all the scope allowance as default. - Blazor Server is the application client using
hybrid
grant type. This client has all the scope allowance as default.
- Web Client is the Razor/MVC application client using
Public/Landing Page Client: Public Web application is a Razor/MVC application client using
hybrid
grant type. This client hasAccountService
,AdministrationService
andProductService
scope allowance as default.Service Clients: These are the server-to-server interactions between services. This is a
client_credentials
grant type and there is no user or user information involved in this flow.By default, AdministrationService is declared as a client. AdministrationService requires a list of user data from IdentityService. Since this endpoint is authorized with permission, required permission is also granted on the client creation. Granted permission will be seen with ProviderName
C
under AbpPermissionGrants table in the Administration database. That indicates this is aclient_credential
given permission.//Administration Service Client await CreateApplicationAsync( name: "MyProjectName_AdministrationService", type: OpenIddictConstants.ClientTypes.Confidential, consentType: OpenIddictConstants.ConsentTypes.Implicit, displayName: "Administration Service Client", secret: "1q2w3e*", grantTypes: new List<string> { OpenIddictConstants.GrantTypes.ClientCredentials }, scopes: commonScopes.Union(new[] { "IdentityService" }).ToList(), permissions: new List<string> { IdentityPermissions.Users.Default } );
Deployment
Check the OpenIddict deployment guide.
Web Application (Back-office)
This is the back-office (admin-side) application of the template. This application shows the module UI but does not host the module. Modules are hosted by related microservices and the back-office application just uses them as remote services. For more information, do check Module Architecture Best Practices & Conventions Section C.
To achieve this functionality, the back-office application needs to reference to IdentityService
, AdministrationService
, SaasService
and sample ProductService
microservices .Web
and HttpApi.Client
layers to use as remote services while microservices need to host the modules.
Therefore;
- IdentityService microservice hosts OpenIddict Management and Identity Management modules.
Identity.HttpApi.Client
project is referenced for remote service calls but since IdentityService microservice doesn't have a Web layer; module's.Web
packages are referenced explicitly. - AdministrationService microservice hosts Text-Template Management, Language Management, Audit Logging, Lepton Theme Management modules.
Administration.HttpApi.Client
is referenced for remote service calls but since AdministrationService microservice doesn't have a Web layer; module's.Web
packages are referenced explicitly. - SaasService microservice hosts Saas Tenant and Host Management module.
Saas.HttpApi.Client
is referenced for remote service calls but since SaasService microservice doesn't have a Web layer; module's.Web
packages are referenced explicitly. - ProductService microservice doesn't host any external module and has its own Web layer with a modularly developed UI. Henceforth,
ProductService.Web
andProductService.HttpApi.Client
are referenced together.
Remote Service Calls - Web Gateway
The back-office application's interactions with the microservices will be through the Web Gateway
. There is a related configuration for remote services in the appsettings.json:
"RemoteServices": {
"Default": {
"BaseUrl": "https://localhost:44325/"
}
},
This configuration indicates the default base URL of all the Http Api requests; which is the URL of the Web Gateway for the back-office application.
Application Templates
There are 4 different back-office application templates supported:
Razor/MVC
This is a server-side application that you can use both Razor Pages and MVC Controllers. As a recommended flow for server-side clients, this application uses hybrid flow. This client is being seeded in OpenIddictDataSeeder with MyProjectName_Web client name with all the available scopes.
In the WebModule authorization is configured as below to be able to make requests to all the API scopes and some basic identity scopes:
context.Services.AddAuthentication(options =>
{
...
})
.AddCookie("Cookies", options =>
{
...
})
.AddAbpOpenIdConnect("oidc", options =>
{
...
options.Scope.Add("IdentityService");
options.Scope.Add("AdministrationService");
options.Scope.Add("SaasService");
options.Scope.Add("ProductService");
});
There is also related configuration about the Authority
, ClientId
, ClientSecret
under appsettings.json:
"AuthServer": {
"Authority": "https://localhost:44322",
"RequireHttpsMetadata": "true",
"ClientId": "MyProjectName_Web",
"ClientSecret": "1q2w3e*"
},
Blazor.Server
This is the Blazor Server application that is built on top of AspNet Core SignalR with Prometheus configuration on application initialization
app.UseHttpMetrics();
...
app.UseConfiguredEndpoints(endpoints =>
{
endpoints.MapMetrics();
});
AuthServer Interaction
This application uses hybrid flow. This client is being seeded in OpenIddictDataSeeder with MyProjectName_BlazorServer client name with all the available scopes.
Since it shares the same flow with Razor/MVC application; the same configurations apply to this application type as well.
Angular
This is the SPA application used for the back-office application.
Remote Service Call
In the environment.ts file, you can find the configuration for the default remote service call and ProductService. They are both set to Web Gateway.
apis: {
default: {
url: 'https://localhost:44325',
rootNamespace: 'MyCompanyName.MyProjectName',
},
ProductService: {
url: 'https://localhost:44325',
rootNamespace: 'MyCompanyName.MyProjectName.ProductService',
},
},
AuthServer Interaction
This application uses authorization_code with PKCE (update). This client is being seeded in OpenIddictDataSeeder with MyProjectName_Angular client name with all the available scopes.
In the environment.ts file, authorization is configured as below to be able to make requests to all the API scopes:
oAuthConfig: {
issuer: 'https://localhost:44322',
redirectUri: baseUrl,
clientId: 'MyProjectName_Angular',
responseType: 'code',
scope:
'offline_access openid profile email phone IdentityService AdministrationService SaasService ProductService',
},
Blazor (Web Assembly)
This is the web assembly application of blazor UI.
AuthServer Interaction
This application uses authorization_code with PKCE (update). This client is being seeded in IdentityServerDataSeeder with MyProjectName_Blazor client name with all the available scopes.
In the BlazorModule authorization is configured as below to be able to make requests to all the API scopes:
private static void ConfigureAuthentication(WebAssemblyHostBuilder builder)
{
builder.Services.AddOidcAuthentication(options =>
{
...
options.ProviderOptions.DefaultScopes.Add("IdentityService");
options.ProviderOptions.DefaultScopes.Add("AdministrationService");
options.ProviderOptions.DefaultScopes.Add("SaasService");
options.ProviderOptions.DefaultScopes.Add("ProductService");
});
}
There is also related configuration about the Authority
, ClientId
, ResponseType
under wwwroot/appsettings.json:
"AuthServer": {
"Authority": "https://localhost:44322",
"ClientId": "MyProjectName_Blazor",
"ResponseType": "code"
},
Public Application (Landing Page)
This is the landing page application of your microservice solution. This application is Razor/MVC simply because of SEO reasons and has no other varieties by default. However, it is possible to replace or create a new public application.
This application uses the account-related functionality by hosting the Account Module API but forwarding all the requests to PublicWeb Gateway. So that application can use the functionality of just the Account Module without depending on to whole IdentityService microservice. For more information, do check Module Architecture Best Practices & Conventions Section E.
To achieve this functionality, Public Application needs to reference to Account Module .HttpApi
and HttpApi.Client
layers to host the API but proxy the request to a remote service.
Remote Service Calls - PublicWeb Gateway
The public application's interactions with the microservices will be through the PublicWeb Gateway
. There is a related configuration for remote services in the appsettings.json:
"RemoteServices": {
"Default": {
"BaseUrl": "https://localhost:44353/"
}
},
This configuration indicates the default base URL of all the HTTP API requests; which is the URL of the PublicWeb Gateway for the public application.
AuthServer Interaction
The public application uses hybrid flow and it is being seeded in OpenIddictDataSeeder with MyProjectName_PublicWeb client name with all the available scopes.
In the PublicWebModule authorization is configured as below to be able to make requests to AdministrationService and ProductService API scopes since only these two scopes were allowed in OpenIddictDataSeeder
context.Services.AddAuthentication(options =>
{
...
})
.AddCookie("Cookies", options =>
{
...
})
.AddAbpOpenIdConnect("oidc", options =>
{
...
options.Scope.Add("AdministrationService");
options.Scope.Add("ProductService");
});
There is also related configuration about the Authority
, ClientId
, ClientSecret
under appsettings.json:
"AuthServer": {
"Authority": "https://localhost:44322",
"RequireHttpsMetadata": "true",
"ClientId": "MyProjectName_PublicWeb",
"ClientSecret": "1q2w3e*"
},
Updating Scopes
If a new Scope is added to the microservice stack;
- Add the new scope to allowed scopes in OpenIddictDataSeeder web/public-web client creation.
- Add the new scope to the authentication configuration of the web/public-web application.
UI Development
It is possible to develop UI for the applications in two different ways:
Modular UI Development
Develop the application UI like any ABP application template; add UI pages under microservice's .Web project. This way, back-office application will be showing the UI without hosting the microservice application just by using it as a remote service. For more information, do check Module Architecture Best Practices & Conventions Section C.
Add microservice UI to the back-office application (Web application):
Add HttpApi.Client and .Web projects as references to Web project and add new dependencies to WebModule. Already provided sample is as below:
typeof(ProductServiceWebModule),
typeof(ProductServiceHttpApiClientModule)
ProductService.Web module is designed this way. Examine ProductService.Web project for sample implementation.
This approach may benefit from having the integrity of the backend and front-end in a microservice as a whole since it is possible to develop a microservice backend and front-end in the same microservice solution.
Monolith UI Development inside the application
Develop the application UI inside the application. Add UI pages under application's .Web project. This will allow using microservice as a remote service. You can check Module Architecture Best Practices & Conventions Section D for more information.
Add microservice UI to public-web application (PublicWeb application):
Add HttpApi.Client reference to PublicWeb project and add a new dependency to PublicWebModule as below:
typeof(ProductServiceHttpApiClientModule)
ProductService.PublicWeb module is designed this way. Examine ProductService.PublicWeb project for sample implementation.
This way it is possible to separate the frontend and backend teams and develop each of them in their respective solutions.