diff --git a/docs/Diagrams/Models/ApiModels.puml b/docs/Diagrams/Models/ApiModels.puml deleted file mode 100644 index bb5d25a..0000000 --- a/docs/Diagrams/Models/ApiModels.puml +++ /dev/null @@ -1,26 +0,0 @@ -@startuml ApiModels - -namespace HopFrame.Security { - class UserLogin { - +Email: string - +Password: string - } - - class UserRegister { - +Username: string - +Email: string - +Password: string - } -} - -namespace HopFrame.Api { - class SingleValueResult { - +Value: TValue - } - - class UserPasswordValidation { - +Password: string - } -} - -@enduml \ No newline at end of file diff --git a/docs/Diagrams/Models/BaseModels.puml b/docs/Diagrams/Models/BaseModels.puml deleted file mode 100644 index 62706fc..0000000 --- a/docs/Diagrams/Models/BaseModels.puml +++ /dev/null @@ -1,37 +0,0 @@ -@startuml BaseModels -set namespaceSeparator none - -namespace HopFrame.Database { - class User { - +Id: Guid - +Username: string - +Email: string - +CreatedAt: DateTime - +Permissions: IList - } - - class Permission { - +Id: long - +PermissionName: string - +Owner: Guid - +GrantedAt: DateTime - } - - class PermissionGroup { - +Name: string - +IsDefaultGroup: bool - +Description: string - +CreatedAt: DateTime - +Permissions: IList - } - - interface IPermissionOwner {} -} - -IPermissionOwner <|-- User -IPermissionOwner <|-- PermissionGroup - -User .. Permission -PermissionGroup .. Permission - -@enduml \ No newline at end of file diff --git a/docs/Diagrams/Models/DatabaseModels.puml b/docs/Diagrams/Models/DatabaseModels.puml deleted file mode 100644 index 2e47b5b..0000000 --- a/docs/Diagrams/Models/DatabaseModels.puml +++ /dev/null @@ -1,38 +0,0 @@ -@startuml DatabaseModels -set namespaceSeparator none - -namespace HopFrame.Database { - class UserEntry { - +Id: string - +Username: string - +Email: string - +Password: string - +CreatedAt: DateTime - } - - class TokenEntry { - +Type: int - +Token: string - +UserId: string - +CreatedAt: DateTime - } - - class PermissionEntry { - +RecordId: long - +PermissionText: string - +UserId: string - +GrantedAt: DateTime - } - - class GroupEntry { - +Name: string - +Default: bool - +Description: string - +CreatedAt: DateTime - } -} - -UserEntry *-- TokenEntry -UserEntry *-- PermissionEntry - -@enduml \ No newline at end of file diff --git a/docs/Diagrams/Models/img/ApiModels.svg b/docs/Diagrams/Models/img/ApiModels.svg deleted file mode 100644 index 76a19b4..0000000 --- a/docs/Diagrams/Models/img/ApiModels.svg +++ /dev/null @@ -1 +0,0 @@ -HopFrameSecurityApiUserLoginEmail: stringPassword: stringUserRegisterUsername: stringEmail: stringPassword: stringSingleValueResultTValueValue: TValueUserPasswordValidationPassword: string \ No newline at end of file diff --git a/docs/Diagrams/Models/img/BaseModels.svg b/docs/Diagrams/Models/img/BaseModels.svg deleted file mode 100644 index 89ed8d2..0000000 --- a/docs/Diagrams/Models/img/BaseModels.svg +++ /dev/null @@ -1 +0,0 @@ -HopFrame.DatabaseUserId: GuidUsername: stringEmail: stringCreatedAt: DateTimePermissions: IList<Permission>PermissionId: longPermissionName: stringOwner: GuidGrantedAt: DateTimePermissionGroupName: stringIsDefaultGroup: boolDescription: stringCreatedAt: DateTimePermissions: IList<Permission>IPermissionOwner \ No newline at end of file diff --git a/docs/Diagrams/Models/img/DatabaseModels.svg b/docs/Diagrams/Models/img/DatabaseModels.svg deleted file mode 100644 index fedbd56..0000000 --- a/docs/Diagrams/Models/img/DatabaseModels.svg +++ /dev/null @@ -1 +0,0 @@ -HopFrame.DatabaseUserEntryId: stringUsername: stringEmail: stringPassword: stringCreatedAt: DateTimeTokenEntryType: intToken: stringUserId: stringCreatedAt: DateTimePermissionEntryRecordId: longPermissionText: stringUserId: stringGrantedAt: DateTimeGroupEntryName: stringDefault: boolDescription: stringCreatedAt: DateTime \ No newline at end of file diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index eb4fa47..0000000 --- a/docs/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# HopFrame documentation -These sides contain all documentation available for the HopFrame modules - -## Content -| Topic | Description | Document | -|----------|------------------------------------------------|-----------------------| -| Models | All models used by the HopFrame | [link](./models.md) | -| Services | All services provided by the HopFrame | [link](./services.md) | -| Usage | How to properly implement the HopFrame modules | [link](./usage.md) | - -## Dependencies -Both the HopFrame.Api and HopFrame.Web modules are dependent on the HopFrame.Database and HopFrame.Security modules. -So all models and services provided by these modules are available in the other modules as well. diff --git a/docs/api/authorization.md b/docs/api/authorization.md new file mode 100644 index 0000000..8fe422f --- /dev/null +++ b/docs/api/authorization.md @@ -0,0 +1,30 @@ +# HopFrame Authentication + +With the provided HopFrame services, you can secure your endpoints so that only logged-in users or users with the right permissions can access the endpoint. + +## Usage +You can secure your endpoints by adding the `Authorized` attribute. + +```csharp +// Everyone can access this endpoint +[HttpGet("hello")] +public ActionResult HelloWorld() { + return "Hello, World!"; +} +``` + +```csharp +// Only logged-in users can access this endpoint +[HttpGet("hello"), Authorized] +public ActionResult HelloWorld() { + return "Hello, World!"; +} +``` + +```csharp +// Only logged-in users with the specified permissions can access this endpoint +[HttpGet("hello"), Authorized("test.permission", "test.permission.another")] +public ActionResult HelloWorld() { + return "Hello, World!"; +} +``` diff --git a/docs/api/endpoints.md b/docs/api/endpoints.md new file mode 100644 index 0000000..c02a3bc --- /dev/null +++ b/docs/api/endpoints.md @@ -0,0 +1,21 @@ +# HopFrame Endpoints +HopFrame currently only supports endpoints for authentication out of the box. + +> **Hint:** with the help of the [repositories](../repositories.md) you can very easily create missing endpoints for HopFrame components yourself. + +## All currently supported endpoints + +> **Hint:** you can use the build-in [swagger](https://swagger.io/) ui to explore and test all endpoints of your application __including__ HopFrame endpoints. + +### SecurityController +Base endpoint: `/api/v1/authentication`\ +**Important:** All primitive data types (including `string`) are return as a [`SingleValueResult`](./models.md#SingleValueResult) + + +| Method | Endpoint | Payload | Returns | +|--------|---------------|--------------------------------------------------------------|-----------------------| +| PUT | /login | [UserLogin](../models.md#UserLogin) | access token (string) | +| POST | /register | [UserRegister](../models.md#UserRegister) | access token (string) | +| GET | /authenticate | | access token (string) | +| DELETE | /logout | | | +| DELETE | /delete | [UserPasswordValidation](./models.md#UserPasswordValidation) | | diff --git a/docs/api/installation.md b/docs/api/installation.md new file mode 100644 index 0000000..66021eb --- /dev/null +++ b/docs/api/installation.md @@ -0,0 +1,16 @@ +# Ho to use the Web API version +This Installation adds all HopFrame [endpoints](./endpoints.md) and [repositories](../repositories.md) to the application. + +1. Add the HopFrame.Api library to your project: + + ``` + dotnet add package HopFrame.Api + ``` + +2. Create a [DbContext](../database.md) that inherits the ``HopDbContext`` and add a data source + +3. Add the HopFrame services to your application, provide the previously created `DatabaseContext` that inherits from `HopDbContextBase` + + ```csharp + builder.Services.AddHopFrame(); + ``` diff --git a/docs/api/logicresults.md b/docs/api/logicresults.md new file mode 100644 index 0000000..ad2fe43 --- /dev/null +++ b/docs/api/logicresults.md @@ -0,0 +1,33 @@ +# LogicResults +LogicResults provide another layer of abstraction above the ActionResults. +They help you sending the right `HttpStatusCode` with the right data. + +## Usage +1. Create an endpoint that returns an `ActionResult`: + + ```csharp + [HttpGet("hello")] + public ActionResult Hello() { + return new ActionResult("Hello, World!"); + } + ``` +2. Now instead of directly returning the `ActionResult`, return a `LogicResult` + + ```csharp + [HttpGet("hello")] + public ActionResult Hello() { + return LogicResult.Ok("Hello, World!"); + } + ``` +3. This allows you to very easily change the return type by simply calling the right function + + ```csharp + [HttpGet("hello")] + public ActionResult Hello() { + if (!Auth.IsLoggedIn) + return LogicResult.Forbidden(); + + return LogicResult.Ok("Hello, World!"); + } + ``` + > **Hint:** You can also provide an error message for status codes that are not in the 200 range. \ No newline at end of file diff --git a/docs/api/models.md b/docs/api/models.md new file mode 100644 index 0000000..c102452 --- /dev/null +++ b/docs/api/models.md @@ -0,0 +1,16 @@ +# HopFrame Models +All models used by the RestAPI are listed below + +## SingleValueResult +```csharp +public struct SingleValueResult(TValue value) { + public TValue Value { get; set; } = value; +} +``` + +## UserPasswordValidation +```csharp +public sealed class UserPasswordValidation { + public string Password { get; set; } +} +``` diff --git a/docs/blazor/admin.md b/docs/blazor/admin.md new file mode 100644 index 0000000..feec095 --- /dev/null +++ b/docs/blazor/admin.md @@ -0,0 +1,133 @@ +# HopFrame Admin Pages +Admin pages can be defined through a `AdminContext` similar to how a `DbContext` is defined. They generate administration pages like [`/administration/users`](./pages.md) +simply by reading the structure of the provided model and optionally some additional configuration. + +> **Fun fact:** The already existing pages `/administration/users` and `/administration/groups` are also generated using an internal `AdminContext`. + +## Usage +1. Create a class that inherits the `AdminPagesContext` base class + + ```csharp + public class AdminContext : AdminPagesContext { + + } + ``` + +2. Add your admin pages as properties to the class + + ```csharp + public class AdminContext : AdminPagesContext { + + public AdminPage
Addresses { get; set; } + + public AdminPage Employees { get; set; } + + } + ``` + +3. **Optionally** you can further configure your pages in the `OnModelCreating` method + + ```csharp + public class AdminContext : AdminPagesContext { + + public AdminPage
Addresses { get; set; } + public AdminPage Employees { get; set; } + + public override void OnModelCreating(IAdminContextGenerator generator) { + base.OnModelCreating(generator); + + generator.Page() + .Property(e => e.Address) + .IsSelector(); + + generator.Page
() + .Property(a => a.Employee) + .Ignore(); + + generator.Page
() + .Property(a => a.AddressId) + .IsSelector() + .Parser((model, e) => model.AddressId = e.EmployeeId); + + generator.Page() + .ConfigureRepository() + .ListingProperty(e => e.Name); + + generator.Page
() + .ConfigureRepository() + .ListingProperty(a => a.City); + } + } + ``` +4. **Optionally** you can also add some of the following attributes to your classes / properties to further configure the admin pages:\ + \ + Attributes for classes: + + ```csharp + [AttributeUsage(AttributeTargets.Class)] + public sealed class AdminButtonConfigAttribute(bool showCreateButton = true, bool showDeleteButton = true, bool showUpdateButton = true) : Attribute { + public bool ShowCreateButton { get; set; } = showCreateButton; + public bool ShowDeleteButton { get; set; } = showDeleteButton; + public bool ShowUpdateButton { get; set; } = showUpdateButton; + } + ``` + + ```csharp + [AttributeUsage(AttributeTargets.Class)] + public sealed class AdminPermissionsAttribute(string view = null, string create = null, string update = null, string delete = null) : Attribute { + public AdminPagePermissions Permissions { get; set; } = new() { + Create = create, + Update = update, + Delete = delete, + View = view + }; + } + ``` + + ```csharp + [AttributeUsage(AttributeTargets.Class)] + public class AdminUrlAttribute(string url) : Attribute { + public string Url { get; set; } = url; + } + ``` + + Attributes for properties: + + ```csharp + [AttributeUsage(AttributeTargets.Property)] + public sealed class AdminHideValueAttribute : Attribute; + ``` + + ```csharp + [AttributeUsage(AttributeTargets.Property)] + public sealed class AdminIgnoreAttribute(bool onlyForListing = false) : Attribute { + public bool OnlyForListing { get; set; } = onlyForListing; + } + ``` + + ```csharp + [AttributeUsage(AttributeTargets.Property)] + public sealed class AdminPrefixAttribute(string prefix) : Attribute { + public string Prefix { get; set; } = prefix; + } + ``` + + ```csharp + [AttributeUsage(AttributeTargets.Property)] + public sealed class AdminUneditableAttribute : Attribute; + ``` + + ```csharp + [AttributeUsage(AttributeTargets.Property)] + public class AdminUniqueAttribute : Attribute; + ``` + + ```csharp + [AttributeUsage(AttributeTargets.Property)] + public sealed class AdminUnsortableAttribute : Attribute; + ``` + + ```csharp + [AttributeUsage(AttributeTargets.Property)] + public sealed class ListingPropertyAttribute : Attribute; + ``` diff --git a/docs/blazor/auth.md b/docs/blazor/auth.md new file mode 100644 index 0000000..a759486 --- /dev/null +++ b/docs/blazor/auth.md @@ -0,0 +1,20 @@ +# Auth Service +The `IAuthService` provides some useful methods to handle user authentication (login/register). + +## Usage +Simply define the `IAuthService` as a dependency + +```csharp +public interface IAuthService { + Task Register(UserRegister register); + Task Login(UserLogin login); + Task Logout(); + + Task RefreshLogin(); + Task IsLoggedIn(); +} +``` +## Automatically refresh user sessions +1. Make sure you have implemented the `AuthMiddleware` how it's described in step 5 of the [installation](./installation.md). + +2. After that, the access token of the user gets automatically refreshed as long as the refresh token is valid. diff --git a/docs/blazor/authorization.md b/docs/blazor/authorization.md new file mode 100644 index 0000000..952de9c --- /dev/null +++ b/docs/blazor/authorization.md @@ -0,0 +1,20 @@ +# HopFrame Authentication + +With the provided HopFrame services, you can secure your blazor pages so that only logged-in users or users with the right permissions can access the page. + +## Usage +You can secure your Blazor pages by using the `AuthorizedView` component. +Everything placed inside this component will only be displayed if the authorization was successful. +You can also redirect the user if the authorization fails by specifying a `RedirectIfUnauthorized` url. + +```html + + +

