Added Authorization

This commit is contained in:
t.ruspekhofer 2022-02-22 01:06:41 +01:00
parent 04049f31f6
commit e47d6488c2
15 changed files with 134 additions and 21 deletions

21
Lieb/Data/Constants.cs Normal file
View file

@ -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<string> GetAllRoles()
{
return typeof(Roles).GetFields().Select(f => f.GetValue(f)).Cast<string>().ToList();
}
}
}
}

View file

@ -7,19 +7,27 @@ namespace Lieb.Data
public static void Initialize(LiebContext context) public static void Initialize(LiebContext context)
{ {
// Look for any students. // Look for any students.
if (context.Users.Any()) if (context.LiebUsers.Any())
{ {
return; // DB has been seeded 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[] var users = new LiebUser[]
{ {
new LiebUser{DiscordUserId=0, Name="Sarah",Birthday=DateTime.Parse("1992-01-15")}, new LiebUser{DiscordUserId=0, Name="Sarah",Birthday=DateTime.Parse("1992-01-15"), Roles=new List<UserRole>(){admin}},
new LiebUser{DiscordUserId=0, Name="Lisa",Birthday=DateTime.Parse("1991-02-15")}, new LiebUser{DiscordUserId=1, Name="Lisa",Birthday=DateTime.Parse("1991-02-15"), Roles=new List<UserRole>(){guildLead} },
new LiebUser{DiscordUserId=0, Name="Simon",Birthday=DateTime.Parse("2019-09-01")} new LiebUser{DiscordUserId=2, Name="Simon",Birthday=DateTime.Parse("2019-09-01"), Roles=new List<UserRole>(){member}}
}; };
context.Users.AddRange(users); context.LiebUsers.AddRange(users);
context.SaveChanges(); context.SaveChanges();
} }

View file

@ -13,7 +13,8 @@ namespace Lieb.Data
{ {
} }
public DbSet<LiebUser> Users { get; set; } public DbSet<LiebUser> LiebUsers { get; set; }
public DbSet<UserRole> UserRoles { get; set; }
public DbSet<GuildWars2Account> GuildWars2Account { get; set; } public DbSet<GuildWars2Account> GuildWars2Account { get; set; }
public DbSet<Equipped> Equipped { get; set; } public DbSet<Equipped> Equipped { get; set; }
public DbSet<GuildWars2Build> RaidRoles { get; set; } public DbSet<GuildWars2Build> RaidRoles { get; set; }
@ -27,6 +28,7 @@ namespace Lieb.Data
protected override void OnModelCreating(ModelBuilder modelBuilder) protected override void OnModelCreating(ModelBuilder modelBuilder)
{ {
modelBuilder.Entity<LiebUser>().ToTable("LiebUser"); modelBuilder.Entity<LiebUser>().ToTable("LiebUser");
modelBuilder.Entity<UserRole>().ToTable("UserRole");
modelBuilder.Entity<GuildWars2Account>().ToTable("GuildWars2Account"); modelBuilder.Entity<GuildWars2Account>().ToTable("GuildWars2Account");
modelBuilder.Entity<Equipped>().ToTable("Equipped"); modelBuilder.Entity<Equipped>().ToTable("Equipped");
modelBuilder.Entity<GuildWars2Build>().ToTable("GuildWars2Build"); modelBuilder.Entity<GuildWars2Build>().ToTable("GuildWars2Build");

View file

@ -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.AspNetCore.Authentication.OAuth;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Security.Claims; using System.Security.Claims;
@ -10,9 +13,12 @@ namespace Discord.OAuth2
{ {
internal class DiscordHandler : OAuthHandler<DiscordOptions> internal class DiscordHandler : OAuthHandler<DiscordOptions>
{ {
public DiscordHandler(IOptionsMonitor<DiscordOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) private readonly Lieb.Data.LiebContext _LiebDbcontext;
public DiscordHandler(IOptionsMonitor<DiscordOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, Lieb.Data.LiebContext context)
: base(options, logger, encoder, clock) : base(options, logger, encoder, clock)
{ {
_LiebDbcontext = context;
} }
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens) protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
@ -30,6 +36,16 @@ namespace Discord.OAuth2
context.RunClaimActions(); context.RunClaimActions();
await Events.CreatingTicket(context); 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); return new AuthenticationTicket(context.Principal, context.Properties, Scheme.Name);
} }
} }

View file

@ -16,6 +16,7 @@ namespace Discord.OAuth2
TokenEndpoint = DiscordDefaults.TokenEndpoint; TokenEndpoint = DiscordDefaults.TokenEndpoint;
UserInformationEndpoint = DiscordDefaults.UserInformationEndpoint; UserInformationEndpoint = DiscordDefaults.UserInformationEndpoint;
Scope.Add("identify"); Scope.Add("identify");
//Scope.Add("guilds.members.read");
ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id", ClaimValueTypes.UInteger64); ClaimActions.MapJsonKey(ClaimTypes.NameIdentifier, "id", ClaimValueTypes.UInteger64);
ClaimActions.MapJsonKey(ClaimTypes.Name, "username", ClaimValueTypes.String); ClaimActions.MapJsonKey(ClaimTypes.Name, "username", ClaimValueTypes.String);

View file

@ -8,7 +8,7 @@
RandomEliteSpecialization = 4, RandomEliteSpecialization = 4,
} }
public abstract class Raid public class Raid
{ {
public int RaidId { get; private set; } public int RaidId { get; private set; }

View file

@ -10,5 +10,6 @@ namespace Lieb.Models
public string Pronouns { get; set; } = string.Empty; public string Pronouns { get; set; } = string.Empty;
public DateTime? Birthday { get; set; } public DateTime? Birthday { get; set; }
public ICollection<GuildWars2Account> GuildWars2Accounts { get; set; } = new List<GuildWars2Account>(); public ICollection<GuildWars2Account> GuildWars2Accounts { get; set; } = new List<GuildWars2Account>();
public ICollection<UserRole> Roles { get; set; } = new List<UserRole>();
} }
} }

