Skip to content

Commit

Permalink
Prepare for next lecture
Browse files Browse the repository at this point in the history
  • Loading branch information
Tomas-Juri committed Mar 9, 2024
1 parent 9f66427 commit 35f2097
Show file tree
Hide file tree
Showing 14 changed files with 615 additions and 24 deletions.
10 changes: 10 additions & 0 deletions 2024/React/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@

public class AppSettings
{
public required JwtSettings Jwt { get; init; }

public record JwtSettings
{
public required string Issuer { get; init; }

public required string Audience { get; init; }

public required string Key { get; init; }
}
}
4 changes: 4 additions & 0 deletions 2024/React/Application.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
</ItemGroup>

<ItemGroup>
<Folder Include="Backend\Domain\" />
</ItemGroup>


<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
Expand Down
52 changes: 52 additions & 0 deletions 2024/React/Backend/Api/AccountController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Application.Backend.Api.Models;
using Application.Backend.Authorization;
using Application.Backend.Core;
using Application.Backend.Database;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;

namespace Application.Backend.Api;

[ApiController]
[Route("/api/account")]
public class AccountController(DataContext dataContext, IOptions<AppSettings> appSettings) : Controller
{
private readonly AppSettings _appSettings = appSettings.Value;

[HttpPost("login")]
public IActionResult Login(LoginRequest request)
{
var user = dataContext.Users.FirstOrDefault(user => user.Email == request.Email);
if (user == null)
return NotFound();

if (Password.Verify(request.Password, user.PasswordHash, user.PasswordSalt) == false)
return BadRequest();

var issuer = _appSettings.Jwt.Issuer;
var audience = _appSettings.Jwt.Audience;
var key = Encoding.ASCII.GetBytes(_appSettings.Jwt.Key);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[]
{
new Claim("Id", user.Id.ToString()),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
new Claim(Policy.CanEditForecasts, (user.Role == Role.Administrator).ToString())
}),
Expires = DateTime.UtcNow.AddDays(1),
Issuer = issuer,
Audience = audience,
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
var jwtToken = tokenHandler.WriteToken(token);

return Ok(jwtToken);
}
}
8 changes: 8 additions & 0 deletions 2024/React/Backend/Api/Models/LoginRequest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Application.Backend.Api.Models;

public record LoginRequest
{
public required string Email { get; set; }

public required string Password { get; set; }
}
15 changes: 11 additions & 4 deletions 2024/React/Backend/Api/WeatherForecastController.cs
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
using Application.Backend.Api.Models;
using System.Security.Claims;
using Application.Backend.Api.Models;
using Application.Backend.Authorization;
using Application.Backend.Database;
using Application.Backend.Database.Models;
using Application.Backend.Database.Repository;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Application.Backend.Api;

[ApiController]
[Route("/api/weather-forecast")]
public class WeatherForecastController(DataContext dataContext, UsersRepository usersRepository) : ControllerBase
[Authorize]
public class WeatherForecastController(DataContext dataContext) : ControllerBase
{
[HttpGet]
public IActionResult Get()
{
var emailClaim = User.FindFirst(ClaimTypes.Email);

var weatherForecasts = dataContext.WeatherForecasts.ToList();
return Ok(weatherForecasts);
}

// HTTP-GET /api/weather-forecasts/guid
[HttpGet("{id:guid}")]
public IActionResult Get(Guid id)
{
Expand All @@ -30,6 +34,7 @@ public IActionResult Get(Guid id)
}

[HttpPost]
[Authorize(Policy = Policy.CanEditForecasts)]
public IActionResult Create(WeatherForecast weatherForecast)
{
dataContext.Add(weatherForecast);
Expand All @@ -39,6 +44,7 @@ public IActionResult Create(WeatherForecast weatherForecast)
}

[HttpPut("{id:guid}")]
[Authorize(Policy = Policy.CanEditForecasts)]
public IActionResult Update(Guid id, UpdateWeatherForecastRequest request)
{
var weatherForecasts = dataContext.WeatherForecasts.FirstOrDefault(forecast => forecast.Id == id);
Expand All @@ -55,6 +61,7 @@ public IActionResult Update(Guid id, UpdateWeatherForecastRequest request)


[HttpDelete("{id:guid}")]
[Authorize(Policy = Policy.CanDeleteForecasts)]
public IActionResult Delete(Guid id)
{
var weatherForecasts = dataContext.WeatherForecasts.FirstOrDefault(forecast => forecast.Id == id);
Expand Down
7 changes: 7 additions & 0 deletions 2024/React/Backend/Authorization/Policy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Application.Backend.Authorization;

public class Policy
{
public const string CanEditForecasts = "CanEditForecasts";
public const string CanDeleteForecasts = "CanDeleteForecasts";
}
7 changes: 7 additions & 0 deletions 2024/React/Backend/Authorization/Role.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Application.Backend.Authorization;

public class Role
{
public const string Administrator = "Administrator";
public const string User = "User";
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System;
using Application.Backend.Authorization;
using Microsoft.EntityFrameworkCore.Migrations;

#nullable disable

namespace Application.Migrations
{
/// <inheritdoc />
public partial class AddRoleMigration : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Deliveries_Users_UserId",
table: "Deliveries");

migrationBuilder.AddColumn<string>(
name: "Role",
table: "Users",
type: "nvarchar(max)",
nullable: false,
defaultValue: Role.Administrator);

migrationBuilder.AlterColumn<Guid>(
name: "UserId",
table: "Deliveries",
type: "uniqueidentifier",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uniqueidentifier");

migrationBuilder.AddForeignKey(
name: "FK_Deliveries_Users_UserId",
table: "Deliveries",
column: "UserId",
principalTable: "Users",
principalColumn: "Id");
}

/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Deliveries_Users_UserId",
table: "Deliveries");

migrationBuilder.DropColumn(
name: "Role",
table: "Users");

migrationBuilder.AlterColumn<Guid>(
name: "UserId",
table: "Deliveries",
type: "uniqueidentifier",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uniqueidentifier",
oldNullable: true);

migrationBuilder.AddForeignKey(
name: "FK_Deliveries_Users_UserId",
table: "Deliveries",
column: "UserId",
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}
Loading

0 comments on commit 35f2097

Please sign in to comment.