Add UserRole handling
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
using Imprink.Domain.Repositories;
|
using Imprink.Domain.Repositories;
|
||||||
using Imprink.Domain.Repositories.Products;
|
using Imprink.Domain.Repositories.Products;
|
||||||
|
using Imprink.Domain.Repositories.Users;
|
||||||
|
|
||||||
namespace Imprink.Application;
|
namespace Imprink.Application;
|
||||||
|
|
||||||
|
|||||||
7
src/Imprink.Application/Users/Dtos/RoleDto.cs
Normal file
7
src/Imprink.Application/Users/Dtos/RoleDto.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Imprink.Application.Users.Dtos;
|
||||||
|
|
||||||
|
public class RoleDto
|
||||||
|
{
|
||||||
|
public required Guid RoleId { get; set; }
|
||||||
|
public required string RoleName { get; set; }
|
||||||
|
}
|
||||||
7
src/Imprink.Application/Users/Dtos/UserRoleDto.cs
Normal file
7
src/Imprink.Application/Users/Dtos/UserRoleDto.cs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
namespace Imprink.Application.Users.Dtos;
|
||||||
|
|
||||||
|
public class UserRoleDto
|
||||||
|
{
|
||||||
|
public required string UserId { get; set; }
|
||||||
|
public required Guid RoleId { get; set; }
|
||||||
|
}
|
||||||
@@ -1,15 +1,22 @@
|
|||||||
using Imprink.Domain.Entities.Users;
|
using Imprink.Application.Users.Dtos;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace Imprink.Application.Users;
|
namespace Imprink.Application.Users;
|
||||||
|
|
||||||
public record GetUserRolesCommand(string Sub) : IRequest<IEnumerable<Role>>;
|
public record GetUserRolesCommand(string Sub) : IRequest<IEnumerable<RoleDto>>;
|
||||||
|
|
||||||
public class GetUserRolesHandler(IUnitOfWork uw): IRequestHandler<GetUserRolesCommand, IEnumerable<Role>>
|
public class GetUserRolesHandler(IUnitOfWork uw): IRequestHandler<GetUserRolesCommand, IEnumerable<RoleDto>>
|
||||||
{
|
{
|
||||||
public async Task<IEnumerable<Role>> Handle(GetUserRolesCommand request, CancellationToken cancellationToken)
|
public async Task<IEnumerable<RoleDto>> Handle(GetUserRolesCommand request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
if (await uw.UserRepository.UserExistsAsync(request.Sub, cancellationToken)) return [];
|
if (!await uw.UserRepository.UserExistsAsync(request.Sub, cancellationToken)) return [];
|
||||||
return await uw.UserRoleRepository.GetUserRolesAsync(request.Sub, cancellationToken);;
|
|
||||||
|
var roles = await uw.UserRoleRepository.GetUserRolesAsync(request.Sub, cancellationToken);
|
||||||
|
|
||||||
|
return roles.Select(role => new RoleDto
|
||||||
|
{
|
||||||
|
RoleId = role.Id,
|
||||||
|
RoleName = role.RoleName
|
||||||
|
}).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
using Imprink.Domain.Entities.Users;
|
|
||||||
using Imprink.Domain.Repositories;
|
|
||||||
using MediatR;
|
|
||||||
|
|
||||||
namespace Imprink.Application.Users.Roles;
|
|
||||||
|
|
||||||
public record AddUserToRoleCommand(string UserId, Guid RoleId) : IRequest<bool>;
|
|
||||||
|
|
||||||
public class AddUserToRoleCommandHandler(
|
|
||||||
IUserRoleRepository userRoleRepository,
|
|
||||||
IRoleRepository roleRepository,
|
|
||||||
IUserRepository userRepository)
|
|
||||||
: IRequestHandler<AddUserToRoleCommand, bool>
|
|
||||||
{
|
|
||||||
public async Task<bool> Handle(AddUserToRoleCommand request, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var userExists = await userRepository.UserExistsAsync(request.UserId, cancellationToken);
|
|
||||||
if (!userExists)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var roleExists = await roleRepository.RoleExistsAsync(request.RoleId, cancellationToken);
|
|
||||||
if (!roleExists)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var isAlreadyInRole = await userRoleRepository.IsUserInRoleAsync(request.UserId, request.RoleId, cancellationToken);
|
|
||||||
if (isAlreadyInRole)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
var userRole = new UserRole
|
|
||||||
{
|
|
||||||
UserId = request.UserId,
|
|
||||||
RoleId = request.RoleId
|
|
||||||
};
|
|
||||||
|
|
||||||
await userRoleRepository.AddUserRoleAsync(userRole, cancellationToken);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
using Imprink.Domain.Repositories;
|
|
||||||
using MediatR;
|
|
||||||
|
|
||||||
namespace Imprink.Application.Users.Roles;
|
|
||||||
|
|
||||||
public record RemoveUserFromRoleCommand(string UserId, Guid RoleId) : IRequest<bool>;
|
|
||||||
|
|
||||||
public class RemoveUserFromRoleCommandHandler(
|
|
||||||
IUserRoleRepository userRoleRepository,
|
|
||||||
IRoleRepository roleRepository,
|
|
||||||
IUserRepository userRepository)
|
|
||||||
: IRequestHandler<RemoveUserFromRoleCommand, bool>
|
|
||||||
{
|
|
||||||
public async Task<bool> Handle(RemoveUserFromRoleCommand request, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var userExists = await userRepository.UserExistsAsync(request.UserId, cancellationToken);
|
|
||||||
if (!userExists)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var roleExists = await roleRepository.RoleExistsAsync(request.RoleId, cancellationToken);
|
|
||||||
if (!roleExists)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var userRole = await userRoleRepository.GetUserRoleAsync(request.UserId, request.RoleId, cancellationToken);
|
|
||||||
if (userRole == null)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
await userRoleRepository.RemoveUserRoleAsync(userRole, cancellationToken);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
29
src/Imprink.Application/Users/SetUserRoleHandler.cs
Normal file
29
src/Imprink.Application/Users/SetUserRoleHandler.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using Imprink.Application.Users.Dtos;
|
||||||
|
using Imprink.Domain.Entities.Users;
|
||||||
|
using MediatR;
|
||||||
|
|
||||||
|
namespace Imprink.Application.Users;
|
||||||
|
|
||||||
|
public record SetUserRoleCommand(string Sub, Guid RoleId) : IRequest<UserRoleDto?>;
|
||||||
|
|
||||||
|
public class SetUserRoleHandler(IUnitOfWork uw) : IRequestHandler<SetUserRoleCommand, UserRoleDto?>
|
||||||
|
{
|
||||||
|
public async Task<UserRoleDto?> Handle(SetUserRoleCommand request, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (!await uw.UserRepository.UserExistsAsync(request.Sub, cancellationToken)) return null;
|
||||||
|
|
||||||
|
var userRole = new UserRole
|
||||||
|
{
|
||||||
|
UserId = request.Sub,
|
||||||
|
RoleId = request.RoleId
|
||||||
|
};
|
||||||
|
|
||||||
|
var addedRole = await uw.UserRoleRepository.AddUserRoleAsync(userRole, cancellationToken);
|
||||||
|
|
||||||
|
return new UserRoleDto
|
||||||
|
{
|
||||||
|
UserId = addedRole.UserId,
|
||||||
|
RoleId = addedRole.RoleId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,13 @@
|
|||||||
using Imprink.Domain.Entities.Users;
|
using Imprink.Domain.Entities.Users;
|
||||||
|
|
||||||
namespace Imprink.Domain.Repositories;
|
namespace Imprink.Domain.Repositories.Users;
|
||||||
|
|
||||||
public interface IUserRoleRepository
|
public interface IUserRoleRepository
|
||||||
{
|
{
|
||||||
Task<IEnumerable<Role>> GetUserRolesAsync(string userId, CancellationToken cancellationToken = default);
|
Task<IEnumerable<Role>> GetUserRolesAsync(string userId, CancellationToken cancellationToken = default);
|
||||||
Task<IEnumerable<User>> GetUsersInRoleAsync(Guid roleId, CancellationToken cancellationToken = default);
|
Task<IEnumerable<User>> GetUsersInRoleAsync(Guid roleId, CancellationToken cancellationToken = default);
|
||||||
Task<bool> IsUserInRoleAsync(string userId, Guid roleId, CancellationToken cancellationToken = default);
|
|
||||||
|
|
||||||
Task<UserRole?> GetUserRoleAsync(string userId, Guid roleId, CancellationToken cancellationToken = default);
|
Task<UserRole?> GetUserRoleAsync(string userId, Guid roleId, CancellationToken cancellationToken = default);
|
||||||
Task AddUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default);
|
Task<UserRole> AddUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default);
|
||||||
Task RemoveUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default);
|
Task<UserRole> RemoveUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default);
|
||||||
Task<IEnumerable<UserRole>> GetUserRolesByUserIdAsync(string userId, CancellationToken cancellationToken = default);
|
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Imprink.Domain.Entities.Users;
|
using Imprink.Domain.Entities.Users;
|
||||||
using Imprink.Domain.Repositories;
|
using Imprink.Domain.Repositories;
|
||||||
|
using Imprink.Domain.Repositories.Users;
|
||||||
using Imprink.Infrastructure.Database;
|
using Imprink.Infrastructure.Database;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
@@ -25,12 +26,6 @@ public class UserRoleRepository(ApplicationDbContext context) : IUserRoleReposit
|
|||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> IsUserInRoleAsync(string userId, Guid roleId, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return await context.UserRole
|
|
||||||
.AnyAsync(ur => ur.UserId == userId && ur.RoleId == roleId, cancellationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<UserRole?> GetUserRoleAsync(string userId, Guid roleId, CancellationToken cancellationToken = default)
|
public async Task<UserRole?> GetUserRoleAsync(string userId, Guid roleId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
return await context.UserRole
|
return await context.UserRole
|
||||||
@@ -38,23 +33,17 @@ public class UserRoleRepository(ApplicationDbContext context) : IUserRoleReposit
|
|||||||
.FirstOrDefaultAsync(ur => ur.UserId == userId && ur.RoleId == roleId, cancellationToken);
|
.FirstOrDefaultAsync(ur => ur.UserId == userId && ur.RoleId == roleId, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task AddUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default)
|
public async Task<UserRole> AddUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
context.UserRole.Add(userRole);
|
var ur = context.UserRole.Add(userRole);
|
||||||
await context.SaveChangesAsync(cancellationToken);
|
await context.SaveChangesAsync(cancellationToken);
|
||||||
|
return ur.Entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RemoveUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default)
|
public async Task<UserRole> RemoveUserRoleAsync(UserRole userRole, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
context.UserRole.Remove(userRole);
|
var ur = context.UserRole.Remove(userRole);
|
||||||
await context.SaveChangesAsync(cancellationToken);
|
await context.SaveChangesAsync(cancellationToken);
|
||||||
}
|
return ur.Entity;
|
||||||
|
|
||||||
public async Task<IEnumerable<UserRole>> GetUserRolesByUserIdAsync(string userId, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return await context.UserRole
|
|
||||||
.AsNoTracking()
|
|
||||||
.Where(ur => ur.UserId == userId)
|
|
||||||
.ToListAsync(cancellationToken);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using Imprink.Application;
|
using Imprink.Application;
|
||||||
using Imprink.Domain.Repositories;
|
using Imprink.Domain.Repositories;
|
||||||
using Imprink.Domain.Repositories.Products;
|
using Imprink.Domain.Repositories.Products;
|
||||||
|
using Imprink.Domain.Repositories.Users;
|
||||||
using Imprink.Infrastructure.Database;
|
using Imprink.Infrastructure.Database;
|
||||||
|
|
||||||
namespace Imprink.Infrastructure;
|
namespace Imprink.Infrastructure;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using Imprink.Application.Users;
|
using Imprink.Application.Users;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
|
||||||
namespace Imprink.WebApi.Controllers.Users;
|
namespace Imprink.WebApi.Controllers.Users;
|
||||||
@@ -9,7 +10,7 @@ namespace Imprink.WebApi.Controllers.Users;
|
|||||||
[Route("/api/users/roles")]
|
[Route("/api/users/roles")]
|
||||||
public class UserRoleController(IMediator mediator) : ControllerBase
|
public class UserRoleController(IMediator mediator) : ControllerBase
|
||||||
{
|
{
|
||||||
//[Authorize]
|
[Authorize]
|
||||||
[HttpGet("me")]
|
[HttpGet("me")]
|
||||||
public async Task<IActionResult> GetMyRoles()
|
public async Task<IActionResult> GetMyRoles()
|
||||||
{
|
{
|
||||||
@@ -20,4 +21,16 @@ public class UserRoleController(IMediator mediator) : ControllerBase
|
|||||||
|
|
||||||
return Ok(myRoles);
|
return Ok(myRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Authorize(Roles = "Admin")]
|
||||||
|
[HttpPost("set")]
|
||||||
|
public async Task<IActionResult> SetUserRole(SetUserRoleCommand command)
|
||||||
|
{
|
||||||
|
var userRole = await mediator.Send(command);
|
||||||
|
|
||||||
|
if (userRole == null)
|
||||||
|
return BadRequest();
|
||||||
|
|
||||||
|
return Ok(userRole);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@ using Imprink.Application.Products.Create;
|
|||||||
using Imprink.Application.Validation.Models;
|
using Imprink.Application.Validation.Models;
|
||||||
using Imprink.Domain.Repositories;
|
using Imprink.Domain.Repositories;
|
||||||
using Imprink.Domain.Repositories.Products;
|
using Imprink.Domain.Repositories.Products;
|
||||||
|
using Imprink.Domain.Repositories.Users;
|
||||||
using Imprink.Infrastructure;
|
using Imprink.Infrastructure;
|
||||||
using Imprink.Infrastructure.Database;
|
using Imprink.Infrastructure.Database;
|
||||||
using Imprink.Infrastructure.Repositories.Products;
|
using Imprink.Infrastructure.Repositories.Products;
|
||||||
@@ -74,6 +75,7 @@ public static class Startup
|
|||||||
|
|
||||||
foreach (var role in roles) identity!.AddClaim(new Claim(ClaimTypes.Role, role));
|
foreach (var role in roles) identity!.AddClaim(new Claim(ClaimTypes.Role, role));
|
||||||
identity!.AddClaim(new Claim(ClaimTypes.Role, "User"));
|
identity!.AddClaim(new Claim(ClaimTypes.Role, "User"));
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -99,8 +101,9 @@ public static class Startup
|
|||||||
Description = "JWT Authorization header using the Bearer scheme.",
|
Description = "JWT Authorization header using the Bearer scheme.",
|
||||||
Name = "Authorization",
|
Name = "Authorization",
|
||||||
In = ParameterLocation.Header,
|
In = ParameterLocation.Header,
|
||||||
Type = SecuritySchemeType.ApiKey,
|
Type = SecuritySchemeType.Http,
|
||||||
Scheme = "Bearer"
|
Scheme = "Bearer",
|
||||||
|
BearerFormat = "JWT"
|
||||||
});
|
});
|
||||||
|
|
||||||
options.AddSecurityRequirement(new OpenApiSecurityRequirement
|
options.AddSecurityRequirement(new OpenApiSecurityRequirement
|
||||||
@@ -112,12 +115,9 @@ public static class Startup
|
|||||||
{
|
{
|
||||||
Type = ReferenceType.SecurityScheme,
|
Type = ReferenceType.SecurityScheme,
|
||||||
Id = "Bearer"
|
Id = "Bearer"
|
||||||
},
|
}
|
||||||
Scheme = "Bearer",
|
|
||||||
Name = "Bearer",
|
|
||||||
In = ParameterLocation.Header
|
|
||||||
},
|
},
|
||||||
new List<string>()
|
[]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ export default function Home() {
|
|||||||
const fetchAccessToken = async () => {
|
const fetchAccessToken = async () => {
|
||||||
if (user) {
|
if (user) {
|
||||||
try {
|
try {
|
||||||
const v = await fetch('/token');
|
await fetch('/token');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching token");
|
console.error("Error fetching token");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
const resp = await fetch('/untoken');
|
await fetch('/untoken');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('Error in /api/untoken:', e);
|
console.error('Error in /api/untoken:', e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import {cookies, headers} from 'next/headers';
|
|
||||||
import { NextResponse } from 'next/server';
|
import { NextResponse } from 'next/server';
|
||||||
import {auth0} from "@/lib/auth0";
|
import {auth0} from "@/lib/auth0";
|
||||||
import api from "@/lib/api";
|
import api from "@/lib/api";
|
||||||
@@ -9,20 +8,11 @@ export async function GET() {
|
|||||||
|
|
||||||
if (!token) { return NextResponse.json({ error: 'No access token found' }, { status: 401 }); }
|
if (!token) { return NextResponse.json({ error: 'No access token found' }, { status: 401 }); }
|
||||||
|
|
||||||
(await cookies()).set('access_token', token, {
|
|
||||||
httpOnly: true,
|
|
||||||
secure: true,
|
|
||||||
sameSite: 'strict',
|
|
||||||
path: '/',
|
|
||||||
domain: process.env.COOKIE_DOMAIN,
|
|
||||||
maxAge: 3600,
|
|
||||||
});
|
|
||||||
|
|
||||||
await api.post('/users/sync', {}, {
|
await api.post('/users/sync', {}, {
|
||||||
headers: { Cookie: `access_token=${token}` }
|
headers: { Cookie: `access_token=${token}` }
|
||||||
});
|
});
|
||||||
|
|
||||||
return NextResponse.json({ message: 'Access token set in cookie' });
|
return NextResponse.json({ access_token: token });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in /api/token:', error);
|
console.error('Error in /api/token:', error);
|
||||||
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
import {cookies} from 'next/headers';
|
|
||||||
import {NextResponse} from 'next/server';
|
|
||||||
|
|
||||||
export async function GET() {
|
|
||||||
try {
|
|
||||||
(await cookies()).set({
|
|
||||||
name: 'access_token',
|
|
||||||
value: '',
|
|
||||||
httpOnly: true,
|
|
||||||
secure: true,
|
|
||||||
sameSite: 'strict',
|
|
||||||
path: '/',
|
|
||||||
domain: process.env.COOKIE_DOMAIN,
|
|
||||||
maxAge: -1,
|
|
||||||
});
|
|
||||||
|
|
||||||
return NextResponse.json({message: 'Deleted access token'});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error in /api/untoken:', error);
|
|
||||||
return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user