Skip to content
Snippets Groups Projects
Commit 55ccdc02 authored by Abdelsamad, Mouaz R (UG - SISC)'s avatar Abdelsamad, Mouaz R (UG - SISC)
Browse files

Merge branch 'master' into 'main'

Master

See merge request ma03081/usermicroservice!1
parents b9e440a6 3cd5547b
No related branches found
No related tags found
No related merge requests found
Showing
with 645 additions and 0 deletions
bin/
.vs/
obj/
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using UserMicroservice.Models;
using UserMicroservice.Services;
namespace UserMicroservice.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
// Dependency injection of a user service
private readonly IUserService _userService;
public UsersController(IUserService userService)
{
_userService = userService;
}
// POST: api/Users/register
[HttpPost("register")]
public IActionResult Register([FromBody] RegisterModel model)
{
string token = _userService.RegisterUser(model.Email, model.Password);
if(token == null)
return BadRequest();
return Ok(token);
//return Created("api/users/{id}", new { /* user data */ });
}
// POST: api/Users/login
[HttpPost("login")]
public IActionResult Login([FromBody] LoginModel model)
{
string? token = _userService.Login(model.Email, model.Password);
if (string.IsNullOrEmpty(token))
return Unauthorized();
return Ok(token);
}
// GET: api/Users
[Authorize]
[HttpGet()]
public IActionResult GetUsers()
{
List<User> users = new List<User>()
{
new User("User1", "Password1"),
new User("User2", "Password2"),
new User("User3", "Password3")
};
return Ok(users);
}
// GET: api/Users/{id}
[Authorize]
[HttpGet("{id}")]
public IActionResult GetUser(int id)
{
return Ok(new User( /* user data */ ));
}
// PUT: api/Users/{id}
[Authorize]
[HttpPut("{id}")]
public IActionResult UpdateUser(int id, [FromBody] User user)
{
return Ok(user);
}
}
}
using Microsoft.AspNetCore.Mvc;
using UserMicroservice.Models;
namespace UserMicroservice.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet(Name = "GetWeatherForecast")]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using UserMicroservice.Models;
#nullable disable
namespace UserMicroservice.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20240228234031_InitialCreate")]
partial class InitialCreate
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("UserMicroservice.Models.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("Type")
.HasColumnType("int");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("Users");
});
#pragma warning restore 612, 618
}
}
}
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace UserMicroservice.Migrations
{
/// <inheritdoc />
public partial class InitialCreate : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
Username = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Email = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
PasswordHash = table.Column<string>(type: "longtext", nullable: false)
.Annotation("MySql:CharSet", "utf8mb4"),
Type = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Id);
})
.Annotation("MySql:CharSet", "utf8mb4");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Users");
}
}
}
// <auto-generated />
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using UserMicroservice.Models;
#nullable disable
namespace UserMicroservice.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
partial class ApplicationDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.2")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("UserMicroservice.Models.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("Type")
.HasColumnType("int");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("longtext");
b.HasKey("Id");
b.ToTable("Users");
});
#pragma warning restore 612, 618
}
}
}
using Microsoft.EntityFrameworkCore;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
using UserMicroservice.Migrations;
namespace UserMicroservice.Models
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<User> Users { get; set; }
// Add other DbSet properties for other models
//use the commands to update the db
//dotnet ef migrations add InitialCreate
//dotnet ef database update
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Model configuration goes here
}
}
}
namespace UserMicroservice.Models
{
public class LoginModel
{
public string Email { get; set; }
public string Password { get; set; }
}
}
namespace UserMicroservice.Models
{
public class RegisterModel
{
public string Username { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
}
namespace UserMicroservice.Models
{
public class User
{
// TODO:
// remove setters from properties
// add constructor
// make class internal
// make required properites required
// properties can probably also be internal instead of public
public User(String userName, string passwordHash)
{
this.Username = userName;
this.PasswordHash = passwordHash;
}
public User() { } // remove this later
public int Id { get; set; }
public string Username { get; set; }
public string Email { get; set; } = "random@gmail.com";
public string PasswordHash { get; set; }
public UserType Type { get; set; } = UserType.BUYER; // set to default for now
}
public enum UserType
{
BUYER = 0,
SELLER = 1
}
}
namespace UserMicroservice.Models
{
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
}
using Microsoft.EntityFrameworkCore;
using UserMicroservice.Models;
using UserMicroservice.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
// Configure your DbContext and MySQL connection here
// This is also dependancy injection BTW...
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseMySql(builder.Configuration.GetConnectionString("DefaultConnection"),
new MariaDbServerVersion(new Version(10, 4, 20))));
// new MySqlServerVersion(new Version(8, 0, 21))));
// Configuration for the connection string
builder.Configuration.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddEnvironmentVariables();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
ValidateIssuer = true,
ValidateAudience = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"]
};
});
// Add dependecy injections
builder.Services.AddScoped<IAuthService, AuthService>();
builder.Services.AddScoped<IUserService, UserService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseAuthentication();
app.MapControllers();
app.Run();
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:52042",
"sslPort": 44367
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5089",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7137;http://localhost:5089",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using UserMicroservice.Models;
namespace UserMicroservice.Services
{
public class AuthService : IAuthService
{
private readonly IConfiguration _configuration;
public AuthService(IConfiguration configuration)
{
_configuration = configuration;
}
public string GenerateToken(User user)
{
string? configuredKey = _configuration["Jwt:Key"];
string? configuredIssuer = _configuration["Jwt:Issuer"];
string? configuredAudience = _configuration["Jwt:Audience"];
throwIfNull(configuredKey, configuredIssuer, configuredAudience);
SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuredKey));
SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
List<Claim> claims = new List<Claim>
{
new Claim(JwtRegisteredClaimNames.Sub, user.Username),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
};
var token = new JwtSecurityToken(
issuer: configuredIssuer,
audience: configuredAudience,
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: creds);
return new JwtSecurityTokenHandler().WriteToken(token);
}
private void throwIfNull(string? key, string? issuer, string? audience)
{
if(string.IsNullOrWhiteSpace(key))
throw new ArgumentNullException(nameof(key));
if(string.IsNullOrWhiteSpace(issuer))
throw new ArgumentNullException(nameof(issuer));
if(string.IsNullOrEmpty(audience))
throw new ArgumentNullException(nameof(audience));
}
}
}
using UserMicroservice.Models;
namespace UserMicroservice.Services
{
public interface IAuthService
{
string GenerateToken(User user);
}
}
using UserMicroservice.Models;
namespace UserMicroservice.Services
{
// CRUD Based Service
public interface IUserService
{
User GetUser(string username);
List<User> GetUsers();
string RegisterUser(string username, string password);
User UpdateUser(User updatedUser);
bool DeleteUser(string username);
string? Login(string username, string password);
}
// interfaces are great for writing unit tests
// mocking certain parts of the code and asserting the outcome
// also so each class that inherits this have its own implementation
// while have the same parameters and return types
// ~ Russell Horwood
}
using Microsoft.EntityFrameworkCore;
using UserMicroservice.Models;
namespace UserMicroservice.Services
{
public class UserService : IUserService
{
// look at entity framwork documetation for queries to the db using the DbContext
private readonly ApplicationDbContext _context;
private readonly IAuthService _authService;
public UserService(ApplicationDbContext context, IAuthService authService)
{
_context = context;
_authService = authService;
}
public bool DeleteUser(string username)
{
User user = _context.Users.Single(user => user.Username == username);
if(user == null)
return false;
_context.Users.Remove(user);
_context.SaveChanges();
return true;
}
public List<User> GetUsers()
{
List<User> users = _context.Users.ToList();
return users;
}
public User GetUser(string username)
{
User user = _context.Users.Single(user => user.Username == username);
return user;
}
public string? Login(string username, string password)
{
User user = _context.Users
.Single(user => user.Username == username && user.PasswordHash == password);
if (user == null)
return null;
return _authService.GenerateToken(user);
}
public string RegisterUser(string username, string password)
{
User user = new User { Username = username, PasswordHash = password }; // use the contructor later
_context.Users.Add(user);
_context.SaveChanges();
return _authService.GenerateToken(user);
}
public User UpdateUser(User updatedUser)
{
_context.Users
.Where(user => user.Id == updatedUser.Id)
.ExecuteUpdate(setters => setters
.SetProperty(user => user.Username, updatedUser.Username)
.SetProperty(user => user.PasswordHash, updatedUser.PasswordHash));
_context.SaveChanges();
return updatedUser;
}
}
}
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.2" />
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.2" PrivateAssets="All" />
</ItemGroup>
</Project>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ActiveDebugProfile>http</ActiveDebugProfile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DebuggerFlavor>ProjectDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>
\ No newline at end of file
@UserMicroservice_HostAddress = http://localhost:5089
GET {{UserMicroservice_HostAddress}}/weatherforecast/
Accept: application/json
###
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