diff --git a/api/Migrations/AppDbContextModelSnapshot.cs b/api/Migrations/AppDbContextModelSnapshot.cs
index 0d019e7..26b91d3 100644
--- a/api/Migrations/AppDbContextModelSnapshot.cs
+++ b/api/Migrations/AppDbContextModelSnapshot.cs
@@ -1,5 +1,6 @@
//
using System;
+using System.Collections.Generic;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
@@ -249,6 +250,10 @@ namespace agologum_api.Migrations
b.Property("PasswordHash")
.HasColumnType("text");
+ b.PrimitiveCollection>("Permissions")
+ .IsRequired()
+ .HasColumnType("text[]");
+
b.Property("PhoneNumber")
.HasColumnType("text");
diff --git a/api/Program.cs b/api/Program.cs
index 897d159..ea1bbb3 100644
--- a/api/Program.cs
+++ b/api/Program.cs
@@ -49,11 +49,9 @@ builder.Services.AddAuthentication(options => {
builder.Services.AddAuthorization(options => {
options.AddPolicy("SensitiveDataRead", policy =>
- policy.RequireRole("admin", "superuser"));
+ policy.RequireClaim("permission", Permission.SensitiveData_Read));
options.AddPolicy("SensitiveDataModify", policy =>
- policy.RequireRole("superuser"));
-
- // TODO: policies are read at runtime. define policy names in a central place and distribute the symbol
+ policy.RequireClaim("permission", Permission.SensitiveData_Modify));
});
diff --git a/api/src/Controllers/UsersController.cs b/api/src/Controllers/UsersController.cs
index 38f8d7f..4491636 100644
--- a/api/src/Controllers/UsersController.cs
+++ b/api/src/Controllers/UsersController.cs
@@ -20,7 +20,7 @@ public class UsersController : ControllerBase {
service_ = service;
}
- [Authorize(Policy = "SensitiveDataRead")]
+ [Authorize(Policy = Permission.SensitiveData_Read)]
[HttpGet]
public async Task>> getUsers() {
List rawArray = await service_.GetAll();
@@ -42,7 +42,7 @@ public class UsersController : ControllerBase {
return Ok(dtoArray);
}
- [Authorize(Policy = "SensitiveDataRead")]
+ [Authorize(Policy = Permission.SensitiveData_Read)]
[HttpGet("{id:int}")]
public async Task> getUser(string id) {
@@ -60,7 +60,7 @@ public class UsersController : ControllerBase {
return Ok(newDto);
}
- [Authorize(Policy = "SensitiveDataModify")]
+ [Authorize(Policy = Permission.SensitiveData_Modify)]
[HttpDelete("{id}")]
public async Task deleteUser(string id) {
@@ -68,6 +68,11 @@ public class UsersController : ControllerBase {
if (!success) return NotFound();
+ // TODO: set safeguard to no delete the current user
+
return NoContent();
}
+
+ // TODO: add controls on editing roles
+
}
\ No newline at end of file
diff --git a/api/src/Models/User.cs b/api/src/Models/User.cs
index a2bc758..a173bfb 100644
--- a/api/src/Models/User.cs
+++ b/api/src/Models/User.cs
@@ -7,6 +7,8 @@ public class User : IdentityUser {
public DateTime CreatedAt { get; set; }
+ public List Permissions { get; set; } = [ Permission.SensitiveData_Read, Permission.SensitiveData_Modify ]; // just seeding these here initially
+
// properties inherited from IdentityUser:
/*
AccessFailedCount: Gets or sets the number of failed login attempts for the current user.
@@ -49,7 +51,8 @@ public class LoginDto {
public class UserDto {
- public DateTime CreatedAt { get; set; } = DateTime.UtcNow; // gets compressed to a string
+ public DateTime CreatedAt { get; set; } = DateTime.UtcNow; // gets compressed to a string'
+ public List permissions { get; set; } = [];
public string? Email { get; set; } = "";
public string Id { get; set; } = "";
public string? UserName { get; set; } = "";
diff --git a/api/src/Services/JwtService.cs b/api/src/Services/JwtService.cs
index 093c792..24fa21a 100644
--- a/api/src/Services/JwtService.cs
+++ b/api/src/Services/JwtService.cs
@@ -31,21 +31,22 @@ public class JwtService {
if(user.UserName == null) return null;
- var roles = await userManager_.GetRolesAsync(user);
-
// not too sure
var claims = new List {
new Claim(ClaimTypes.Name, user.UserName),
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString())
};
- claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
+ List permissions = user.Permissions;
+ foreach(var perm in permissions) {
+ claims.Add(new Claim("permission", perm));
+ }
var token = new JwtSecurityToken(
issuer: "agologum",
audience: "agologum",
claims: claims,
- expires: DateTime.UtcNow.AddHours(2), // will add a refresher later
+ expires: DateTime.UtcNow.AddHours(2),
signingCredentials: creds
);
diff --git a/client/src/api/axios.ts b/client/src/api/axios.ts
index 8d05317..601abe3 100644
--- a/client/src/api/axios.ts
+++ b/client/src/api/axios.ts
@@ -87,4 +87,7 @@ api.interceptors.response.use(response => response, async error => { // mainly f
return Promise.reject(error);
})
+// TODO: if you get a 403 while navigating then redirect to the last authenticated page
+// if you gert a 403 on a form submissio nthen do like an unauthorized popup
+
export default api;