From e47d6488c27d891cb4d29d5caef9d7029b018edc Mon Sep 17 00:00:00 2001 From: "t.ruspekhofer" Date: Tue, 22 Feb 2022 01:06:41 +0100 Subject: [PATCH] Added Authorization --- Lieb/Data/Constants.cs | 21 ++++++++++++ Lieb/Data/DbInitializer.cs | 18 +++++++--- Lieb/Data/LiebContext.cs | 4 ++- Lieb/DiscordOAuth2/DiscordHandler.cs | 20 +++++++++-- Lieb/DiscordOAuth2/DiscordOptions.cs | 1 + Lieb/Models/GuildWars2/Raid/Raid.cs | 2 +- Lieb/Models/LiebUser.cs | 1 + Lieb/Models/UserRole.cs | 9 +++++ Lieb/Pages/Users/Create.cshtml.cs | 2 +- Lieb/Pages/Users/Delete.cshtml.cs | 6 ++-- Lieb/Pages/Users/Details.cshtml.cs | 2 +- Lieb/Pages/Users/Edit.cshtml.cs | 4 +-- Lieb/Pages/Users/Index.cshtml.cs | 2 +- Lieb/Program.cs | 13 ++++++-- Lieb/Shared/MainLayout.razor | 50 +++++++++++++++++++++++++++- 15 files changed, 134 insertions(+), 21 deletions(-) create mode 100644 Lieb/Data/Constants.cs create mode 100644 Lieb/Models/UserRole.cs diff --git a/Lieb/Data/Constants.cs b/Lieb/Data/Constants.cs new file mode 100644 index 0000000..21f6969 --- /dev/null +++ b/Lieb/Data/Constants.cs @@ -0,0 +1,21 @@ +namespace Lieb.Data +{ + public static class Constants + { + + + public const string ClaimType = "Role"; + public static class Roles + { + public const string User = "User"; + public const string RaidLead = "RaidLead"; + public const string GuildLead = "GuildLead"; + public const string Admin = "Admin"; + + public static List GetAllRoles() + { + return typeof(Roles).GetFields().Select(f => f.GetValue(f)).Cast().ToList(); + } + } + } +} diff --git a/Lieb/Data/DbInitializer.cs b/Lieb/Data/DbInitializer.cs index b3d68ca..19003ab 100644 --- a/Lieb/Data/DbInitializer.cs +++ b/Lieb/Data/DbInitializer.cs @@ -7,19 +7,27 @@ namespace Lieb.Data public static void Initialize(LiebContext context) { // Look for any students. - if (context.Users.Any()) + if (context.LiebUsers.Any()) { return; // DB has been seeded } + UserRole admin = new UserRole(); + admin.RoleName = Constants.Roles.Admin; + UserRole guildLead = new UserRole(); + guildLead.RoleName = Constants.Roles.GuildLead; + UserRole member = new UserRole(); + member.RoleName = Constants.Roles.User; + + var users = new LiebUser[] { - new LiebUser{DiscordUserId=0, Name="Sarah",Birthday=DateTime.Parse("1992-01-15")}, - new LiebUser{DiscordUserId=0, Name="Lisa",Birthday=DateTime.Parse("1991-02-15")}, - new LiebUser{DiscordUserId=0, Name="Simon",Birthday=DateTime.Parse("2019-09-01")} + new LiebUser{DiscordUserId=0, Name="Sarah",Birthday=DateTime.Parse("1992-01-15"), Roles=new List(){admin}}, + new LiebUser{DiscordUserId=1, Name="Lisa",Birthday=DateTime.Parse("1991-02-15"), Roles=new List(){guildLead} }, + new LiebUser{DiscordUserId=2, Name="Simon",Birthday=DateTime.Parse("2019-09-01"), Roles=new List(){member}} }; - context.Users.AddRange(users); + context.LiebUsers.AddRange(users); context.SaveChanges(); } diff --git a/Lieb/Data/LiebContext.cs b/Lieb/Data/LiebContext.cs index 0b69060..bd99fb8 100644 --- a/Lieb/Data/LiebContext.cs +++ b/Lieb/Data/LiebContext.cs @@ -13,7 +13,8 @@ namespace Lieb.Data { } - public DbSet Users { get; set; } + public DbSet LiebUsers { get; set; } + public DbSet UserRoles { get; set; } public DbSet GuildWars2Account { get; set; } public DbSet Equipped { get; set; } public DbSet RaidRoles { get; set; } @@ -27,6 +28,7 @@ namespace Lieb.Data protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity().ToTable("LiebUser"); + modelBuilder.Entity().ToTable("UserRole"); modelBuilder.Entity().ToTable("GuildWars2Account"); modelBuilder.Entity().ToTable("Equipped"); modelBuilder.Entity().ToTable("GuildWars2Build"); diff --git a/Lieb/DiscordOAuth2/DiscordHandler.cs b/Lieb/DiscordOAuth2/DiscordHandler.cs index 09457b9..4a87e01 100644 --- a/Lieb/DiscordOAuth2/DiscordHandler.cs +++ b/Lieb/DiscordOAuth2/DiscordHandler.cs @@ -1,5 +1,8 @@ -using Microsoft.AspNetCore.Authentication; +using Lieb.Data; +using Lieb.Models; +using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.OAuth; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; using System.Net.Http.Headers; using System.Security.Claims; @@ -10,9 +13,12 @@ namespace Discord.OAuth2 { internal class DiscordHandler : OAuthHandler { - public DiscordHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) + private readonly Lieb.Data.LiebContext _LiebDbcontext; + + public DiscordHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, Lieb.Data.LiebContext context) : base(options, logger, encoder, clock) { + _LiebDbcontext = context; } protected override async Task CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) @@ -30,6 +36,16 @@ namespace Discord.OAuth2 context.RunClaimActions(); await Events.CreatingTicket(context); + + LiebUser? user = await _LiebDbcontext.LiebUsers.Include(u => u.Roles).FirstOrDefaultAsync(m => m.DiscordUserId == 1); + if (user != null) + { + foreach (UserRole role in user.Roles) + { + context.Identity.AddClaim(new Claim(Constants.ClaimType, role.RoleName)); + } + } + return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name); } } diff --git a/Lieb/DiscordOAuth2/DiscordOptions.cs b/Lieb/DiscordOAuth2/DiscordOptions.cs index d705c68..223c29e 100644 --- a/Lieb/DiscordOAuth2/DiscordOptions.cs +++ b/Lieb/DiscordOAuth2/DiscordOptions.cs @@ -16,6 +16,7 @@ namespace Discord.OAuth2 TokenEndpoint = DiscordDefaults.TokenEndpoint; UserInformationEndpoint = DiscordDefaults.UserInformationEndpoint; Scope.Add("identify"); + //Scope.Add("guilds.members.read"); ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id", ClaimValueTypes.UInteger64); ClaimActions.MapJsonKey(ClaimTypes.Name, "username", ClaimValueTypes.String); diff --git a/Lieb/Models/GuildWars2/Raid/Raid.cs b/Lieb/Models/GuildWars2/Raid/Raid.cs index 81ebd9c..374cb9d 100644 --- a/Lieb/Models/GuildWars2/Raid/Raid.cs +++ b/Lieb/Models/GuildWars2/Raid/Raid.cs @@ -8,7 +8,7 @@ RandomEliteSpecialization = 4, } - public abstract class Raid + public class Raid { public int RaidId { get; private set; } diff --git a/Lieb/Models/LiebUser.cs b/Lieb/Models/LiebUser.cs index 87dbff2..60c9111 100644 --- a/Lieb/Models/LiebUser.cs +++ b/Lieb/Models/LiebUser.cs @@ -10,5 +10,6 @@ namespace Lieb.Models public string Pronouns { get; set; } = string.Empty; public DateTime? Birthday { get; set; } public ICollection GuildWars2Accounts { get; set; } = new List(); + public ICollection Roles { get; set; } = new List(); } } diff --git a/Lieb/Models/UserRole.cs b/Lieb/Models/UserRole.cs new file mode 100644 index 0000000..49f48ef --- /dev/null +++ b/Lieb/Models/UserRole.cs @@ -0,0 +1,9 @@ +namespace Lieb.Models +{ + public class UserRole + { + public int UserRoleId { get; set; } + + public string RoleName { get; set; } = string.Empty; + } +} diff --git a/Lieb/Pages/Users/Create.cshtml.cs b/Lieb/Pages/Users/Create.cshtml.cs index 3d749af..e6ba4c0 100644 --- a/Lieb/Pages/Users/Create.cshtml.cs +++ b/Lieb/Pages/Users/Create.cshtml.cs @@ -36,7 +36,7 @@ namespace Lieb.Pages.Users return Page(); } - _context.Users.Add(User); + _context.LiebUsers.Add(User); await _context.SaveChangesAsync(); return RedirectToPage("./Index"); diff --git a/Lieb/Pages/Users/Delete.cshtml.cs b/Lieb/Pages/Users/Delete.cshtml.cs index 9f8856c..d79b0af 100644 --- a/Lieb/Pages/Users/Delete.cshtml.cs +++ b/Lieb/Pages/Users/Delete.cshtml.cs @@ -30,7 +30,7 @@ namespace Lieb.Pages.Users return NotFound(); } - User = await _context.Users.FirstOrDefaultAsync(m => m.LiebUserId == id); + User = await _context.LiebUsers.FirstOrDefaultAsync(m => m.LiebUserId == id); if (User == null) { @@ -46,11 +46,11 @@ namespace Lieb.Pages.Users return NotFound(); } - User = await _context.Users.FindAsync(id); + User = await _context.LiebUsers.FindAsync(id); if (User != null) { - _context.Users.Remove(User); + _context.LiebUsers.Remove(User); await _context.SaveChangesAsync(); } diff --git a/Lieb/Pages/Users/Details.cshtml.cs b/Lieb/Pages/Users/Details.cshtml.cs index 3b5a22a..2b1fbd2 100644 --- a/Lieb/Pages/Users/Details.cshtml.cs +++ b/Lieb/Pages/Users/Details.cshtml.cs @@ -29,7 +29,7 @@ namespace Lieb.Pages.Users return NotFound(); } - User = await _context.Users.FirstOrDefaultAsync(m => m.LiebUserId == id); + User = await _context.LiebUsers.FirstOrDefaultAsync(m => m.LiebUserId == id); if (User == null) { diff --git a/Lieb/Pages/Users/Edit.cshtml.cs b/Lieb/Pages/Users/Edit.cshtml.cs index c5126d9..000bb99 100644 --- a/Lieb/Pages/Users/Edit.cshtml.cs +++ b/Lieb/Pages/Users/Edit.cshtml.cs @@ -31,7 +31,7 @@ namespace Lieb.Pages.Users return NotFound(); } - User = await _context.Users.FirstOrDefaultAsync(m => m.LiebUserId == id); + User = await _context.LiebUsers.FirstOrDefaultAsync(m => m.LiebUserId == id); if (User == null) { @@ -72,7 +72,7 @@ namespace Lieb.Pages.Users private bool UserExists(int id) { - return _context.Users.Any(e => e.LiebUserId == id); + return _context.LiebUsers.Any(e => e.LiebUserId == id); } } } diff --git a/Lieb/Pages/Users/Index.cshtml.cs b/Lieb/Pages/Users/Index.cshtml.cs index 046e32a..9a79d27 100644 --- a/Lieb/Pages/Users/Index.cshtml.cs +++ b/Lieb/Pages/Users/Index.cshtml.cs @@ -24,7 +24,7 @@ namespace Lieb.Pages.Users public async Task OnGetAsync() { - User = await _context.Users.ToListAsync(); + User = await _context.LiebUsers.ToListAsync(); } } } diff --git a/Lieb/Program.cs b/Lieb/Program.cs index 9869132..b3c6eea 100644 --- a/Lieb/Program.cs +++ b/Lieb/Program.cs @@ -1,10 +1,7 @@ using Discord.OAuth2; using Lieb.Data; using Microsoft.AspNetCore.Authentication.Cookies; -using Microsoft.AspNetCore.Components; -using Microsoft.AspNetCore.Components.Web; using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; var builder = WebApplication.CreateBuilder(args); @@ -32,6 +29,15 @@ builder.Services.AddAuthentication(opt => x.SaveTokens = true; }); +builder.Services.AddAuthorization(options => +{ + foreach(string role in Constants.Roles.GetAllRoles()) + { + options.AddPolicy(role, policy => policy.RequireClaim(Constants.ClaimType, role)); + } +}); + + var app = builder.Build(); // Configure the HTTP request pipeline. @@ -62,6 +68,7 @@ app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); +app.UseAuthorization(); app.UseEndpoints(endpoints => { diff --git a/Lieb/Shared/MainLayout.razor b/Lieb/Shared/MainLayout.razor index 4974751..e7728b0 100644 --- a/Lieb/Shared/MainLayout.razor +++ b/Lieb/Shared/MainLayout.razor @@ -1,4 +1,7 @@ -@inherits LayoutComponentBase +@using System.Security.Claims +@using Microsoft.AspNetCore.Components.Authorization +@inject AuthenticationStateProvider AuthenticationStateProvider +@inherits LayoutComponentBase Lieb @@ -20,9 +23,54 @@ + +

You can only see this if you are loged in

+
+ +

You can only see this if you satisfy the "Admin" policy.

+
+
@Body
+ +

@_authMessage

+ +@if (_claims.Count() > 0) +{ +
    + @foreach (var claim in _claims) + { +
  • @claim.Type: @claim.Value
  • + } +
+} + +

@_surnameMessage

+ +@code { + private string _authMessage; + private string _surnameMessage; + private IEnumerable _claims = Enumerable.Empty(); + + private async Task GetClaimsPrincipalData() + { + var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); + var user = authState.User; + + if (user.Identity.IsAuthenticated) + { + _authMessage = $"{user.Identity.Name} is authenticated."; + _claims = user.Claims; + _surnameMessage = + $"Surname: {user.FindFirst(c => c.Type == ClaimTypes.Surname)?.Value}"; + } + else + { + _authMessage = "The user is NOT authenticated."; + } + } +} \ No newline at end of file