Services, service registration and dependency injection for auth
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
using AipsCore.Domain.Models.User;
|
||||
|
||||
namespace AipsCore.Application.Abstract.UserContext;
|
||||
|
||||
public interface ITokenProvider
|
||||
{
|
||||
string Generate(User user, IList<string> roles);
|
||||
}
|
||||
3
dotnet/AipsCore/Application/Authentication/Token.cs
Normal file
3
dotnet/AipsCore/Application/Authentication/Token.cs
Normal file
@@ -0,0 +1,3 @@
|
||||
namespace AipsCore.Application.Authentication;
|
||||
|
||||
public record Token(string Value);
|
||||
@@ -14,7 +14,7 @@ public static class AipsRegistrationExtensions
|
||||
|
||||
services.AddPersistence(configuration);
|
||||
|
||||
services.AddUserContext();
|
||||
services.AddUserContext(configuration);
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,67 @@
|
||||
using System.Text;
|
||||
using AipsCore.Application.Abstract.UserContext;
|
||||
using AipsCore.Infrastructure.Persistence.Authentication;
|
||||
using AipsCore.Infrastructure.Persistence.Db;
|
||||
using AipsCore.Infrastructure.Persistence.User;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace AipsCore.Infrastructure.DI;
|
||||
|
||||
public static class UserContextRegistrationExtension
|
||||
{
|
||||
public static IServiceCollection AddUserContext(this IServiceCollection services)
|
||||
public static IServiceCollection AddUserContext(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
services.AddTransient<IUserContext, UserContext>();
|
||||
var jwtSettings = new JwtSettings
|
||||
{
|
||||
Issuer = configuration["JWT_ISSUER"]!,
|
||||
Audience = configuration["JWT_AUDIENCE"]!,
|
||||
Key = configuration["JWT_KEY"]!,
|
||||
ExpirationMinutes = int.Parse(configuration["JWT_EXPIRATION_MINUTES"] ?? "60")
|
||||
};
|
||||
|
||||
services.AddSingleton(jwtSettings);
|
||||
|
||||
services.AddHttpContextAccessor();
|
||||
|
||||
services.AddIdentityCore<User>(options =>
|
||||
{
|
||||
options.Password.RequiredLength = 8;
|
||||
options.Password.RequireDigit = true;
|
||||
options.Password.RequireLowercase = true;
|
||||
options.Password.RequireUppercase = true;
|
||||
options.Password.RequireNonAlphanumeric = true;
|
||||
|
||||
options.User.RequireUniqueEmail = true;
|
||||
})
|
||||
.AddRoles<IdentityRole<Guid>>()
|
||||
.AddEntityFrameworkStores<AipsDbContext>()
|
||||
.AddSignInManager()
|
||||
.AddDefaultTokenProviders();
|
||||
|
||||
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = jwtSettings.Issuer,
|
||||
ValidAudience = jwtSettings.Audience,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(
|
||||
Encoding.UTF8.GetBytes(jwtSettings.Key))
|
||||
};
|
||||
});
|
||||
|
||||
services.AddAuthorization();
|
||||
|
||||
services.AddTransient<IUserContext, HttpUserContext>();
|
||||
services.AddTransient<ITokenProvider, JwtTokenProvider>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Security.Claims;
|
||||
using AipsCore.Application.Abstract.UserContext;
|
||||
using AipsCore.Domain.Models.User.ValueObjects;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
namespace AipsCore.Infrastructure.Persistence.Authentication;
|
||||
|
||||
public class HttpUserContext : IUserContext
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
|
||||
public HttpUserContext(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public UserId GetCurrentUserId()
|
||||
{
|
||||
var user = _httpContextAccessor.HttpContext?.User;
|
||||
|
||||
if (user is null || !user.Identity!.IsAuthenticated)
|
||||
{
|
||||
throw new UnauthorizedAccessException("User is not authenticated");
|
||||
}
|
||||
|
||||
var userIdClaim = user.FindFirst(ClaimTypes.NameIdentifier);
|
||||
|
||||
if (userIdClaim is null)
|
||||
{
|
||||
throw new UnauthorizedAccessException("User id claim not found");
|
||||
}
|
||||
|
||||
return new UserId(userIdClaim.Value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace AipsCore.Infrastructure.Persistence.Authentication;
|
||||
|
||||
public sealed class JwtSettings
|
||||
{
|
||||
public string Issuer { get; init; } = null!;
|
||||
public string Audience { get; init; } = null!;
|
||||
public string Key { get; init; } = null!;
|
||||
public int ExpirationMinutes { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using AipsCore.Application.Abstract.UserContext;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace AipsCore.Infrastructure.Persistence.Authentication;
|
||||
|
||||
public class JwtTokenProvider : ITokenProvider
|
||||
{
|
||||
private readonly JwtSettings _jwtSettings;
|
||||
|
||||
public JwtTokenProvider(JwtSettings jwtSettings)
|
||||
{
|
||||
_jwtSettings = jwtSettings;
|
||||
}
|
||||
|
||||
public string Generate(Domain.Models.User.User user, IList<string> roles)
|
||||
{
|
||||
var claims = new List<Claim>
|
||||
{
|
||||
new Claim(ClaimTypes.NameIdentifier, user.Id.IdValue),
|
||||
new Claim(ClaimTypes.Email, user.Email.EmailValue)
|
||||
};
|
||||
|
||||
foreach (var role in roles)
|
||||
{
|
||||
claims.Add(new Claim(ClaimTypes.Role, role));
|
||||
}
|
||||
|
||||
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Key));
|
||||
|
||||
var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
|
||||
|
||||
var token = new JwtSecurityToken(
|
||||
issuer: _jwtSettings.Issuer,
|
||||
audience: _jwtSettings.Audience,
|
||||
claims: claims,
|
||||
expires: DateTime.UtcNow.AddMinutes(_jwtSettings.ExpirationMinutes),
|
||||
signingCredentials: credentials);
|
||||
|
||||
return new JwtSecurityTokenHandler().WriteToken(token);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,11 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace AipsCore.Infrastructure.Persistence.Db;
|
||||
|
||||
public class AipsDbContext : DbContext
|
||||
public class AipsDbContext : IdentityDbContext<User.User, IdentityRole<Guid>, Guid>
|
||||
{
|
||||
public DbSet<User.User> Users { get; set; }
|
||||
public DbSet<Whiteboard.Whiteboard> Whiteboards { get; set; }
|
||||
public DbSet<Shape.Shape> Shapes { get; set; }
|
||||
public DbSet<WhiteboardMembership.WhiteboardMembership> WhiteboardMemberships { get; set; }
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
using AipsCore.Application.Abstract.UserContext;
|
||||
using AipsCore.Domain.Models.User.ValueObjects;
|
||||
|
||||
namespace AipsCore.Infrastructure;
|
||||
|
||||
public class UserContext : IUserContext
|
||||
{
|
||||
public UserId GetCurrentUserId()
|
||||
{
|
||||
return new UserId(new Guid("52a1810c-802f-48b0-a74c-7b517807e392").ToString());
|
||||
}
|
||||
}
|
||||
|
||||
//Ovo je samo trenutno resenje
|
||||
Reference in New Issue
Block a user