This paragraph is only visible if the user is logged-in and has the required permission

+
+``` + +```html + + +``` diff --git a/docs/blazor/installation.md b/docs/blazor/installation.md new file mode 100644 index 0000000..f740b7b --- /dev/null +++ b/docs/blazor/installation.md @@ -0,0 +1,36 @@ +## How to use the Blazor API +This Installation adds all HopFrame [pages](./pages.md) and [repositories](../repositories.md) to the application. + +1. Add the HopFrame.Web library to your project + + ``` + dotnet add package HopFrame.Web + ``` + +2. Create a [DbContext](../database.md) that inherits the ``HopDbContext`` and add a data source + +3. Add the HopFrame services to your application, provide the previously created `DatabaseContext` that inherits from `HopDbContextBase` + + ```csharp + builder.Services.AddHopFrame(); + ``` + +4. **Optional:** You can also add your [AdminContext](./admin.md) + + ```csharp + builder.Services.AddAdminContext(); + ``` + +5. Add the authentication middleware to your app + + ```csharp + app.UseMiddleware(); + ``` + +6. Add the HopFrame pages to your Razor components + + ```csharp + app.MapRazorComponents() + .AddHopFrameAdminPages() + .AddInteractiveServerRenderMode(); + ``` diff --git a/docs/blazor/pages.md b/docs/blazor/pages.md new file mode 100644 index 0000000..214b771 --- /dev/null +++ b/docs/blazor/pages.md @@ -0,0 +1,14 @@ +# HopFrame Pages +By default, the HopFrame provides some blazor pages for managing user accounts and permissions + +## All currently supported blazor pages + +| Page | Endpoint | Permission | Usage | +|-----------------|------------------------|----------------------------|--------------------------------------------------------------------------------------------------------| +| Admin Dashboard | /administration | hopframe.admin | This page provides an overview to all admin pages built-in and created by [AdminContexts](./admin.md). | +| Admin Login | /administration/login | | This page is a simple login screen so no login screen needs to be created to access the admin pages. | +| User Dashboard | /administration/users | hopframe.admin.users.view | This page serves as a management site for all users and their permissions. | +| Group Dashboard | /administration/groups | hopframe.admin.groups.view | This page serves as a management site for all groups and their permissions. | + +> **Hint:** All pages created by [AdminContexts](./admin.md) are also under the `/administration/` location. This can unfortunately __not__ be changed at the moment. + diff --git a/docs/database.md b/docs/database.md new file mode 100644 index 0000000..c695a8f --- /dev/null +++ b/docs/database.md @@ -0,0 +1,35 @@ +# Database initialization +You also need to initialize the data source with the tables from HopFrame. + +## Create a DbContext + +1. Create a c# class that inherits from the `HopDbContextBase` and add a data source (In the example Sqlite is used)\ + **IMPORTANT:** You need to leave the `base.OnConfiguring(optionsBuilder)` in place so the HopFrame model relations are set correctly. + + ```csharp + public class DatabaseContext : HopDbContextBase { + protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { + base.OnConfiguring(optionsBuilder); + + optionsBuilder.UseSqlite("..."); + } + } + ``` + +2. Register the `DatabaseContext` as a service + + ```csharp + builder.Services.AddDbContext(); + ``` + +3. Create a database migration + + ```bash + dotnet ef migrations add Initial + ``` + +4. Apply the migration to the data source + + ```bash + dotnet ef database update + ``` diff --git a/docs/models.md b/docs/models.md index 6af77a4..39ecc99 100644 --- a/docs/models.md +++ b/docs/models.md @@ -1,21 +1,71 @@ -# Models for HopFrame +# HopFrame base models +All models listed below are part of the core HopFrame components and accessible in all installation variations -This page shows all models that HopFrame uses. +> **Note:** All properties of the models that are `virtual` are relational properties and don't directly correspond to columns in the database. +## User +```csharp +public class User : IPermissionOwner { + public Guid Id { get; init; } + public string Username { get; set; } + public string Email { get; set; } + public string Password { get; set; } + public DateTime CreatedAt { get; set; } + public virtual List Permissions { get; set; } + public virtual List Tokens { get; set; } +} +``` -## Base Models -These are the models used by the various database services. +## PermissionGroup +```csharp +public class PermissionGroup : IPermissionOwner { + public string Name { get; init; } + public bool IsDefaultGroup { get; set; } + public string Description { get; set; } + public DateTime CreatedAt { get; set; } + public virtual List Permissions { get; set; } +} +``` -![](./Diagrams/Models/img/BaseModels.svg) +## Permission +```csharp +public class Permission { + public long Id { get; init; } + public string PermissionName { get; set; } + public DateTime GrantedAt { get; set; } + public virtual User User { get; set; } + public virtual PermissionGroup Group { get; set; } +} +``` +## Token +```csharp +public class Token { + public int Type { get; set; } + public Guid Content { get; set; } + public DateTime CreatedAt { get; set; } + public virtual User Owner { get; set; } +} +``` -## API Models -These are the models used by the REST API and the Blazor API. +## UserLogin +```csharp +public class UserLogin { + public string Email { get; set; } + public string Password { get; set; } +} +``` -![](./Diagrams/Models/img/ApiModels.svg) +## UserRegister +```csharp +public class UserRegister { + public string Username { get; set; } + public string Email { get; set; } + public string Password { get; set; } +} +``` - -## Database Models -These are the models that correspond to the scheme in the Database - -![](./Diagrams/Models/img/DatabaseModels.svg) +## IPermissionOwner +```csharp +public interface IPermissionOwner; +``` diff --git a/docs/readme.md b/docs/readme.md new file mode 100644 index 0000000..289a64c --- /dev/null +++ b/docs/readme.md @@ -0,0 +1,25 @@ +# HopFrame Documentation + +The HopFrame comes in two variations, you can eiter only use the backend with some basic endpoints or with fully fledged blazor pages for managing HopFrame components. + +## Shared HopFrame Modules + +- [Database](./database.md) +- [Repositories](./repositories.md) +- [Base Models](./models.md) + +## HopFrame Web API + +- [Installation](./api/installation.md) +- [Endpoints](./api/endpoints.md) +- [Authorization](./api/authorization.md) +- [Models](./api/models.md) +- [LogicResults](./api/logicresults.md) + +## HopFrame Blazor library + +- [Installation](./blazor/installation.md) +- [Pages](./blazor/pages.md) +- [Authorization](./blazor/authorization.md) +- [Auth Service](./blazor/auth.md) +- [Admin Context](./blazor/admin.md) diff --git a/docs/repositories.md b/docs/repositories.md new file mode 100644 index 0000000..25cb4ac --- /dev/null +++ b/docs/repositories.md @@ -0,0 +1,75 @@ +# HopFrame Repositories +The HopFrame provies repositories for the various build in database models as an abstraction around the `HopDbContext` to ensure, that the data is proccessed and saved correctly. + +## Overview +The repositories can also be used by simply defining them as a dependency in your service / controller. + +### User Repository + +```csharp +public interface IUserRepository { + Task> GetUsers(); + + Task GetUser(Guid userId); + + Task GetUserByEmail(string email); + + Task GetUserByUsername(string username); + + Task AddUser(User user); + + Task UpdateUser(User user); + + Task DeleteUser(User user); + + Task CheckUserPassword(User user, string password); + + Task ChangePassword(User user, string password); +} +``` + +### Group Repository + +```csharp +public interface IGroupRepository { + Task> GetPermissionGroups(); + + Task> GetDefaultGroups(); + + Task> GetUserGroups(User user); + + Task GetPermissionGroup(string name); + + Task EditPermissionGroup(PermissionGroup group); + + Task CreatePermissionGroup(PermissionGroup group); + + Task DeletePermissionGroup(PermissionGroup group); +} +``` + +### Permission Repository + +```csharp +public interface IPermissionRepository { + Task HasPermission(IPermissionOwner owner, params string[] permissions); + + Task AddPermission(IPermissionOwner owner, string permission); + + Task RemovePermission(IPermissionOwner owner, string permission); + + Task> GetFullPermissions(IPermissionOwner owner); +} +``` + +### Token Repository + +```csharp +public interface ITokenRepository { + Task GetToken(string content); + + Task CreateToken(int type, User owner); + + Task DeleteUserTokens(User owner); +} +``` diff --git a/docs/services.md b/docs/services.md deleted file mode 100644 index 81a7312..0000000 --- a/docs/services.md +++ /dev/null @@ -1,145 +0,0 @@ -# HopFrame Services -This page describes all services provided by the HopFrame. -You can use these services by specifying them as a dependency. All of them are scoped dependencies. - -## HopFrame.Security -### ITokenContext -This service provides the information given by the current request - -```csharp -public interface ITokenContext { - bool IsAuthenticated { get; } - - User User { get; } - - Guid AccessToken { get; } -} -``` - -### IUserService -This service simplifies the data access of the user table in the database. - -```csharp -public interface IUserService { - Task> GetUsers(); - - Task GetUser(Guid userId); - - Task GetUserByEmail(string email); - - Task GetUserByUsername(string username); - - Task AddUser(UserRegister user); - - Task UpdateUser(User user); - - Task DeleteUser(User user); - - Task CheckUserPassword(User user, string password); - - Task ChangePassword(User user, string password); -} -``` - -### IPermissionService -This service handles all permission and group interactions with the data source. - -```csharp -public interface IPermissionService { - Task HasPermission(string permission, Guid user); - - Task> GetPermissionGroups(); - - Task GetPermissionGroup(string name); - - Task EditPermissionGroup(PermissionGroup group); - - Task> GetUserPermissionGroups(User user); - - Task RemoveGroupFromUser(User user, PermissionGroup group); - - Task CreatePermissionGroup(string name, bool isDefault = false, string description = null); - - Task DeletePermissionGroup(PermissionGroup group); - - Task GetPermission(string name, IPermissionOwner owner); - - Task AddPermission(IPermissionOwner owner, string permission); - - Task RemovePermission(Permission permission); - - Task GetFullPermissions(string user); -} -``` - -## HopFrame.Api -### LogicResult -Logic result is an extension of the ActionResult for an ApiController. It provides simple Http status results with either a message or data by specifying the generic type. - -```csharp -public class LogicResult : ILogicResult { - public static LogicResult Ok(); - - public static LogicResult BadRequest(); - - public static LogicResult BadRequest(string message); - - public static LogicResult Forbidden(); - - public static LogicResult Forbidden(string message); - - public static LogicResult NotFound(); - - public static LogicResult NotFound(string message); - - public static LogicResult Conflict(); - - public static LogicResult Conflict(string message); - - public static LogicResult Forward(LogicResult result); - - public static LogicResult Forward(ILogicResult result); - - public static implicit operator ActionResult(LogicResult v); -} - -public class LogicResult : ILogicResult { - public static LogicResult Ok(); - - public static LogicResult Ok(T result); - - ... -} -``` - -### IAuthLogic -This service handles all logic needed to provide the authentication endpoints by using the LogicResults. - -```csharp -public interface IAuthLogic { - Task>> Login(UserLogin login); - - Task>> Register(UserRegister register); - - Task>> Authenticate(); - - Task Logout(); - - Task Delete(UserPasswordValidation validation); -} -``` - -## HopFrame.Web -### IAuthService -This service handles all the authentication like login or register. It properly creates all tokens so the user can be identified - -```csharp -public interface IAuthService { - Task Register(UserRegister register); - Task Login(UserLogin login); - Task Logout(); - - Task RefreshLogin(); - Task IsLoggedIn(); -} -``` diff --git a/docs/usage.md b/docs/usage.md deleted file mode 100644 index 2023531..0000000 --- a/docs/usage.md +++ /dev/null @@ -1,70 +0,0 @@ -# HopFrame Usage -There are two different versions of HopFrame, either the Web API version or the full Blazor web version. - -## Ho to use the Web API version - -1. Add the HopFrame.Api library to your project: - - ``` - dotnet add package HopFrame.Api - ``` - -2. Create a DbContext that inherits the ``HopDbContext`` and add a data source - - ```csharp - public class DatabaseContext : HopDbContextBase { - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - base.OnConfiguring(optionsBuilder); - - optionsBuilder.UseSqlite("..."); - } - } - ``` - -3. Add the DbContext and HopFrame to your services - - ```csharp - builder.Services.AddDbContext(); - builder.Services.AddHopFrame(); - ``` - -## How to use the Blazor API - -1. Add the HopFrame.Web library to your project - - ``` - dotnet add package HopFrame.Web - ``` - -2. Create a DbContext that inherits the ``HopDbContext`` and add a data source - - ```csharp - public class DatabaseContext : HopDbContextBase { - protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - base.OnConfiguring(optionsBuilder); - - optionsBuilder.UseSqlite("..."); - } - } - ``` - -3. Add the DbContext and HopFrame to your services - - ```csharp - builder.Services.AddDbContext(); - builder.Services.AddHopFrame(); - ``` - -4. Add the authentication middleware to your app - - ```csharp - app.UseMiddleware(); - ``` - -5. Add the HopFrame pages to your Razor components - - ```csharp - app.MapRazorComponents() - .AddHopFrameAdminPages() - .AddInteractiveServerRenderMode(); - ``` diff --git a/src/HopFrame.Api/Logic/IAuthLogic.cs b/src/HopFrame.Api/Logic/IAuthLogic.cs index 7dc5b78..3dd5b5b 100644 --- a/src/HopFrame.Api/Logic/IAuthLogic.cs +++ b/src/HopFrame.Api/Logic/IAuthLogic.cs @@ -8,9 +8,18 @@ public interface IAuthLogic { Task>> Register(UserRegister register); + /// + /// Reassures that the user has a valid refresh token and generates a new access token + /// + /// The newly generated access token Task>> Authenticate(); Task Logout(); + /// + /// Deletes the user account that called the endpoint if the provided password is correct + /// + /// The password od the user + /// Task Delete(UserPasswordValidation validation); } \ No newline at end of file diff --git a/src/HopFrame.Api/Models/SingleValueResult.cs b/src/HopFrame.Api/Models/SingleValueResult.cs index c09fdb6..81cbdb4 100644 --- a/src/HopFrame.Api/Models/SingleValueResult.cs +++ b/src/HopFrame.Api/Models/SingleValueResult.cs @@ -1,5 +1,10 @@ namespace HopFrame.Api.Models; +/// +/// Useful for endpoints that only return a single int or string +/// +/// The value of the result +/// The type of the result public struct SingleValueResult(TValue value) { public TValue Value { get; set; } = value; diff --git a/src/HopFrame.Database/Repositories/IPermissionRepository.cs b/src/HopFrame.Database/Repositories/IPermissionRepository.cs index 5971e34..07680ce 100644 --- a/src/HopFrame.Database/Repositories/IPermissionRepository.cs +++ b/src/HopFrame.Database/Repositories/IPermissionRepository.cs @@ -19,5 +19,5 @@ public interface IPermissionRepository { Task RemovePermission(IPermissionOwner owner, string permission); - public Task> GetFullPermissions(IPermissionOwner owner); + Task> GetFullPermissions(IPermissionOwner owner); } \ No newline at end of file diff --git a/src/HopFrame.Database/Repositories/ITokenRepository.cs b/src/HopFrame.Database/Repositories/ITokenRepository.cs index 19b38ac..bec3963 100644 --- a/src/HopFrame.Database/Repositories/ITokenRepository.cs +++ b/src/HopFrame.Database/Repositories/ITokenRepository.cs @@ -3,7 +3,7 @@ using HopFrame.Database.Models; namespace HopFrame.Database.Repositories; public interface ITokenRepository { - public Task GetToken(string content); - public Task CreateToken(int type, User owner); - public Task DeleteUserTokens(User owner); + Task GetToken(string content); + Task CreateToken(int type, User owner); + Task DeleteUserTokens(User owner); } \ No newline at end of file diff --git a/src/HopFrame.Web.Admin/Models/AdminPageProperty.cs b/src/HopFrame.Web.Admin/Models/AdminPageProperty.cs index 8347e36..60cc763 100644 --- a/src/HopFrame.Web.Admin/Models/AdminPageProperty.cs +++ b/src/HopFrame.Web.Admin/Models/AdminPageProperty.cs @@ -1,5 +1,3 @@ -using System.Text.Json.Serialization; - namespace HopFrame.Web.Admin.Models; public sealed class AdminPageProperty { diff --git a/src/HopFrame.Web/AuthMiddleware.cs b/src/HopFrame.Web/AuthMiddleware.cs index 509ad83..33e2f52 100644 --- a/src/HopFrame.Web/AuthMiddleware.cs +++ b/src/HopFrame.Web/AuthMiddleware.cs @@ -7,6 +7,9 @@ using Microsoft.AspNetCore.Http; namespace HopFrame.Web; +/// +/// Assures that the user stays logged in even if the access token is expired +/// public sealed class AuthMiddleware(IAuthService auth, IPermissionRepository perms) : IMiddleware { public async Task InvokeAsync(HttpContext context, RequestDelegate next) { var loggedIn = await auth.IsLoggedIn(); @@ -14,7 +17,7 @@ public sealed class AuthMiddleware(IAuthService auth, IPermissionRepository perm if (!loggedIn) { var token = await auth.RefreshLogin(); if (token is null) { - await next.Invoke(context); + next?.Invoke(context); return; } diff --git a/src/HopFrame.Web/HopAdminContext.cs b/src/HopFrame.Web/HopAdminContext.cs index e0ab493..22aac7b 100644 --- a/src/HopFrame.Web/HopAdminContext.cs +++ b/src/HopFrame.Web/HopAdminContext.cs @@ -8,7 +8,7 @@ using HopFrame.Web.Repositories; namespace HopFrame.Web; -public class HopAdminContext : AdminPagesContext { +internal class HopAdminContext : AdminPagesContext { public AdminPage Users { get; set; } public AdminPage Groups { get; set; } diff --git a/src/HopFrame.Web/Pages/Administration/AdminDashboard.razor b/src/HopFrame.Web/Pages/Administration/AdminDashboard.razor index 71d3482..7ebb3cf 100644 --- a/src/HopFrame.Web/Pages/Administration/AdminDashboard.razor +++ b/src/HopFrame.Web/Pages/Administration/AdminDashboard.razor @@ -5,11 +5,14 @@ @using BlazorStrap @using HopFrame.Web.Pages.Administration.Layout @using BlazorStrap.V5 +@using HopFrame.Security @using HopFrame.Web.Admin.Providers @using HopFrame.Web.Components @using Microsoft.AspNetCore.Components.Web @layout AdminLayout + + Admin Dashboard diff --git a/src/HopFrame.Web/Pages/Administration/Layout/AdminMenu.razor b/src/HopFrame.Web/Pages/Administration/Layout/AdminMenu.razor index aae2c7f..a47bafb 100644 --- a/src/HopFrame.Web/Pages/Administration/Layout/AdminMenu.razor +++ b/src/HopFrame.Web/Pages/Administration/Layout/AdminMenu.razor @@ -30,13 +30,12 @@ } - + logged in as @Context?.User.Username - + - logout