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)
{
// 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<UserRole>(){admin}},
new LiebUser{DiscordUserId=1, Name="Lisa",Birthday=DateTime.Parse("1991-02-15"), Roles=new List<UserRole>(){guildLead} },
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();
}

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<Equipped> Equipped { get; set; }
public DbSet<GuildWars2Build> RaidRoles { get; set; }
@ -27,6 +28,7 @@ namespace Lieb.Data
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<LiebUser>().ToTable("LiebUser");
modelBuilder.Entity<UserRole>().ToTable("UserRole");
modelBuilder.Entity<GuildWars2Account>().ToTable("GuildWars2Account");
modelBuilder.Entity<Equipped>().ToTable("Equipped");
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.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<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)
{
_LiebDbcontext = context;
}
protected override async Task<AuthenticationTicket> 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);
}
}

View file

@ -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);

View file

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

View file

@ -10,5 +10,6 @@ namespace Lieb.Models
public string Pronouns { get; set; } = string.Empty;
public DateTime? Birthday { get; set; }
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();
}
_context.Users.Add(User);
_context.LiebUsers.Add(User);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");

View file

@ -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();
}

View file

@ -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)
{

View file

@ -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);
}
}
}

View file

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

View file

@ -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 =>
{

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>
@ -20,9 +23,54 @@
</NotAuthorized>
</AuthorizeView>
</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">
@Body
</article>
<button @onclick="GetClaimsPrincipalData">Get ClaimsPrincipal Data</button>
</main>
</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.";
}
}
}