The HrCommonApi library is designed to serve as a foundational framework for kickstarting projects at Hogeschool Rotterdam. It aims to streamline the development process by providing essential components such as Controllers, Services, Data Entities, JWT authentication, and API Key management. This library is currently utilized by two projects:
- CargoHub for Software Construction (2024-2025)
- Calendify for Web Development (2024-2025)
While the library offers a robust set of features, it may be considered somewhat over-engineered for second-year school projects.
- Controllers: Simplified creation and management of API endpoints.
- CoreController: A solid base class for common API controllers, including request and response mapping, and a common handler for the flow.
- Services: Organized business logic with Dependency Injection support.
- CoreService: A solid base class for common CRUD actions on a DataContext, utilizing a
ServiceResult
to communicate the results of service actions.
- CoreService: A solid base class for common CRUD actions on a DataContext, utilizing a
- Data Entities: Streamlined handling of data models.
- BaseEntity: The base for all DataContext entities, providing a GUID called
Id
, aDateTime
forCreatedAt
, and aDateTime
forUpdatedAt
. The CoreService uses these fields, eliminating the need for custom code to fill or update them.
- BaseEntity: The base for all DataContext entities, providing a GUID called
- JWT Authentication: Secure user authentication using JSON Web Tokens.
- API Key Management: Control access to your API using API keys.
There are two ways to start using the HrCommonApi library:
-
Add as Project Reference:
- Clone or download this repository and add it as a project reference in your solution.
-
Use NuGet Package:
- Include the library as a reference via NuGet. You can find the package at HrCommonApi NuGet Package.
Create a configuration file (e.g., appsettings.json
) or modify it with the required sections. You will add more to this section when you make choices regarding the authentication.
After setting up the configuration section you will want to decide on what kind of authentication/authorization you want to use, if any at all. The current project offers a kind of basic Jwt authentication, and a basic Api Key authentication. You can also use both at the same time if you want that. This project uses Swagger & Swashbuckle, and provides methods of providing tokens for that as well.
If you want to use Jwt Authentication you will need to include the JwtAuthorization
configuration section in your configuration file. More on this can be found in Configuration section below.
To bootstrap for Jwt usage, inside your Program.cs
you need to include builder.Services.AddHrCommonJwtApiServices<TDataContext, TUser>(builder.Configuration)
in the builder, and app.AddHrCommonJwtApiMiddleware<TUser>(builder.Configuration)
in the app.
- The type parameter
TDataContext
needs to be theDataContext
implementation for your project.- Inside your Datacontext you need to override
OnModelCreating(ModelBuilder modelBuilder)
and have it callmodelBuilder.AddEntityModelsWithJwt<TUser>(configuration)
.
- Inside your Datacontext you need to override
- The type parameter
TUser
needs to be theUser
implementation for your project.
You can just provide User
if your use case does not require extra fields on the User
model. The standard case has a Role
in the claims and you can get the userId from the claims that you can check against the backend for additional permissions.
If you want to use Api Key Authentication you will need to include the ApiKeyAuthorization
configuration section in your configuration file. More on this can be found in Configuration section below.
To bootstrap for Api Key usage, inside your Program.cs
you need to include builder.Services.AddHrCommonKeyApiServices<TDataContext, TApiKey>(builder.Configuration)
in the builder, and app.AddHrCommonKeyApiMiddleware<TApiKey>(builder.Configuration)
in the app.
- The type parameter
TDataContext
needs to be theDataContext
implementation for your project.- Inside your Datacontext you need to override
OnModelCreating(ModelBuilder modelBuilder)
and have it callmodelBuilder.AddEntityModelsWithKey<TApiKey>(configuration)
.
- Inside your Datacontext you need to override
- The type parameter
TApiKey
needs to be theApiKey
implementation for your project.
You can just provide ApiKey
if your use case does not require extra fields on the ApiKey
model. In most cases the permissions can be dealt with in the database, as it maps them directly to your claims.
You can choose to use both types of authentication as well by using builder.Services.AddHrCommonApiServices<HrDataContext, TUser, TApiKey>(builder.Configuration)
, and app.AddHrCommonApiMiddleware<TUser, TApiKey>(builder.Configuration)
. You follow the same instructions as the individual cases for the type parameters except that in your DataContext you now use modelBuilder.AddEntityModels<TUser, TApiKey>(configuration)
. When using both at the same time your Jwt identity is supplemented by the claims from the Api Key.
If you do not wish to use any of the provided Authentication features simply use builder.Services.AddHrCommonApiServices<HrDataContext>(builder.Configuration)
, and app.AddHrCommonApiMiddleware(builder.Configuration)
. Inside your Datacontext you need to override OnModelCreating(ModelBuilder modelBuilder)
and have it call modelBuilder.AddEntityModels(configuration)
. You do not need to include any of the extra configuration sections.
Example Program.cs
for Jwt Authentication (Replace TDataContext
, TUser
):
public class Program
{
private static void Main(string[] args)
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// This bit can vary based on your choices
builder.Services.AddHrCommonJwtApiServices<TDataContext, TUser>(builder.Configuration);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
// This bit can vary based on your choices
app.AddHrCommonJwtApiMiddleware<TUser>(builder.Configuration);
app.MapControllers();
app.Run();
}
}
Example HrDataContext.cs
for Jwt Authentication (Replace TUser
):
public class HrDataContext(DbContextOptions<HrDataContext> options, IConfiguration configuration) : DbContext(options)
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.AddEntityModelsWithJwt<TUser>(configuration);
}
To use the HrCommonApi library, your project must include a configuration file (e.g., appsettings.json
). It contains the following options:
- CorsAllowOrigins (Required): Put all frontend origins in that are allowed to connect.
- ConnectionString (Required): Reference to the connection string used for the database context.
- Namespaces (Required):
- Models (Required): Namespace containing all entity models to be automatically loaded on startup.
- Profiles (Required): Namespace containing all AutoMapper profiles to be automatically loaded on startup.
- Services (Required): Namespace containing all services to be automatically added to Dependency Injection on startup.
- JwtAuthorization (Only for Jwt or mixed):
- Key: A 32-byte secret key used for signing tokens.
- Issuer: Name of the JWT issuer.
- Audience: Target audience for the tokens.
- TokenExpirationMinutes: Duration in minutes for which the token is valid (default is 60 minutes).
- RefreshExpirationInMinutes: Duration in minutes for the refresh token's validity (default is 31 days).
- ApiKeyAuthorization (Only for Api Key or mixed):
- ApiKeyName: The name of the header that will contain the API key (e.g., 'x-api-key').
- AcceptedApiKeys: An array of accepted API keys (e.g., ["6E3370BC-12FF-4692-8C6F-DE6A56AE2874"]).
"HrCommonApi": {
"CorsAllowOrigins": [ "http://localhost:5000", "http://localhost:3000" ],
"ConnectionString": "DBConnection", // A reference to the connection string you want to use for the DB context.
"Namespaces": {
"Models": "", // The namespace containing all the entity models to automatically load on startup.
"Profiles": "", // The namespace containing all Automapper profiles to automatically load on startup.
"Services": "" // The namespace containing all the services to automatically add to the Dependency Injection on startup.
},
"JwtAuthorization": {
"Jwt": {
"Key": "", // 32 bytes long secret key.
"Issuer": "", // Name of the JWT issuer.
"Audience": "", // Target Audience.
"TokenExpirationMinutes": 60, // Expiration time in minutes. (1 hour)
"RefreshExpirationInMinutes": 44640 // Expiration time in minutes. (31 days)
}
},
"ApiKeyAuthorization": {
"ApiKeyName": "x-api-key", // For example 'x-api-key'
"AcceptedApiKeys": [ "" ] // Contains an array of string, example [ '6E3370BC-12FF-4692-8C6F-DE6A56AE2874' ]
}
}
Contributions are welcome! Please feel free to submit issues or pull requests to improve the library.
The project is licensed under the GPL-3.0 License. See the LICENSE file for details.