@@ -1,8 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using HopFrame.Api.Controller;
|
||||
using HopFrame.Database;
|
||||
using HopFrame.Security.Authentication;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace HopFrame.Api.Extensions;
|
||||
|
||||
public static class ServiceCollectionExtensions {
|
||||
|
||||
/// <summary>
|
||||
/// Adds all HopFrame endpoints and the HopFrame security layer to the WebApplication
|
||||
/// </summary>
|
||||
/// <param name="services">The service provider to add the services to</param>
|
||||
/// <typeparam name="TDbContext">The data source for all HopFrame entities</typeparam>
|
||||
public static void AddHopFrame<TDbContext>(this IServiceCollection services) where TDbContext : HopDbContextBase {
|
||||
services.AddMvcCore().UseSpecificControllers(typeof(SecurityController<TDbContext>));
|
||||
services.AddHopFrameAuthentication<TDbContext>();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
# HopFrame API module
|
||||
This module contains some useful endpoints for user login / register management.
|
||||
|
||||
## 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<DatabaseContext>();
|
||||
builder.Services.AddHopFrame<DatabaseContext>();
|
||||
```
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
# HopFrame Security module
|
||||
this module contains all handlers for the login and register validation. It also checks the user permissions.
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace HopFrame.Web;
|
||||
|
||||
[Obsolete("Use HopFrame.Security.AdminPermissions instead")]
|
||||
public static class AdminPermissions {
|
||||
public const string IsAdmin = Security.AdminPermissions.IsAdmin;
|
||||
|
||||
public const string ViewUsers = Security.AdminPermissions.ViewUsers;
|
||||
public const string EditUser = Security.AdminPermissions.EditUser;
|
||||
public const string DeleteUser = Security.AdminPermissions.DeleteUser;
|
||||
public const string AddUser = Security.AdminPermissions.AddUser;
|
||||
|
||||
public const string ViewGroups = Security.AdminPermissions.ViewGroups;
|
||||
public const string EditGroup = Security.AdminPermissions.EditGroup;
|
||||
public const string DeleteGroup = Security.AdminPermissions.DeleteGroup;
|
||||
public const string AddGroup = Security.AdminPermissions.AddGroup;
|
||||
}
|
||||
16
HopFrame.sln
16
HopFrame.sln
@@ -1,18 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Database", "HopFrame.Database\HopFrame.Database.csproj", "{003120AE-F38B-4632-8497-BE4505189627}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Database", "src\HopFrame.Database\HopFrame.Database.csproj", "{003120AE-F38B-4632-8497-BE4505189627}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Testing", "Testing", "{58703056-8DAD-4221-BBE3-42425D2F4929}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestApiTest", "test\RestApiTest\RestApiTest.csproj", "{921159CE-AF75-44C3-A3F9-6B9B1A4E85CF}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestApiTest", "RestApiTest\RestApiTest.csproj", "{921159CE-AF75-44C3-A3F9-6B9B1A4E85CF}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Security", "src\HopFrame.Security\HopFrame.Security.csproj", "{7F82E1C6-4A42-4337-9E03-2EE6429D004F}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Security", "HopFrame.Security\HopFrame.Security.csproj", "{7F82E1C6-4A42-4337-9E03-2EE6429D004F}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Api", "src\HopFrame.Api\HopFrame.Api.csproj", "{1E821490-AEDC-4F55-B758-52F4FADAB53A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Api", "HopFrame.Api\HopFrame.Api.csproj", "{1E821490-AEDC-4F55-B758-52F4FADAB53A}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Web", "src\HopFrame.Web\HopFrame.Web.csproj", "{3BE585BC-13A5-4BE4-A806-E9EC2D825956}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Web", "HopFrame.Web\HopFrame.Web.csproj", "{3BE585BC-13A5-4BE4-A806-E9EC2D825956}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrontendTest", "FrontendTest\FrontendTest.csproj", "{8F983A37-63CF-48D5-988D-58B78EF8AECD}"
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FrontendTest", "test\FrontendTest\FrontendTest.csproj", "{8F983A37-63CF-48D5-988D-58B78EF8AECD}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@@ -46,7 +44,5 @@ Global
|
||||
{8F983A37-63CF-48D5-988D-58B78EF8AECD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{921159CE-AF75-44C3-A3F9-6B9B1A4E85CF} = {58703056-8DAD-4221-BBE3-42425D2F4929}
|
||||
{8F983A37-63CF-48D5-988D-58B78EF8AECD} = {58703056-8DAD-4221-BBE3-42425D2F4929}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
||||
@@ -13,12 +13,6 @@ namespace HopFrame.Security {
|
||||
}
|
||||
}
|
||||
|
||||
namespace HopFrame.Web {
|
||||
class RegisterData {
|
||||
+RepeatedPassword: string
|
||||
}
|
||||
}
|
||||
|
||||
namespace HopFrame.Api {
|
||||
class SingleValueResult<TValue> {
|
||||
+Value: TValue
|
||||
@@ -29,6 +23,4 @@ namespace HopFrame.Api {
|
||||
}
|
||||
}
|
||||
|
||||
UserRegister <|-- RegisterData
|
||||
|
||||
@enduml
|
||||
@@ -11,9 +11,6 @@ namespace HopFrame.Database {
|
||||
}
|
||||
|
||||
class TokenEntry {
|
||||
{static} +RefreshTokenType: int = 0
|
||||
{static} +AccessTokenType: int = 1
|
||||
|
||||
+Type: int
|
||||
+Token: string
|
||||
+UserId: string
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 12 KiB |
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
13
docs/README.md
Normal file
13
docs/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# 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.
|
||||
@@ -6,16 +6,16 @@ This page shows all models that HopFrame uses.
|
||||
## Base Models
|
||||
These are the models used by the various database services.
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## API Models
|
||||
These are the models used by the REST API and the Blazor API.
|
||||
|
||||

|
||||

|
||||
|
||||
|
||||
## Database Models
|
||||
These are the models that correspond to the scheme in the Database
|
||||
|
||||

|
||||

|
||||
145
docs/services.md
Normal file
145
docs/services.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# 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<IList<User>> GetUsers();
|
||||
|
||||
Task<User> GetUser(Guid userId);
|
||||
|
||||
Task<User> GetUserByEmail(string email);
|
||||
|
||||
Task<User> GetUserByUsername(string username);
|
||||
|
||||
Task<User> AddUser(UserRegister user);
|
||||
|
||||
Task UpdateUser(User user);
|
||||
|
||||
Task DeleteUser(User user);
|
||||
|
||||
Task<bool> 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<bool> HasPermission(string permission, Guid user);
|
||||
|
||||
Task<IList<PermissionGroup>> GetPermissionGroups();
|
||||
|
||||
Task<PermissionGroup> GetPermissionGroup(string name);
|
||||
|
||||
Task EditPermissionGroup(PermissionGroup group);
|
||||
|
||||
Task<IList<PermissionGroup>> GetUserPermissionGroups(User user);
|
||||
|
||||
Task RemoveGroupFromUser(User user, PermissionGroup group);
|
||||
|
||||
Task<PermissionGroup> CreatePermissionGroup(string name, bool isDefault = false, string description = null);
|
||||
|
||||
Task DeletePermissionGroup(PermissionGroup group);
|
||||
|
||||
Task<Permission> GetPermission(string name, IPermissionOwner owner);
|
||||
|
||||
Task AddPermission(IPermissionOwner owner, string permission);
|
||||
|
||||
Task RemovePermission(Permission permission);
|
||||
|
||||
Task<string[]> 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<T>(ILogicResult<T> result);
|
||||
|
||||
public static implicit operator ActionResult(LogicResult v);
|
||||
}
|
||||
|
||||
public class LogicResult<T> : ILogicResult<T> {
|
||||
public static LogicResult<T> Ok();
|
||||
|
||||
public static LogicResult<T> Ok(T result);
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### IAuthLogic
|
||||
This service handles all logic needed to provide the authentication endpoints by using the LogicResults.
|
||||
|
||||
```csharp
|
||||
public interface IAuthLogic {
|
||||
Task<LogicResult<SingleValueResult<string>>> Login(UserLogin login);
|
||||
|
||||
Task<LogicResult<SingleValueResult<string>>> Register(UserRegister register);
|
||||
|
||||
Task<LogicResult<SingleValueResult<string>>> Authenticate();
|
||||
|
||||
Task<LogicResult> Logout();
|
||||
|
||||
Task<LogicResult> 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<bool> Login(UserLogin login);
|
||||
Task Logout();
|
||||
|
||||
Task<TokenEntry> RefreshLogin();
|
||||
Task<bool> IsLoggedIn();
|
||||
}
|
||||
```
|
||||
70
docs/usage.md
Normal file
70
docs/usage.md
Normal file
@@ -0,0 +1,70 @@
|
||||
# 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<DatabaseContext>();
|
||||
builder.Services.AddHopFrame<DatabaseContext>();
|
||||
```
|
||||
|
||||
## 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<DatabaseContext>();
|
||||
builder.Services.AddHopFrame<DatabaseContext>();
|
||||
```
|
||||
|
||||
4. Add the authentication middleware to your app
|
||||
|
||||
```csharp
|
||||
app.UseMiddleware<AuthMiddleware>();
|
||||
```
|
||||
|
||||
5. Add the HopFrame pages to your Razor components
|
||||
|
||||
```csharp
|
||||
app.MapRazorComponents<App>()
|
||||
.AddHopFrameAdminPages()
|
||||
.AddInteractiveServerRenderMode();
|
||||
```
|
||||
38
src/HopFrame.Api/Controller/SecurityController.cs
Normal file
38
src/HopFrame.Api/Controller/SecurityController.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using HopFrame.Api.Logic;
|
||||
using HopFrame.Api.Models;
|
||||
using HopFrame.Security.Authorization;
|
||||
using HopFrame.Security.Models;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace HopFrame.Api.Controller;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/v1/authentication")]
|
||||
public class SecurityController(IAuthLogic auth) : ControllerBase {
|
||||
|
||||
[HttpPut("login")]
|
||||
public async Task<ActionResult<SingleValueResult<string>>> Login([FromBody] UserLogin login) {
|
||||
return await auth.Login(login);
|
||||
}
|
||||
|
||||
[HttpPost("register")]
|
||||
public async Task<ActionResult<SingleValueResult<string>>> Register([FromBody] UserRegister register) {
|
||||
return await auth.Register(register);
|
||||
}
|
||||
|
||||
[HttpGet("authenticate")]
|
||||
public async Task<ActionResult<SingleValueResult<string>>> Authenticate() {
|
||||
return await auth.Authenticate();
|
||||
}
|
||||
|
||||
[HttpDelete("logout"), Authorized]
|
||||
public async Task<ActionResult> Logout() {
|
||||
return await auth.Logout();
|
||||
}
|
||||
|
||||
[HttpDelete("delete"), Authorized]
|
||||
public async Task<ActionResult> Delete([FromBody] UserPasswordValidation validation) {
|
||||
return await auth.Delete(validation);
|
||||
}
|
||||
|
||||
}
|
||||
36
src/HopFrame.Api/Extensions/ServiceCollectionExtensions.cs
Normal file
36
src/HopFrame.Api/Extensions/ServiceCollectionExtensions.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using HopFrame.Api.Controller;
|
||||
using HopFrame.Api.Logic;
|
||||
using HopFrame.Api.Logic.Implementation;
|
||||
using HopFrame.Database;
|
||||
using HopFrame.Security.Authentication;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection.Extensions;
|
||||
|
||||
namespace HopFrame.Api.Extensions;
|
||||
|
||||
public static class ServiceCollectionExtensions {
|
||||
|
||||
/// <summary>
|
||||
/// Adds all HopFrame endpoints and services to the application
|
||||
/// </summary>
|
||||
/// <param name="services">The service provider to add the services to</param>
|
||||
/// <typeparam name="TDbContext">The data source for all HopFrame entities</typeparam>
|
||||
public static void AddHopFrame<TDbContext>(this IServiceCollection services) where TDbContext : HopDbContextBase {
|
||||
services.AddMvcCore().UseSpecificControllers(typeof(SecurityController));
|
||||
AddHopFrameNoEndpoints<TDbContext>(services);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds all HopFrame services to the application
|
||||
/// </summary>
|
||||
/// <param name="services">The service provider to add the services to</param>
|
||||
/// <typeparam name="TDbContext">The data source for all HopFrame entities</typeparam>
|
||||
public static void AddHopFrameNoEndpoints<TDbContext>(this IServiceCollection services) where TDbContext : HopDbContextBase {
|
||||
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
|
||||
services.AddScoped<IAuthLogic, AuthLogic<TDbContext>>();
|
||||
|
||||
services.AddHopFrameAuthentication<TDbContext>();
|
||||
}
|
||||
|
||||
}
|
||||
16
src/HopFrame.Api/Logic/IAuthLogic.cs
Normal file
16
src/HopFrame.Api/Logic/IAuthLogic.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using HopFrame.Api.Models;
|
||||
using HopFrame.Security.Models;
|
||||
|
||||
namespace HopFrame.Api.Logic;
|
||||
|
||||
public interface IAuthLogic {
|
||||
Task<LogicResult<SingleValueResult<string>>> Login(UserLogin login);
|
||||
|
||||
Task<LogicResult<SingleValueResult<string>>> Register(UserRegister register);
|
||||
|
||||
Task<LogicResult<SingleValueResult<string>>> Authenticate();
|
||||
|
||||
Task<LogicResult> Logout();
|
||||
|
||||
Task<LogicResult> Delete(UserPasswordValidation validation);
|
||||
}
|
||||
@@ -1,30 +1,24 @@
|
||||
using HopFrame.Api.Logic;
|
||||
using HopFrame.Api.Models;
|
||||
using HopFrame.Database;
|
||||
using HopFrame.Database.Models.Entries;
|
||||
using HopFrame.Security.Authentication;
|
||||
using HopFrame.Security.Authorization;
|
||||
using HopFrame.Security.Claims;
|
||||
using HopFrame.Security.Models;
|
||||
using HopFrame.Security.Services;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace HopFrame.Api.Controller;
|
||||
namespace HopFrame.Api.Logic.Implementation;
|
||||
|
||||
[ApiController]
|
||||
[Route("authentication")]
|
||||
public class SecurityController<TDbContext>(TDbContext context, IUserService users, ITokenContext tokenContext) : ControllerBase where TDbContext : HopDbContextBase {
|
||||
public class AuthLogic<TDbContext>(TDbContext context, IUserService users, ITokenContext tokenContext, IHttpContextAccessor accessor) : IAuthLogic where TDbContext : HopDbContextBase {
|
||||
|
||||
[HttpPut("login")]
|
||||
public async Task<ActionResult<SingleValueResult<string>>> Login([FromBody] UserLogin login) {
|
||||
public async Task<LogicResult<SingleValueResult<string>>> Login(UserLogin login) {
|
||||
var user = await users.GetUserByEmail(login.Email);
|
||||
|
||||
if (user is null)
|
||||
return LogicResult<SingleValueResult<string>>.NotFound("The provided email address was not found");
|
||||
|
||||
if (await users.CheckUserPassword(user, login.Password))
|
||||
if (!await users.CheckUserPassword(user, login.Password))
|
||||
return LogicResult<SingleValueResult<string>>.Forbidden("The provided password is not correct");
|
||||
|
||||
var refreshToken = new TokenEntry {
|
||||
@@ -40,12 +34,12 @@ public class SecurityController<TDbContext>(TDbContext context, IUserService use
|
||||
UserId = user.Id.ToString()
|
||||
};
|
||||
|
||||
HttpContext.Response.Cookies.Append(ITokenContext.RefreshTokenType, refreshToken.Token, new CookieOptions {
|
||||
accessor.HttpContext?.Response.Cookies.Append(ITokenContext.RefreshTokenType, refreshToken.Token, new CookieOptions {
|
||||
MaxAge = HopFrameAuthentication<TDbContext>.RefreshTokenTime,
|
||||
HttpOnly = true,
|
||||
Secure = true
|
||||
});
|
||||
HttpContext.Response.Cookies.Append(ITokenContext.AccessTokenType, accessToken.Token, new CookieOptions {
|
||||
accessor.HttpContext?.Response.Cookies.Append(ITokenContext.AccessTokenType, accessToken.Token, new CookieOptions {
|
||||
MaxAge = HopFrameAuthentication<TDbContext>.AccessTokenTime,
|
||||
HttpOnly = true,
|
||||
Secure = true
|
||||
@@ -57,8 +51,7 @@ public class SecurityController<TDbContext>(TDbContext context, IUserService use
|
||||
return LogicResult<SingleValueResult<string>>.Ok(accessToken.Token);
|
||||
}
|
||||
|
||||
[HttpPost("register")]
|
||||
public async Task<ActionResult<SingleValueResult<string>>> Register([FromBody] UserRegister register) {
|
||||
public async Task<LogicResult<SingleValueResult<string>>> Register(UserRegister register) {
|
||||
if (register.Password.Length < 8)
|
||||
return LogicResult<SingleValueResult<string>>.Conflict("Password needs to be at least 8 characters long");
|
||||
|
||||
@@ -84,12 +77,12 @@ public class SecurityController<TDbContext>(TDbContext context, IUserService use
|
||||
await context.Tokens.AddRangeAsync(refreshToken, accessToken);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
HttpContext.Response.Cookies.Append(ITokenContext.RefreshTokenType, refreshToken.Token, new CookieOptions {
|
||||
accessor.HttpContext?.Response.Cookies.Append(ITokenContext.RefreshTokenType, refreshToken.Token, new CookieOptions {
|
||||
MaxAge = HopFrameAuthentication<TDbContext>.RefreshTokenTime,
|
||||
HttpOnly = true,
|
||||
Secure = true
|
||||
});
|
||||
HttpContext.Response.Cookies.Append(ITokenContext.AccessTokenType, accessToken.Token, new CookieOptions {
|
||||
accessor.HttpContext?.Response.Cookies.Append(ITokenContext.AccessTokenType, accessToken.Token, new CookieOptions {
|
||||
MaxAge = HopFrameAuthentication<TDbContext>.AccessTokenTime,
|
||||
HttpOnly = false,
|
||||
Secure = true
|
||||
@@ -98,9 +91,8 @@ public class SecurityController<TDbContext>(TDbContext context, IUserService use
|
||||
return LogicResult<SingleValueResult<string>>.Ok(accessToken.Token);
|
||||
}
|
||||
|
||||
[HttpGet("authenticate")]
|
||||
public async Task<ActionResult<SingleValueResult<string>>> Authenticate() {
|
||||
var refreshToken = HttpContext.Request.Cookies[ITokenContext.RefreshTokenType];
|
||||
public async Task<LogicResult<SingleValueResult<string>>> Authenticate() {
|
||||
var refreshToken = accessor.HttpContext?.Request.Cookies[ITokenContext.RefreshTokenType];
|
||||
|
||||
if (string.IsNullOrEmpty(refreshToken))
|
||||
return LogicResult<SingleValueResult<string>>.Conflict("Refresh token not provided");
|
||||
@@ -123,7 +115,7 @@ public class SecurityController<TDbContext>(TDbContext context, IUserService use
|
||||
await context.Tokens.AddAsync(accessToken);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
HttpContext.Response.Cookies.Append(ITokenContext.AccessTokenType, accessToken.Token, new CookieOptions {
|
||||
accessor.HttpContext?.Response.Cookies.Append(ITokenContext.AccessTokenType, accessToken.Token, new CookieOptions {
|
||||
MaxAge = HopFrameAuthentication<TDbContext>.AccessTokenTime,
|
||||
HttpOnly = false,
|
||||
Secure = true
|
||||
@@ -132,10 +124,9 @@ public class SecurityController<TDbContext>(TDbContext context, IUserService use
|
||||
return LogicResult<SingleValueResult<string>>.Ok(accessToken.Token);
|
||||
}
|
||||
|
||||
[HttpDelete("logout"), Authorized]
|
||||
public async Task<ActionResult> Logout() {
|
||||
var accessToken = HttpContext.User.GetAccessTokenId();
|
||||
var refreshToken = HttpContext.Request.Cookies[ITokenContext.RefreshTokenType];
|
||||
public async Task<LogicResult> Logout() {
|
||||
var accessToken = accessor.HttpContext?.User.GetAccessTokenId();
|
||||
var refreshToken = accessor.HttpContext?.Request.Cookies[ITokenContext.RefreshTokenType];
|
||||
|
||||
if (string.IsNullOrEmpty(accessToken) || string.IsNullOrEmpty(refreshToken))
|
||||
return LogicResult.Conflict("access or refresh token not provided");
|
||||
@@ -152,22 +143,22 @@ public class SecurityController<TDbContext>(TDbContext context, IUserService use
|
||||
context.Tokens.Remove(tokenEntries[1]);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
HttpContext.Response.Cookies.Delete(ITokenContext.RefreshTokenType);
|
||||
HttpContext.Response.Cookies.Delete(ITokenContext.AccessTokenType);
|
||||
accessor.HttpContext?.Response.Cookies.Delete(ITokenContext.RefreshTokenType);
|
||||
accessor.HttpContext?.Response.Cookies.Delete(ITokenContext.AccessTokenType);
|
||||
|
||||
return LogicResult.Ok();
|
||||
}
|
||||
|
||||
[HttpDelete("delete"), Authorized]
|
||||
public async Task<ActionResult> Delete([FromBody] UserPasswordValidation validation) {
|
||||
public async Task<LogicResult> Delete(UserPasswordValidation validation) {
|
||||
var user = tokenContext.User;
|
||||
|
||||
if (await users.CheckUserPassword(user, validation.Password))
|
||||
if (!await users.CheckUserPassword(user, validation.Password))
|
||||
return LogicResult.Forbidden("The provided password is not correct");
|
||||
|
||||
await users.DeleteUser(user);
|
||||
|
||||
HttpContext.Response.Cookies.Delete(ITokenContext.RefreshTokenType);
|
||||
accessor.HttpContext?.Response.Cookies.Delete(ITokenContext.RefreshTokenType);
|
||||
accessor.HttpContext?.Response.Cookies.Delete(ITokenContext.AccessTokenType);
|
||||
|
||||
return LogicResult.Ok();
|
||||
}
|
||||
100
src/HopFrame.Api/README.md
Normal file
100
src/HopFrame.Api/README.md
Normal file
@@ -0,0 +1,100 @@
|
||||
# HopFrame API module
|
||||
This module contains some useful endpoints for user login / register management.
|
||||
|
||||
## 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<DatabaseContext>();
|
||||
builder.Services.AddHopFrame<DatabaseContext>();
|
||||
```
|
||||
|
||||
# Endpoints
|
||||
By default, the module provides a controller for handling authentication based requests by the user.
|
||||
You can explore the contoller by the build in swagger site from ASP .NET.
|
||||
|
||||
## Disable the Endpoints
|
||||
|
||||
```csharp
|
||||
builder.Services.AddDbContext<DatabaseContext>();
|
||||
//builder.Services.AddHopFrame<DatabaseContext>();
|
||||
services.AddHopFrameNoEndpoints<TDbContext>();
|
||||
```
|
||||
|
||||
# Services added in this module
|
||||
You can use these services by specifying them as a dependency. All of them are scoped dependencies.
|
||||
|
||||
## 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<T>(ILogicResult<T> result);
|
||||
|
||||
public static implicit operator ActionResult(LogicResult v);
|
||||
}
|
||||
|
||||
public class LogicResult<T> : ILogicResult<T> {
|
||||
public static LogicResult<T> Ok();
|
||||
|
||||
public static LogicResult<T> Ok(T result);
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
## IAuthLogic
|
||||
This service handles all logic needed to provide the authentication endpoints by using the LogicResults.
|
||||
|
||||
```csharp
|
||||
public interface IAuthLogic {
|
||||
Task<LogicResult<SingleValueResult<string>>> Login(UserLogin login);
|
||||
|
||||
Task<LogicResult<SingleValueResult<string>>> Register(UserRegister register);
|
||||
|
||||
Task<LogicResult<SingleValueResult<string>>> Authenticate();
|
||||
|
||||
Task<LogicResult> Logout();
|
||||
|
||||
Task<LogicResult> Delete(UserPasswordValidation validation);
|
||||
}
|
||||
```
|
||||
74
src/HopFrame.Security/README.md
Normal file
74
src/HopFrame.Security/README.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# HopFrame Security module
|
||||
this module contains all handlers for the login and register validation. It also checks the user permissions.
|
||||
|
||||
# Services added in this module
|
||||
You can use these services by specifying them as a dependency. All of them are scoped dependencies.
|
||||
|
||||
## 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<IList<User>> GetUsers();
|
||||
|
||||
Task<User> GetUser(Guid userId);
|
||||
|
||||
Task<User> GetUserByEmail(string email);
|
||||
|
||||
Task<User> GetUserByUsername(string username);
|
||||
|
||||
Task<User> AddUser(UserRegister user);
|
||||
|
||||
Task UpdateUser(User user);
|
||||
|
||||
Task DeleteUser(User user);
|
||||
|
||||
Task<bool> 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<bool> HasPermission(string permission, Guid user);
|
||||
|
||||
Task<IList<PermissionGroup>> GetPermissionGroups();
|
||||
|
||||
Task<PermissionGroup> GetPermissionGroup(string name);
|
||||
|
||||
Task EditPermissionGroup(PermissionGroup group);
|
||||
|
||||
Task<IList<PermissionGroup>> GetUserPermissionGroups(User user);
|
||||
|
||||
Task RemoveGroupFromUser(User user, PermissionGroup group);
|
||||
|
||||
Task<PermissionGroup> CreatePermissionGroup(string name, bool isDefault = false, string description = null);
|
||||
|
||||
Task DeletePermissionGroup(PermissionGroup group);
|
||||
|
||||
Task<Permission> GetPermission(string name, IPermissionOwner owner);
|
||||
|
||||
Task AddPermission(IPermissionOwner owner, string permission);
|
||||
|
||||
Task RemovePermission(Permission permission);
|
||||
|
||||
Task<string[]> GetFullPermissions(string user);
|
||||
}
|
||||
```
|
||||
@@ -41,3 +41,20 @@ This module contains useful helpers for Blazor Apps and an Admin Dashboard.
|
||||
.AddHopFrameAdminPages()
|
||||
.AddInteractiveServerRenderMode();
|
||||
```
|
||||
|
||||
# Services added in this module
|
||||
You can use these services by specifying them as a dependency. All of them are scoped dependencies.
|
||||
|
||||
## 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<bool> Login(UserLogin login);
|
||||
Task Logout();
|
||||
|
||||
Task<TokenEntry> RefreshLogin();
|
||||
Task<bool> IsLoggedIn();
|
||||
}
|
||||
```
|
||||
@@ -19,8 +19,6 @@ public static class ServiceCollectionExtensions {
|
||||
services.AddSweetAlert2();
|
||||
services.AddBlazorStrap();
|
||||
|
||||
//TODO: Use https://blazorstrap.io/V5/V5
|
||||
|
||||
services.AddHopFrameAuthentication<TDbContext>();
|
||||
|
||||
return services;
|
||||
@@ -7,6 +7,6 @@ public class DatabaseContext : HopDbContextBase {
|
||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
||||
base.OnConfiguring(optionsBuilder);
|
||||
|
||||
optionsBuilder.UseSqlite("Data Source=C:\\Users\\Remote\\Documents\\Projekte\\HopFrame\\RestApiTest\\bin\\Debug\\net8.0\\test.db;Mode=ReadWrite;");
|
||||
optionsBuilder.UseSqlite("Data Source=C:\\Users\\Remote\\Documents\\Projekte\\HopFrame\\test\\RestApiTest\\bin\\Debug\\net8.0\\test.db;Mode=ReadWrite;");
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,6 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\HopFrame.Web\HopFrame.Web.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.7" />
|
||||
</ItemGroup>
|
||||
@@ -19,4 +15,8 @@
|
||||
<_ContentIncludedByDefault Remove="wwwroot\bootstrap\bootstrap.min.css.map" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\HopFrame.Web\HopFrame.Web.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user