9
Lieb/Models/UserRole.cs Normal file
View file

@ -0,0 +1,9 @@
namespace Lieb.Models
{
public class UserRole
{
public int UserRoleId { get; set; }
public string RoleName { get; set; } = string.Empty;
}
}

View file

@ -36,7 +36,7 @@ namespace Lieb.Pages.Users
return Page(); return Page();
} }
_context.Users.Add(User); _context.LiebUsers.Add(User);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
return RedirectToPage("./Index"); return RedirectToPage("./Index");

View file

@ -30,7 +30,7 @@ namespace Lieb.Pages.Users
return NotFound(); return NotFound();
} }
User = await _context.Users.FirstOrDefaultAsync(m => m.LiebUserId == id); User = await _context.LiebUsers.FirstOrDefaultAsync(m => m.LiebUserId == id);
if (User == null) if (User == null)
{ {
@ -46,11 +46,11 @@ namespace Lieb.Pages.Users
return NotFound(); return NotFound();
} }
User = await _context.Users.FindAsync(id); User = await _context.LiebUsers.FindAsync(id);
if (User != null) if (User != null)
{ {
_context.Users.Remove(User); _context.LiebUsers.Remove(User);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
} }

View file

@ -29,7 +29,7 @@ namespace Lieb.Pages.Users
return NotFound(); return NotFound();
} }
User = await _context.Users.FirstOrDefaultAsync(m => m.LiebUserId == id); User = await _context.LiebUsers.FirstOrDefaultAsync(m => m.LiebUserId == id);
if (User == null) if (User == null)
{ {

View file

@ -31,7 +31,7 @@ namespace Lieb.Pages.Users
return NotFound(); return NotFound();
} }
User = await _context.Users.FirstOrDefaultAsync(m => m.LiebUserId == id); User = await _context.LiebUsers.FirstOrDefaultAsync(m => m.LiebUserId == id);
if (User == null) if (User == null)
{ {
@ -72,7 +72,7 @@ namespace Lieb.Pages.Users
private bool UserExists(int id) private bool UserExists(int id)
{ {
return _context.Users.Any(e => e.LiebUserId == id); return _context.LiebUsers.Any(e => e.LiebUserId == id);
} }
} }
} }

View file

@ -24,7 +24,7 @@ namespace Lieb.Pages.Users
public async Task OnGetAsync() public async Task OnGetAsync()
{ {
User = await _context.Users.ToListAsync(); User = await _context.LiebUsers.ToListAsync();
} }
} }
} }

View file

@ -1,10 +1,7 @@
using Discord.OAuth2; using Discord.OAuth2;
using Lieb.Data; using Lieb.Data;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
@ -32,6 +29,15 @@ builder.Services.AddAuthentication(opt =>
x.SaveTokens = true; 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(); var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
@ -62,6 +68,7 @@ app.UseStaticFiles();
app.UseRouting(); app.UseRouting();
app.UseAuthentication(); app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => app.UseEndpoints(endpoints =>
{ {

View file

@ -1,4 +1,7 @@
@inherits LayoutComponentBase @using System.Security.Claims
@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider
@inherits LayoutComponentBase
<PageTitle>Lieb</PageTitle> <PageTitle>Lieb</PageTitle>
@ -20,9 +23,54 @@
</NotAuthorized> </NotAuthorized>
</AuthorizeView> </AuthorizeView>
</div> </div>
<AuthorizeView>
<p>You can only see this if you are loged in</p>
</AuthorizeView>
<AuthorizeView Policy="Admin">
<p>You can only see this if you satisfy the "Admin" policy.</p>
</AuthorizeView>
<article class="content px-4"> <article class="content px-4">
@Body @Body
</article> </article>
<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>
</main> </main>
</div> </div>
<p>@_authMessage</p>
@if (_claims.Count() > 0)
{
<ul>
@foreach (var claim in _claims)
{
<li>@claim.Type: @claim.Value</li>
}
</ul>
}
<p>@_surnameMessage</p>
@code {
private string _authMessage;
private string _surnameMessage;
private IEnumerable<Claim> _claims = Enumerable.Empty<Claim>();
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.";
}
}
}