diff options
| author | Paweł Bernaciak <pawelbernaciak@zohomail.eu> | 2023-10-21 11:55:33 +0200 |
|---|---|---|
| committer | Paweł Bernaciak <pawelbernaciak@zohomail.eu> | 2023-10-21 11:55:33 +0200 |
| commit | 12fef7cbaf2073f9cc349ed765ea140be0259d8e (patch) | |
| tree | 83412d050139bcdbd11eedffa61e1d0c9862dbed /backend/Elements.Backend | |
| parent | 17785848eb53f8d0420f6b6b3be00a0d10be4e1e (diff) | |
Basic API auth and Google login
Diffstat (limited to 'backend/Elements.Backend')
| -rw-r--r-- | backend/Elements.Backend/Controllers/AuthController.cs | 106 | ||||
| -rw-r--r-- | backend/Elements.Backend/Controllers/UserController.cs | 41 | ||||
| -rw-r--r-- | backend/Elements.Backend/Controllers/WeatherForecastController.cs | 32 | ||||
| -rw-r--r-- | backend/Elements.Backend/Elements.Backend.csproj | 41 | ||||
| -rw-r--r-- | backend/Elements.Backend/Program.cs | 53 | ||||
| -rw-r--r-- | backend/Elements.Backend/WeatherForecast.cs | 12 |
6 files changed, 214 insertions, 71 deletions
diff --git a/backend/Elements.Backend/Controllers/AuthController.cs b/backend/Elements.Backend/Controllers/AuthController.cs new file mode 100644 index 0000000..56e7c3b --- /dev/null +++ b/backend/Elements.Backend/Controllers/AuthController.cs @@ -0,0 +1,106 @@ +using System.Runtime.Serialization; +using System.Security.Claims; +using System.Text.Json; +using Elements.Data; +using Elements.Data.Models; +using Google.Apis.Auth; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Authentication.Cookies; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace Elements.Backend.Controllers; + +[ApiController] +[Route("[controller]/[action]")] +public class AuthController : ControllerBase +{ + private readonly IConfiguration _config; + private readonly ApplicationDbContext _dbContext; + + public AuthController(IConfiguration config, ApplicationDbContext dbContext) + { + _config = config; + _dbContext = dbContext; + } + + public class LoginModel + { + public required string GoogleToken { get; init; } + } + + [HttpPost] + public async Task<IActionResult> Login([FromBody] LoginModel model) + { + GoogleJsonWebSignature.Payload? payload = await VerifyGoogleIdToken(model.GoogleToken); + if (payload == null) + return Unauthorized(); + + User? user = await _dbContext.Users.SingleOrDefaultAsync(u => u.GoogleId == payload.Subject); + if (user != null) + { + //Check if user's name changed and update if it did + if (user.Name != payload.Name) + user.Name = payload.Name; + } + else + { + user = new User() + { + Name = payload.Name, + GoogleId = payload.Subject, + Elements = new List<Element>() + }; + + await _dbContext.Users.AddAsync(user); + } + + await _dbContext.SaveChangesAsync(); + + List<Claim> claims = new() + { + new Claim("id", user.Id.ToString()), + new Claim(ClaimTypes.Role, "User") + }; + ClaimsIdentity claimsIdentity = new(claims, CookieAuthenticationDefaults.AuthenticationScheme); + + AuthenticationProperties authProperties = new() + { + IsPersistent = true, + AllowRefresh = true + }; + + await HttpContext.SignInAsync( + CookieAuthenticationDefaults.AuthenticationScheme, + new ClaimsPrincipal(claimsIdentity), + authProperties); + + var response = new + { + Id = user.Id.ToString() + }; + + return Ok(JsonSerializer.Serialize(response)); + } + + [HttpPost] + public async Task<IActionResult> Logout() + { + await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); + return Ok(); + } + + private async Task<GoogleJsonWebSignature.Payload?> VerifyGoogleIdToken(string token) + { + try + { + GoogleJsonWebSignature.Payload? payload = await GoogleJsonWebSignature.ValidateAsync(token); + return payload; + } + catch (InvalidJwtException) + { + return null; + } + } +}
\ No newline at end of file diff --git a/backend/Elements.Backend/Controllers/UserController.cs b/backend/Elements.Backend/Controllers/UserController.cs new file mode 100644 index 0000000..bde93aa --- /dev/null +++ b/backend/Elements.Backend/Controllers/UserController.cs @@ -0,0 +1,41 @@ +using System.Security.Claims; +using System.Text.Json; +using Elements.Data; +using Elements.Data.Models; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore; + +namespace Elements.Backend.Controllers; + +[ApiController] +[Route("[controller]/[action]")] +public class UserController: ControllerBase +{ + private readonly ApplicationDbContext _dbContext; + + public UserController(ApplicationDbContext dbContext) + { + _dbContext = dbContext; + } + + [HttpGet] + [Authorize] + [Route("/user/{id:int}")] + public async Task<IActionResult> Users(int id) + { + IEnumerable<Claim> claims = User.Claims; + string? currentUserId = claims.FirstOrDefault(claim => claim.Type == "id")?.Value; + if (currentUserId == null) + return StatusCode(StatusCodes.Status500InternalServerError); + if (currentUserId != id.ToString()) + return Unauthorized(); + + User? user = await _dbContext.Users.FirstOrDefaultAsync(user => user.Id == id); + if (user == null) + return StatusCode(StatusCodes.Status500InternalServerError); + + string userJson = JsonSerializer.Serialize(user); + return Ok(userJson); + } +}
\ No newline at end of file diff --git a/backend/Elements.Backend/Controllers/WeatherForecastController.cs b/backend/Elements.Backend/Controllers/WeatherForecastController.cs deleted file mode 100644 index 9a70e36..0000000 --- a/backend/Elements.Backend/Controllers/WeatherForecastController.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Microsoft.AspNetCore.Mvc;
-
-namespace Elements.Backend.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),
- TemperatureC = Random.Shared.Next(-20, 55),
- Summary = Summaries[Random.Shared.Next(Summaries.Length)]
- })
- .ToArray();
- }
-}
diff --git a/backend/Elements.Backend/Elements.Backend.csproj b/backend/Elements.Backend/Elements.Backend.csproj index 0c664a6..787d048 100644 --- a/backend/Elements.Backend/Elements.Backend.csproj +++ b/backend/Elements.Backend/Elements.Backend.csproj @@ -1,18 +1,27 @@ -<Project Sdk="Microsoft.NET.Sdk.Web">
-
- <PropertyGroup>
- <TargetFramework>net7.0</TargetFramework>
- <Nullable>enable</Nullable>
- <ImplicitUsings>enable</ImplicitUsings>
- </PropertyGroup>
-
- <ItemGroup>
- <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" />
- <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
- </ItemGroup>
-
+<Project Sdk="Microsoft.NET.Sdk.Web"> + + <PropertyGroup> + <TargetFramework>net7.0</TargetFramework> + <Nullable>enable</Nullable> + <ImplicitUsings>enable</ImplicitUsings> + <UserSecretsId>dae266ca-b349-4b87-a992-5470f9dd635d</UserSecretsId> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="Google.Apis.Auth" Version="1.62.1" /> + <PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="7.0.12" /> + <PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.5" /> + <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.12"> + <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> + <PrivateAssets>all</PrivateAssets> + </PackageReference> + <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.12" /> + <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="7.0.10" /> + <PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" /> + </ItemGroup> + <ItemGroup> <ProjectReference Include="..\Elements.Data\Elements.Data.csproj" /> - </ItemGroup>
-
-</Project>
+ </ItemGroup> + +</Project> diff --git a/backend/Elements.Backend/Program.cs b/backend/Elements.Backend/Program.cs index 15eacee..50e5255 100644 --- a/backend/Elements.Backend/Program.cs +++ b/backend/Elements.Backend/Program.cs @@ -1,23 +1,54 @@ +using System.Text.Json;
+using Elements.Data;
+using Microsoft.AspNetCore.Authentication.Cookies;
+using Microsoft.AspNetCore.Authentication.Google;
+using Microsoft.EntityFrameworkCore;
+
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
+builder.Services.AddRouting(options => options.LowercaseUrls = true);
+builder.Services.AddControllers().AddJsonOptions(options =>
+{
+ options.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
+});
-builder.Services.AddControllers();
-// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
-builder.Services.AddEndpointsApiExplorer();
-builder.Services.AddSwaggerGen();
-
-var app = builder.Build();
-
-// Configure the HTTP request pipeline.
-if (app.Environment.IsDevelopment())
+if (builder.Environment.IsDevelopment())
{
- app.UseSwagger();
- app.UseSwaggerUI();
+ builder.Services.AddDbContext<ApplicationDbContext>(options =>
+ {
+ options.UseSqlite("Data Source=elements.db");
+ });
}
+builder.Services
+.AddAuthentication(options =>
+{
+ options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
+})
+.AddCookie(options =>
+{
+ options.Events = new()
+ {
+ OnRedirectToLogin = (ctx) =>
+ {
+ ctx.Response.StatusCode = 401;
+ return Task.CompletedTask;
+ },
+ OnRedirectToAccessDenied = (ctx) =>
+ {
+ ctx.Response.StatusCode = 401;
+ return Task.CompletedTask;
+ }
+
+ };
+});
+
+var app = builder.Build();
+
app.UseHttpsRedirection();
+app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
diff --git a/backend/Elements.Backend/WeatherForecast.cs b/backend/Elements.Backend/WeatherForecast.cs deleted file mode 100644 index 7c8962e..0000000 --- a/backend/Elements.Backend/WeatherForecast.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Elements.Backend;
-
-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; }
-}
|
