Skip to content
Snippets Groups Projects
Commit 3f55ac90 authored by Enzo Santangelo Dodera's avatar Enzo Santangelo Dodera
Browse files

Merge branch 'feature/registrar-usuario' into 'master'

registrar usuario

See merge request !1
parents 8184df36 4b8e45ad
No related branches found
No related tags found
1 merge request!1registrar usuario
Showing
with 497 additions and 40 deletions
......@@ -3,11 +3,11 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30523.141
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tsi1.Api", "Tsi1.Api\Tsi1.Api.csproj", "{02E63197-0AEA-4942-941F-DFB7AD145A1E}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tsi1.Api", "Tsi1.Api\Tsi1.Api.csproj", "{02E63197-0AEA-4942-941F-DFB7AD145A1E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tsi1.BusinessLayer", "Tsi1.BusinessLayer\Tsi1.BusinessLayer.csproj", "{3B46AFDD-AB4A-4D0E-8A94-49559E1D2083}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tsi1.BusinessLayer", "Tsi1.BusinessLayer\Tsi1.BusinessLayer.csproj", "{3B46AFDD-AB4A-4D0E-8A94-49559E1D2083}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tsi1.DataLayer", "Tsi1.DataLayer\Tsi1.DataLayer.csproj", "{57C4932A-C228-4A49-8FAC-8E9447F0E6E0}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tsi1.DataLayer", "Tsi1.DataLayer\Tsi1.DataLayer.csproj", "{57C4932A-C228-4A49-8FAC-8E9447F0E6E0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
......
......@@ -5,6 +5,8 @@ using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Tsi1.Api.Infrastructure;
using Tsi1.Api.Models;
using Tsi1.BusinessLayer.Dtos;
using Tsi1.BusinessLayer.Helpers;
using Tsi1.BusinessLayer.Interfaces;
namespace Tsi1.Api.Controllers
......@@ -14,26 +16,30 @@ namespace Tsi1.Api.Controllers
[ApiController]
public class UserController : ControllerBase
{
private readonly IUserService _userService;
private readonly IJwtAuthManager _jwtAuthManager;
private readonly IUserService _userService;
private readonly IUserTypeService _userTypeService;
public UserController(IUserService userService, IJwtAuthManager jwtAuthManager)
public UserController(IJwtAuthManager jwtAuthManager, IUserService userService, IUserTypeService userTypeService)
{
_userService = userService;
_jwtAuthManager = jwtAuthManager;
_userService = userService;
_userTypeService = userTypeService;
}
[AllowAnonymous]
[HttpPost("Login")]
public async Task<IActionResult> Login(LoginRequest request)
{
var user = await _userService.Authenticate(request.UserName, request.Password);
var result = await _userService.Authenticate(request.UserName, request.Password);
if (user == null)
if (result.HasError)
{
return BadRequest();
return BadRequest(result.Message);
}
var user = result.Data;
var claims = new[]
{
new Claim(ClaimTypes.Name,user.Username),
......@@ -51,11 +57,27 @@ namespace Tsi1.Api.Controllers
});
}
[HttpGet("Register")]
public async Task<IActionResult> Register()
[Authorize(Roles = UserTypes.FacultyAdmin)]
[HttpPost("Register")]
public async Task<IActionResult> Register(UserRegisterDto dto)
{
var userTypeResult = await _userTypeService.GetById(dto.UserTypeId);
if (userTypeResult.HasError)
{
BadRequest(userTypeResult.Message);
}
var userType = userTypeResult.Data;
var userServiceResult = await _userService.Create(dto, userType.Name);
if (userServiceResult.HasError)
{
BadRequest(userServiceResult.Message);
}
return Ok();
}
}
}
......@@ -48,12 +48,14 @@ namespace Tsi1.Api.Infrastructure
public JwtAuthResult GenerateTokens(string username, Claim[] claims, DateTime now)
{
var shouldAddAudienceClaim = string.IsNullOrWhiteSpace(claims?.FirstOrDefault(x => x.Type == JwtRegisteredClaimNames.Aud)?.Value);
var jwtToken = new JwtSecurityToken(
_jwtTokenConfig.Issuer,
shouldAddAudienceClaim ? _jwtTokenConfig.Audience : string.Empty,
claims,
expires: now.AddMinutes(_jwtTokenConfig.AccessTokenExpiration),
signingCredentials: new SigningCredentials(new SymmetricSecurityKey(_secret), SecurityAlgorithms.HmacSha256Signature));
var accessToken = new JwtSecurityTokenHandler().WriteToken(jwtToken);
var refreshToken = new RefreshToken
......
......@@ -14,9 +14,6 @@ namespace Tsi1.Api.Models
[JsonPropertyName("role")]
public string Role { get; set; }
[JsonPropertyName("originalUserName")]
public string OriginalUserName { get; set; }
[JsonPropertyName("accessToken")]
public string AccessToken { get; set; }
......
......@@ -38,9 +38,13 @@ namespace Tsi1.Api
services.AddDbContext<Tsi1Context>(x => x.UseNpgsql(Configuration.GetConnectionString("PostgreSql")));
services.AddScoped<IUserService, UserService>();
services.AddScoped<IUserTypeService, UserTypeService>();
services.AddCors();
var jwtTokenConfig = Configuration.GetSection("jwtTokenConfig").Get<JwtTokenConfig>();
services.AddSingleton(jwtTokenConfig);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
......@@ -61,6 +65,7 @@ namespace Tsi1.Api
ClockSkew = TimeSpan.FromMinutes(1)
};
});
services.AddSingleton<IJwtAuthManager, JwtAuthManager>();
services.AddHostedService<JwtRefreshTokenCache>();
......@@ -105,7 +110,6 @@ namespace Tsi1.Api
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Tsi1 api V1");
c.DocumentTitle = "Tsi1 api";
//c.RoutePrefix = string.Empty;
});
app.UseRouting();
......
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
namespace Tsi1.BusinessLayer.Dtos
{
public class UserRegisterDto
{
[Required]
public int UserTypeId { get; set; }
[Required]
public string Username { get; set; }
[Required]
public string Password { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string IdentityCard { get; set; }
public int Age { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace Tsi1.BusinessLayer.Helpers
{
public static class ErrorMessages
{
public const string UserDoesNotExist = "El usuario '{0}' no existe";
public const string IncorrectPassword = "Contraseña incorrecta";
public const string UserTypeDoesNotExist = "El tipo de usuario con id '{0}' no existe";
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace Tsi1.BusinessLayer.Helpers
{
public class ServiceResult<T>
{
public T Data { get; set; }
public string Message { get; set; }
public bool HasError { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace Tsi1.BusinessLayer.Helpers
{
public static class UserTypes
{
public const string FacultyAdmin = nameof(FacultyAdmin);
public const string Professor = nameof(Professor);
public const string Student = nameof(Student);
}
}
......@@ -2,12 +2,15 @@
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Tsi1.BusinessLayer.Dtos;
using Tsi1.BusinessLayer.Helpers;
using Tsi1.DataLayer.Entities;
namespace Tsi1.BusinessLayer.Interfaces
{
public interface IUserService
{
Task<User> Authenticate(string username, string password);
Task<ServiceResult<User>> Authenticate(string username, string password);
Task<ServiceResult<User>> Create(UserRegisterDto dto, string type);
}
}
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Tsi1.BusinessLayer.Helpers;
using Tsi1.DataLayer.Entities;
namespace Tsi1.BusinessLayer.Interfaces
{
public interface IUserTypeService
{
public Task<ServiceResult<UserType>> GetById(int id);
}
}
......@@ -3,6 +3,8 @@ using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Tsi1.BusinessLayer.Dtos;
using Tsi1.BusinessLayer.Helpers;
using Tsi1.BusinessLayer.Interfaces;
using Tsi1.DataLayer;
using Tsi1.DataLayer.Entities;
......@@ -18,32 +20,69 @@ namespace Tsi1.BusinessLayer.Services
_context = context;
}
public async Task<User> Authenticate(string username, string password)
public async Task<ServiceResult<User>> Authenticate(string username, string password)
{
var user = await _context.Users.FirstOrDefaultAsync(x => x.Username == username);
var result = new ServiceResult<User>();
user = new User()
{
Id = 1,
Username = "lucca",
UserType = new UserType()
{
Id = 1,
Name = "admin"
}
};
var user = await _context.Users
.Include(x => x.UserType)
.FirstOrDefaultAsync(x => x.Username == username);
if (user == null)
{
// no existe el usuario
result.HasError = true;
result.Message = string.Format(ErrorMessages.UserDoesNotExist, username);
return result;
}
if (user.Password != password)
{
// contraseña incorrecta
result.HasError = true;
result.Message = ErrorMessages.IncorrectPassword;
return result;
}
result.Data = user;
return result;
}
public async Task<ServiceResult<User>> Create(UserRegisterDto dto, string type)
{
var result = new ServiceResult<User>();
var user = new User()
{
UserTypeId = dto.UserTypeId,
Username = dto.Username,
Password = dto.Password,
Email = dto.Email,
FirstName = dto.FirstName,
LastName = dto.LastName
};
if (type == UserTypes.Student)
{
user.Student = new Student()
{
IdentityCard = dto.IdentityCard,
Age = dto.Age
};
}
if (type == UserTypes.Professor)
{
user.Professor = new Professor()
{
IdentityCard = dto.IdentityCard
};
}
return user;
_context.Users.Add(user);
await _context.SaveChangesAsync();
result.Data = user;
return result;
}
}
}
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Tsi1.BusinessLayer.Helpers;
using Tsi1.BusinessLayer.Interfaces;
using Tsi1.DataLayer;
using Tsi1.DataLayer.Entities;
namespace Tsi1.BusinessLayer.Services
{
public class UserTypeService : IUserTypeService
{
private readonly Tsi1Context _context;
public UserTypeService(Tsi1Context context)
{
_context = context;
}
public async Task<ServiceResult<UserType>> GetById(int id)
{
var result = new ServiceResult<UserType>();
var userType = await _context.UserTypes.FirstOrDefaultAsync(x => x.Id == id);
if (userType == null)
{
result.HasError = true;
result.Message = string.Format(ErrorMessages.UserTypeDoesNotExist, id);
}
result.Data = userType;
return result;
}
}
}
......@@ -12,7 +12,6 @@ namespace Tsi1.DataLayer.Entities
}
public int Id { get; set; }
public int UserId { get; set; }
public string IdentityCard { get; set; }
public User User { get; set; }
......
......@@ -12,7 +12,6 @@ namespace Tsi1.DataLayer.Entities
}
public int Id { get; set; }
public int UserId { get; set; }
public string IdentityCard { get; set; }
public int Age { get; set; }
......
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using Tsi1.DataLayer;
namespace Tsi1.DataLayer.Migrations
{
[DbContext(typeof(Tsi1Context))]
[Migration("20201016201059_remove-UserId-from-Student-Professor")]
partial class removeUserIdfromStudentProfessor
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn)
.HasAnnotation("ProductVersion", "3.1.4")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
modelBuilder.Entity("Tsi1.DataLayer.Entities.Course", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Name")
.IsRequired()
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("Courses");
});
modelBuilder.Entity("Tsi1.DataLayer.Entities.Professor", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("IdentityCard")
.IsRequired()
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.HasIndex("IdentityCard")
.IsUnique();
b.ToTable("Professors");
});
modelBuilder.Entity("Tsi1.DataLayer.Entities.ProfessorCourse", b =>
{
b.Property<int>("ProfessorId")
.HasColumnType("integer");
b.Property<int>("CourseId")
.HasColumnType("integer");
b.HasKey("ProfessorId", "CourseId");
b.HasIndex("CourseId");
b.ToTable("ProfessorCourses");
});
modelBuilder.Entity("Tsi1.DataLayer.Entities.Student", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<int>("Age")
.HasColumnType("integer");
b.Property<string>("IdentityCard")
.IsRequired()
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.HasIndex("IdentityCard")
.IsUnique();
b.ToTable("Students");
});
modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourse", b =>
{
b.Property<int>("StudentId")
.HasColumnType("integer");
b.Property<int>("CourseId")
.HasColumnType("integer");
b.HasKey("StudentId", "CourseId");
b.HasIndex("CourseId");
b.ToTable("StudentCourses");
});
modelBuilder.Entity("Tsi1.DataLayer.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Email")
.IsRequired()
.HasColumnType("character varying(255)");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("character varying(255)");
b.Property<string>("LastName")
.IsRequired()
.HasColumnType("character varying(255)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("character varying(255)");
b.Property<int?>("ProfessorId")
.HasColumnType("integer");
b.Property<int?>("StudentId")
.HasColumnType("integer");
b.Property<int>("UserTypeId")
.HasColumnType("integer");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.HasIndex("ProfessorId")
.IsUnique();
b.HasIndex("StudentId")
.IsUnique();
b.HasIndex("UserTypeId");
b.HasIndex("Username")
.IsUnique();
b.ToTable("Users");
});
modelBuilder.Entity("Tsi1.DataLayer.Entities.UserType", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn);
b.Property<string>("Name")
.IsRequired()
.HasColumnType("character varying(50)");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("UserTypes");
});
modelBuilder.Entity("Tsi1.DataLayer.Entities.ProfessorCourse", b =>
{
b.HasOne("Tsi1.DataLayer.Entities.Course", "Course")
.WithMany("ProfessorCourses")
.HasForeignKey("CourseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Tsi1.DataLayer.Entities.Professor", "Professor")
.WithMany("ProfessorCourses")
.HasForeignKey("ProfessorId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tsi1.DataLayer.Entities.StudentCourse", b =>
{
b.HasOne("Tsi1.DataLayer.Entities.Course", "Course")
.WithMany("StudentCourses")
.HasForeignKey("CourseId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Tsi1.DataLayer.Entities.Student", "Student")
.WithMany("StudentCourses")
.HasForeignKey("StudentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Tsi1.DataLayer.Entities.User", b =>
{
b.HasOne("Tsi1.DataLayer.Entities.Professor", "Professor")
.WithOne("User")
.HasForeignKey("Tsi1.DataLayer.Entities.User", "ProfessorId");
b.HasOne("Tsi1.DataLayer.Entities.Student", "Student")
.WithOne("User")
.HasForeignKey("Tsi1.DataLayer.Entities.User", "StudentId");
b.HasOne("Tsi1.DataLayer.Entities.UserType", "UserType")
.WithMany()
.HasForeignKey("UserTypeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
#pragma warning restore 612, 618
}
}
}
using Microsoft.EntityFrameworkCore.Migrations;
namespace Tsi1.DataLayer.Migrations
{
public partial class removeUserIdfromStudentProfessor : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UserId",
table: "Students");
migrationBuilder.DropColumn(
name: "UserId",
table: "Professors");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "UserId",
table: "Students",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "UserId",
table: "Professors",
type: "integer",
nullable: false,
defaultValue: 0);
}
}
}
......@@ -49,9 +49,6 @@ namespace Tsi1.DataLayer.Migrations
.IsRequired()
.HasColumnType("character varying(50)");
b.Property<int>("UserId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("IdentityCard")
......@@ -89,9 +86,6 @@ namespace Tsi1.DataLayer.Migrations
.IsRequired()
.HasColumnType("character varying(50)");
b.Property<int>("UserId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("IdentityCard")
......
......@@ -9,6 +9,10 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.4">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="3.1.9" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="3.1.9" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="3.1.4" />
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment