0% found this document useful (0 votes)
30 views76 pages

Using FlexibleAuth

using flexible uthorization on ASP.NET Core

Uploaded by

saidmtanzania
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
30 views76 pages

Using FlexibleAuth

using flexible uthorization on ASP.NET Core

Uploaded by

saidmtanzania
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 76

using FlexibleAuth.Server.

Models;
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using System.Security.Claims;

namespace FlexibleAuth.Server.Authorization;

public class ApplicationUserClaimsPrincipalFactory :


UserClaimsPrincipalFactory<User, Role>
{
public ApplicationUserClaimsPrincipalFactory(
UserManager<User> userManager,
RoleManager<Role> roleManager,
IOptions<IdentityOptions> optionsAccessor)
: base(userManager, roleManager, optionsAccessor)
{ }

protected override async Task<ClaimsIdentity> GenerateClaimsAsync(User user)


{
var identity = await base.GenerateClaimsAsync(user);

var userRoleNames = await UserManager.GetRolesAsync(user) ??


Array.Empty<string>();

var userRoles = await RoleManager.Roles.Where(r =>


userRoleNames.Contains(r.Name!)).ToListAsync();

var userPermissions = Permissions.None;

foreach (var role in userRoles)


userPermissions |= role.Permissions;

var permissionsValue = (int)userPermissions;

identity.AddClaim(
new Claim(CustomClaimTypes.Permissions,
permissionsValue.ToString()));

return identity;
}
}

using FlexibleAuth.Server.Models;
using FlexibleAuth.Shared;
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
namespace FlexibleAuth.Server.Controllers.Admin;

[ApiController]
[Route("api/Admin/[controller]")]
public class AccessControlController : ControllerBase
{
private readonly RoleManager<Role> _roleManager;

public AccessControlController(RoleManager<Role> roleManager)


{
_roleManager = roleManager;
}

[HttpGet]
[Authorize(Permissions.ViewAccessControl)]
public async Task<ActionResult<AccessControlVm>> GetConfiguration()
{
var roles = await _roleManager.Roles
.ToListAsync();

var roleDtos = roles


.Select(r => new RoleDto(r.Id, r.Name ?? string.Empty,
r.Permissions))
.OrderBy(r => r.Name)
.ToList();

return new AccessControlVm(roleDtos);


}

[HttpPut]
[Authorize(Permissions.ConfigureAccessControl)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
public async Task<IActionResult> UpdateConfiguration(RoleDto updatedRole)
{
var role = await _roleManager.FindByIdAsync(updatedRole.Id);

if (role != null)
{
role.Permissions = updatedRole.Permissions;

await _roleManager.UpdateAsync(role);
}

return NoContent();
}
}

using FlexibleAuth.Server.Models;
using FlexibleAuth.Shared;
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace FlexibleAuth.Server.Controllers.Admin;

[ApiController]
[Route("api/Admin/[controller]")]
public class RolesController : ControllerBase
{
private readonly RoleManager<Role> _roleManager;

public RolesController(RoleManager<Role> roleManager)


{
_roleManager = roleManager;
}

// GET: api/Admin/Roles
[HttpGet]
[Authorize(Permissions.ViewRoles)]
public async Task<ActionResult<IEnumerable<RoleDto>>> GetRoles()
{
var roles = await _roleManager.Roles
.OrderBy(r => r.Name)
.ToListAsync();

return roles
.Select(r => new RoleDto(r.Id, r.Name ?? string.Empty,
r.Permissions))
.ToList();
}

// POST: api/Admin/Roles
// To protect from overposting attacks, see
https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPost]
[Authorize(Permissions.ManageRoles)]
public async Task<ActionResult<RoleDto>> PostRole(RoleDto newRole)
{
var role = new Role { Name = newRole.Name };

await _roleManager.CreateAsync(role);

return new RoleDto(role.Id, role.Name, role.Permissions);


}

// PUT: api/Admin/Roles/5
// To protect from overposting attacks, see
https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPut("{id}")]
[Authorize(Permissions.ManageRoles)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> PutRole(string id, RoleDto updatedRole)
{
if (id != updatedRole.Id)
{
return BadRequest();
}

var role = await _roleManager.FindByIdAsync(id);

if (role == null)
{
return NotFound();
}

role.Name = updatedRole.Name;

await _roleManager.UpdateAsync(role);

if (role == null)
{
return NotFound();
}

return NoContent();
}

// DELETE: api/Admin/Roles/5
[HttpDelete("{id}")]
[Authorize(Permissions.ManageRoles)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
public async Task<IActionResult> DeleteRole(string id)
{
var role = await _roleManager.FindByIdAsync(id);
if (role == null)
{
return NotFound();
}

await _roleManager.DeleteAsync(role);

return NoContent();
}
}

using FlexibleAuth.Server.Models;
using FlexibleAuth.Shared;
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace FlexibleAuth.Server.Controllers.Admin
{
[ApiController]
[Route("api/Admin/[controller]")]
public class UsersController : ControllerBase
{
private readonly UserManager<User> _userManager;

public UsersController(UserManager<User> userManager)


{
_userManager = userManager;
}

// GET: api/Admin/Users
[HttpGet]
[Authorize(Permissions.ViewUsers | Permissions.ManageUsers)]
public async Task<ActionResult<IEnumerable<UserDto>>> GetUsers()
{
return await _userManager.Users
.OrderBy(r => r.UserName)
.Select(u => new UserDto(u.Id, u.UserName ?? string.Empty,
u.Email ?? string.Empty))
.ToListAsync();
}

// GET: api/Admin/Users/5
[HttpGet("{id}")]
[Authorize(Permissions.ViewUsers)]
public async Task<ActionResult<UserDto>> GetUser(string id)
{
var user = await _userManager.FindByIdAsync(id);

if (user == null)
{
return NotFound();
}

var dto = new UserDto(user.Id, user.UserName ?? string.Empty,


user.Email ?? string.Empty);

var roles = await _userManager.GetRolesAsync(user);

dto.Roles.AddRange(roles);

return dto;
}

// PUT: api/Admin/Users/5
// To protect from overposting attacks, see
https://go.microsoft.com/fwlink/?linkid=2123754
[HttpPut("{id}")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[Authorize(Permissions.ManageUsers)]
public async Task<IActionResult> PutUser(string id, UserDto updatedUser)
{
if (id != updatedUser.Id)
{
return BadRequest();
}

var user = await _userManager.FindByIdAsync(id);

if (user == null)
{
return NotFound();
}

user.UserName = updatedUser.UserName;
user.Email = updatedUser.Email;

await _userManager.UpdateAsync(user);

var currentRoles = await _userManager.GetRolesAsync(user);


var addedRoles = updatedUser.Roles.Except(currentRoles);
var removedRoles = currentRoles.Except(updatedUser.Roles);

if (addedRoles.Any())
{
await _userManager.AddToRolesAsync(user, addedRoles);
}

if (removedRoles.Any())
{
await _userManager.RemoveFromRolesAsync(user, removedRoles);
}

return NoContent();
}
}
}

using Microsoft.AspNetCore.ApiAuthorization.IdentityServer;
using Microsoft.AspNetCore.Mvc;

namespace FlexibleAuth.Server.Controllers;

[ApiExplorerSettings(IgnoreApi = true)]
public class OidcConfigurationController : Controller
{
private readonly ILogger<OidcConfigurationController> _logger;

public OidcConfigurationController(IClientRequestParametersProvider
clientRequestParametersProvider, ILogger<OidcConfigurationController> logger)
{
ClientRequestParametersProvider = clientRequestParametersProvider;
_logger = logger;
}

public IClientRequestParametersProvider ClientRequestParametersProvider {


get; }

[HttpGet("_configuration/{clientId}")]
public IActionResult GetClientRequestParameters([FromRoute] string clientId)
{
var parameters =
ClientRequestParametersProvider.GetClientParameters(HttpContext, clientId);
return Ok(parameters);
}
}

using FlexibleAuth.Shared;
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace FlexibleAuth.Server.Controllers;

[Authorize(Permissions.Forecast)]
[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]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}

using Duende.IdentityServer.EntityFramework.Entities;
using Duende.IdentityServer.EntityFramework.Extensions;
using Duende.IdentityServer.EntityFramework.Interfaces;
using Duende.IdentityServer.EntityFramework.Options;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;

namespace FlexibleAuth.Server.Data;

// Based on
https://github.com/dotnet/aspnetcore/blob/main/src/Identity/ApiAuthorization.Iden
tityServer/src/Data/ApiAuthorizationDbContext.cs
// Customised to add TRole.
public class ApiAuthorizationDbContext<TUser, TRole> : IdentityDbContext<TUser,
TRole, string>, IPersistedGrantDbContext where TUser : IdentityUser where TRole :
IdentityRole
{
private readonly IOptions<OperationalStoreOptions> _operationalStoreOptions;

/// <summary>
/// Initializes a new instance of <see
cref="ApiAuthorizationDbContext{TUser}"/>.
/// </summary>
/// <param name="options">The <see cref="DbContextOptions"/>.</param>
/// <param name="operationalStoreOptions">The <see
cref="IOptions{OperationalStoreOptions}"/>.</param>
public ApiAuthorizationDbContext(
DbContextOptions options,
IOptions<OperationalStoreOptions> operationalStoreOptions)
: base(options)
{
_operationalStoreOptions = operationalStoreOptions;
}

/// <summary>
/// Gets or sets the <see cref="DbSet{PersistedGrant}"/>.
/// </summary>
public DbSet<PersistedGrant> PersistedGrants { get; set; }

/// <summary>
/// Gets or sets the <see cref="DbSet{DeviceFlowCodes}"/>.
/// </summary>
public DbSet<DeviceFlowCodes> DeviceFlowCodes { get; set; }

/// <summary>
/// Gets or sets the <see cref="DbSet{Key}"/>.
/// </summary>
public DbSet<Key> Keys { get; set; }

Task<int> IPersistedGrantDbContext.SaveChangesAsync() =>


base.SaveChangesAsync();

/// <inheritdoc />


protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value);
}
}

using FlexibleAuth.Server.Models;
using Duende.IdentityServer.EntityFramework.Options;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using System.Reflection;

namespace FlexibleAuth.Server.Data
{
public class ApplicationDbContext : ApiAuthorizationDbContext<User, Role>
{
public ApplicationDbContext(
DbContextOptions options,
IOptions<OperationalStoreOptions> operationalStoreOptions) :
base(options, operationalStoreOptions)
{
}

protected override void OnModelCreating(ModelBuilder builder)


{
base.OnModelCreating(builder);

builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
}
}
}
using FlexibleAuth.Server.Models;
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

namespace FlexibleAuth.Server.Data;
public class DbInitializer
{
private readonly ApplicationDbContext _context;
private readonly UserManager<User> _userManager;
private readonly RoleManager<Role> _roleManager;

private const string AdministratorsRole = "Administrators";


private const string AccountsRole = "Accounts";
private const string OperationsRole = "Operations";

private const string DefaultPassword = "Password123!";

public DbInitializer(
ApplicationDbContext context,
UserManager<User> userManager,
RoleManager<Role> roleManager)
{
_context = context;
_userManager = userManager;
_roleManager = roleManager;
}

public async Task RunAsync()


{
_context.Database.Migrate();

// Create roles
await _roleManager.CreateAsync(
new Role
{
Name = AdministratorsRole,
NormalizedName = AdministratorsRole.ToUpper(),
Permissions = Permissions.All
});

await _roleManager.CreateAsync(
new Role
{
Name = AccountsRole,
NormalizedName = AccountsRole.ToUpper(),
Permissions =
Permissions.ViewUsers |
Permissions.Counter
});

await _roleManager.CreateAsync(
new Role
{
Name = OperationsRole,
NormalizedName = OperationsRole.ToUpper(),
Permissions =
Permissions.ViewUsers |
Permissions.Forecast
});

// Ensure admin role has all permissions


var adminRole = await _roleManager.FindByNameAsync(AdministratorsRole);
adminRole!.Permissions = Permissions.All;
await _roleManager.UpdateAsync(adminRole);

// Create default admin user


var adminUserName = "admin@localhost";
var adminUser = new User { UserName = adminUserName, Email =
adminUserName };
await _userManager.CreateAsync(adminUser, DefaultPassword);

adminUser = await _userManager.FindByNameAsync(adminUserName);


if (adminUser != null)
{
await _userManager.AddToRoleAsync(adminUser, AdministratorsRole);
}

// Create default auditor user


var auditorUserName = "auditor@localhost";
var auditorUser = new User { UserName = auditorUserName, Email =
auditorUserName };
await _userManager.CreateAsync(auditorUser, DefaultPassword);

await _context.SaveChangesAsync();
}
}

using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Identity;

namespace FlexibleAuth.Server.Models;

public class Role : IdentityRole


{
public Permissions Permissions { get; set; }
}

using FlexibleAuth.Shared;
using Microsoft.AspNetCore.Identity;

namespace FlexibleAuth.Server.Models;

public class User : IdentityUser


{
}
@page
@model FlexibleAuth.Server.Pages.ErrorModel

<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0,
maximum-scale=1.0, user-scalable=no" />
<title>Error</title>
<link href="~/css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="~/css/app.css" rel="stylesheet" asp-append-version="true" />
</head>

<body>
<div class="main">
<div class="content px-4">
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your
request.</h2>

@if (Model.ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@Model.RequestId</code>
</p>
}

<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays
detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for
deployed applications.</strong>
It can result in displaying sensitive information from exceptions
to end users.
For local debugging, enable the <strong>Development</strong>
environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment
variable to <strong>Development</strong>
and restarting the app.
</p>
</div>
</div>
</body>

</html>
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Diagnostics;

namespace FlexibleAuth.Server.Pages
{
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore =
true)]
[IgnoreAntiforgeryToken]
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }

public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);

private readonly ILogger<ErrorModel> _logger;

public ErrorModel(ILogger<ErrorModel> logger)


{
_logger = logger;
}

public void OnGet()


{
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}
}
using FlexibleAuth.Server.Authorization;
using FlexibleAuth.Server.Data;
using FlexibleAuth.Server.Models;
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using System.IdentityModel.Tokens.Jwt;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.


var connectionString =
builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services
.AddDefaultIdentity<User>(options => options.SignIn.RequireConfirmedAccount =
false)
.AddRoles<Role>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddClaimsPrincipalFactory<ApplicationUserClaimsPrincipalFactory>();
builder.Services.AddIdentityServer()
.AddApiAuthorization<User, ApplicationDbContext>(options =>
{
options.IdentityResources["openid"].UserClaims.Add("role");
options.ApiResources.Single().UserClaims.Add("role");
options.IdentityResources["openid"].UserClaims.Add("permissions");
options.ApiResources.Single().UserClaims.Add("permissions");
});

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("role");

builder.Services.AddAuthentication()
.AddIdentityServerJwt();

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

builder.Services.AddOpenApiDocument(configure =>
{
configure.Title = "FlexibleAuth";
});

builder.Services.AddScoped<DbInitializer>();

builder.Services.AddSingleton<IAuthorizationHandler,
PermissionAuthorizationHandler>();
builder.Services.AddSingleton<IAuthorizationPolicyProvider,
FlexibleAuthorizationPolicyProvider>();

var app = builder.Build();

// Configure the HTTP request pipeline.


if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
app.UseWebAssemblyDebugging();

using var scope = app.Services.CreateScope();

var services = scope.ServiceProvider;

var initializer = services.GetRequiredService<DbInitializer>();

await initializer.RunAsync();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for
production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}

app.UseHttpsRedirection();

app.UseBlazorFrameworkFiles();
app.UseStaticFiles();

app.UseRouting();

app.UseOpenApi();
app.UseSwaggerUi3();

app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();
app.MapControllers();
app.MapFallbackToFile("index.html");

app.Run();

namespace FlexibleAuth.Shared.Authorization;

public class AuthorizeAttribute :


Microsoft.AspNetCore.Authorization.AuthorizeAttribute
{
public AuthorizeAttribute() { }

public AuthorizeAttribute(string policy) : base(policy) { }

public AuthorizeAttribute(Permissions permission)


{
Permissions = permission;
}

public Permissions Permissions


{
get
{
return !string.IsNullOrEmpty(Policy)
? PolicyNameHelper.GetPermissionsFrom(Policy)
: Permissions.None;
}
set
{
Policy = value != Permissions.None
? PolicyNameHelper.GeneratePolicyNameFor(value)
: string.Empty;
}
}
}

namespace System.Security.Claims;

public static class CustomClaimTypes


{
public const string Permissions = "permissions";
}

using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;

namespace FlexibleAuth.Shared.Authorization;

public class FlexibleAuthorizationPolicyProvider :


DefaultAuthorizationPolicyProvider
{
private readonly AuthorizationOptions _options;

public FlexibleAuthorizationPolicyProvider(IOptions<AuthorizationOptions>
options)
: base(options)
{
_options = options.Value;
}

public override async Task<AuthorizationPolicy?> GetPolicyAsync(string


policyName)
{
var policy = await base.GetPolicyAsync(policyName);

if (policy == null && PolicyNameHelper.IsValidPolicyName(policyName))


{
var permissions = PolicyNameHelper.GetPermissionsFrom(policyName);

policy = new AuthorizationPolicyBuilder()


.AddRequirements(new
PermissionAuthorizationRequirement(permissions))
.Build();

_options.AddPolicy(policyName!, policy);
}

return policy;
}
}

using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;
namespace FlexibleAuth.Shared.Authorization;

public static class IAuthorizationServiceExtensions


{
public static Task<AuthorizationResult> AuthorizeAsync(this
IAuthorizationService service, ClaimsPrincipal user, Permissions permissions)
{
return service.AuthorizeAsync(user,
PolicyNameHelper.GeneratePolicyNameFor(permissions));
}
}

using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;

namespace FlexibleAuth.Shared.Authorization;

public class PermissionAuthorizationHandler :


AuthorizationHandler<PermissionAuthorizationRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext
context, PermissionAuthorizationRequirement requirement)
{
var permissionClaim = context.User.FindFirst(
c => c.Type == CustomClaimTypes.Permissions);

if (permissionClaim == null)
{
return Task.CompletedTask;
}

if (!int.TryParse(permissionClaim.Value, out int permissionClaimValue))


{
return Task.CompletedTask;
}

var userPermissions = (Permissions)permissionClaimValue;

if ((userPermissions & requirement.Permissions) != 0)


{
context.Succeed(requirement);
return Task.CompletedTask;
}

return Task.CompletedTask;
}
}

using Microsoft.AspNetCore.Authorization;
namespace FlexibleAuth.Shared.Authorization;

public class PermissionAuthorizationRequirement : IAuthorizationRequirement


{
public PermissionAuthorizationRequirement(Permissions permission)
{
Permissions = permission;
}

public Permissions Permissions { get; }


}

namespace FlexibleAuth.Shared.Authorization;

[Flags]
public enum Permissions
{
None = 0,
ViewRoles = 1,
ManageRoles = 2,
ViewUsers = 4,
ManageUsers = 8,
ConfigureAccessControl = 16,
Counter = 32,
Forecast = 64,
ViewAccessControl = 128,
All = ~None
}
namespace FlexibleAuth.Shared.Authorization;

public static class PermissionsProvider


{
public static List<Permissions> GetAll()
{
return Enum.GetValues(typeof(Permissions))
.OfType<Permissions>()
.ToList();
}
}

namespace FlexibleAuth.Shared.Authorization;

public static class PolicyNameHelper


{
public const string Prefix = "Permissions";

public static bool IsValidPolicyName(string? policyName)


{
return policyName != null && policyName.StartsWith(Prefix,
StringComparison.OrdinalIgnoreCase);
}
public static string GeneratePolicyNameFor(Permissions permissions)
{
return $"{Prefix}{(int)permissions}";
}

public static Permissions GetPermissionsFrom(string policyName)


{
var permissionsValue = int.Parse(policyName[Prefix.Length..]!);

return (Permissions)permissionsValue;
}
}

using FlexibleAuth.Shared.Authorization;

namespace FlexibleAuth.Shared;

public class AccessControlVm


{
internal AccessControlVm() { }

public AccessControlVm(List<RoleDto> roles)


{
Roles = roles;

foreach(var permission in PermissionsProvider.GetAll())


{
if (permission == Permissions.None) continue;

AvailablePermissions.Add(permission);
}
}

public List<RoleDto> Roles { get; set; } = new();

public List<Permissions> AvailablePermissions { get; set; } = new();


}

using FlexibleAuth.Shared.Authorization;

namespace FlexibleAuth.Shared;

public class RoleDto


{
public RoleDto()
{
Id = string.Empty;
Name = string.Empty;
Permissions = Permissions.None;
}
public RoleDto(string id, string name, Permissions permissions)
{
Id = id;
Name = name;
Permissions = permissions;
}

public string Id { get; set; }

public string Name { get; set; }

public Permissions Permissions { get; set; }

public bool Has(Permissions permission)


{
return Permissions.HasFlag(permission);;
}

public void Set(Permissions permission, bool granted)


{
if (granted)
{
Grant(permission);
}
else
{
Revoke(permission);
}
}

public void Grant(Permissions permission)


{
Permissions |= permission;
}

public void Revoke(Permissions permission)


{
Permissions ^= permission;
}
}
namespace FlexibleAuth.Shared;

public class UserDto


{
public UserDto() : this(string.Empty, string.Empty, string.Empty) { }

public UserDto(string id, string userName, string email)


{
Id = id;
UserName = userName;
Email = email;
}

public string Id { get; set; }

public string UserName { get; set; }

public string Email { get; set; }

public List<string> Roles { get; set; } = new();


}

namespace FlexibleAuth.Shared;

public class WeatherForecast


{
public DateTime Date { get; set; }

public int TemperatureC { get; set; }

public string? Summary { get; set; }

public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);


}

@using Microsoft.AspNetCore.Identity
@using FlexibleAuth.Server.Models
@inject SignInManager<User> SignInManager
@inject UserManager<User> UserManager
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@{
var returnUrl = "/";
if (Context.Request.Query.TryGetValue("returnUrl", out var existingUrl)) {
returnUrl = existingUrl;
}
}

<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-
page="/Account/Manage/Index" title="Manage">Hello @User.Identity?.Name!</a>
</li>
<li class="nav-item">
<form class="form-inline" asp-area="Identity" asp-page="/Account/Logout"
asp-route-returnUrl="/" method="post">
<button type="submit" class="nav-link btn btn-link text-
dark">Logout</button>
</form>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-
page="/Account/Register" asp-route-returnUrl="@returnUrl">Register</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="Identity" asp-
page="/Account/Login" asp-route-returnUrl="@returnUrl">Login</a>
</li>
}
</ul>

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
using System.Security.Claims;
using System.Text.Json;

namespace FlexibleAuth.Client.Authorization;

public class CustomAccountClaimsPrincipalFactory :


AccountClaimsPrincipalFactory<RemoteUserAccount>
{
public CustomAccountClaimsPrincipalFactory(IAccessTokenProviderAccessor
accessor)
: base(accessor)
{
}
public async override ValueTask<ClaimsPrincipal> CreateUserAsync(
RemoteUserAccount account,
RemoteAuthenticationUserOptions options)
{
var user = await base.CreateUserAsync(account, options);

var identity = (ClaimsIdentity)user.Identity!;

if (account != null)
{
foreach (var property in account.AdditionalProperties)
{
var key = property.Key;
var value = property.Value;

if (value != null &&


value is JsonElement element && element.ValueKind ==
JsonValueKind.Array)
{
identity.RemoveClaim(identity.FindFirst(property.Key));
var claims = element.EnumerateArray()
.Select(x => new Claim(property.Key, x.ToString()));

identity.AddClaims(claims);
}
}
}

return user;
}
}

@page "/admin/access-control"
@attribute [Authorize(Permissions.ViewAccessControl |
Permissions.ConfigureAccessControl)]

<PageTitle>Access Control</PageTitle>

<h1>Access Control</h1>

<p>This is a description.</p>

@if (_vm == null) return;

<table class="table table-hover">


<thead>
<tr>
<th>Permissions</th>
@foreach(var role in _vm.Roles)
{
<th>@role.Name</th>
}
</tr>
</thead>
<tbody>
@foreach(var permission in _vm.AvailablePermissions)
{
<tr>
<th>@permission.ToString()</th>
@foreach(var role in _vm.Roles)
{
<th>
<FlexibleAuthorizeView
Permissions="@Permissions.ConfigureAccessControl">
<Authorized>
<input
type="checkbox"
class="form-check-input"
checked="@role.Has(permission)"
@onchange="(args) =>
Set(role, permission, (bool)args.Value!)"
/>
</Authorized>
<NotAuthorized>
<input
type="checkbox"
class="form-check-input"
checked="@role.Has(permission)"
disabled="disabled" />
</NotAuthorized>
</FlexibleAuthorizeView>
</th>
}
</tr>
}
</tbody>
</table>
using FlexibleAuth.Client.Services;
using FlexibleAuth.Shared;
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Components;

namespace FlexibleAuth.Client.Pages.Admin.AccessControl;

public partial class Index


{
[Inject]
private IAccessControlClient AccessControlClient { get; set; } = null!;

private AccessControlVm? _vm;

protected override async Task OnInitializedAsync()


{
_vm = await AccessControlClient.GetConfigurationAsync();
}

private async Task Set(RoleDto role, Permissions permission, bool granted)


{
role.Set(permission, granted);

await AccessControlClient.UpdateConfigurationAsync(role);
}
}

@page "/admin/roles"
@attribute [Authorize(Permissions.ViewRoles)]

<PageTitle>Roles</PageTitle>

<h1>Roles</h1>
<p>This is a description.</p>

<table class="table table-striped table-hover w-50">


<thead>
<tr>
<th>Name</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var role in Roles)
{
@if (role != roleToEdit)
{
<tr>
<td>
<input type="text" id="name" class="form-control-
plaintext" style="padding-left: 0.75rem" value="@role.Name" />
</td>
<td>
<FlexibleAuthorizeView
Permissions="@Permissions.ManageRoles">
<button type="button" class="btn btn-secondary"
@onclick="() => EditRole(role)">
<span class="oi oi-pencil"></span>
</button>
<button type="button" class="btn btn-secondary"
@onclick="() => DeleteRole(role)">
<span class="oi oi-x"></span>
</button>
</FlexibleAuthorizeView>
</td>
</tr>
}
else
{
<tr>
<td>
<input type="text" id="name" class="form-control"
@bind="@role.Name" />
</td>
<td>
<FlexibleAuthorizeView
Permissions="@Permissions.ManageRoles">
<button type="button" class="btn btn-secondary"
@onclick="() => UpdateRole()">
<span class="oi oi-check"></span>
</button>
<button type="button" class="btn btn-secondary"
@onclick="() => CancelEditRole()">
<span class="oi oi-action-undo"></span>
</button>
</FlexibleAuthorizeView>
</td>
</tr>
}
}
</tbody>
<FlexibleAuthorizeView Permissions="@Permissions.ManageRoles">
<tfoot>
<tr>
<td>
<input type="text" id="name" class="form-control"
placeholder="New Role..." @bind="newRoleName" />
</td>
<td>
<button type="button" class="btn btn-primary"
@onclick="AddRole">
<span class="oi oi-plus"></span>
</button>
</td>
</tr>
</tfoot>
</FlexibleAuthorizeView>
</table>
using FlexibleAuth.Client.Services;
using FlexibleAuth.Shared;
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Components;

namespace FlexibleAuth.Client.Pages.Admin.Roles;

public partial class Index


{
[Inject]
public IRolesClient RolesClient { get; set; } = null!;

public ICollection<RoleDto> Roles { get; set; } = new List<RoleDto>();

private string newRoleName = string.Empty;

private RoleDto? roleToEdit;

protected override async Task OnInitializedAsync()


{
Roles = await RolesClient.GetRolesAsync();
}

private async Task AddRole()


{
if (!string.IsNullOrWhiteSpace(newRoleName))
{
var role = await RolesClient.PostRoleAsync(
new RoleDto("", newRoleName, Permissions.None));

Roles.Add(role);
}

newRoleName = string.Empty;
}

private void EditRole(RoleDto role)


{
roleToEdit = role;
}

private void CancelEditRole()


{
roleToEdit = null;
}

private async Task UpdateRole()


{
await RolesClient.PutRoleAsync(roleToEdit!.Id, roleToEdit);

roleToEdit = null;
}

private async Task DeleteRole(RoleDto role)


{
await RolesClient.DeleteRoleAsync(role.Id);
Roles.Remove(role);
}
}

@page "/admin/users/{userId}"
@attribute [Authorize(Permissions.ManageUsers)]

<PageTitle>Users - Edit</PageTitle>

<h1>Edit</h1>

<h2>User</h2>

@if (User != null)


{
<div class="row">
<div class="col-md-4">

<EditForm Model="@User" OnValidSubmit="UpdateUser">

<div class="form-group">
<label for="username">Username</label>
<InputText id="username" @bind-Value="User.UserName"
class="form-control-plaintext" />
</div>

<div class="form-group">
<label for="email">Email</label>
<InputText id="email" @bind-Value="User.Email" class="form-
control-plaintext" />
</div>

<div class="form-group">
<label for="roles">Roles</label>
@foreach (var role in Roles)
{
<div class="form-check">
<input type="checkbox" class="form-check-input"
id="@($"role{role.Id}")" checked="@User.Roles.Contains(role.Name)"
@onchange="(args) => ToggleSelectedRole(role.Name)" />
<label class="form-check-label"
for="@($"role{role.Id}")">
@role.Name
</label>
</div>
}
</div>

<button type="submit" class="btn btn-primary">Save</button>


</EditForm>
</div>
</div>
}

<div>
<a href="/admin/users">Back to List</a>
</div>
using FlexibleAuth.Client.Services;
using FlexibleAuth.Shared;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Logging.Abstractions;

namespace FlexibleAuth.Client.Pages.Admin.Users;

public partial class Edit


{
[Parameter]
public string UserId { get; set; } = null!;

[Inject]
public IUsersClient UsersClient { get; set; } = null!;

[Inject]
public IRolesClient RolesClient { get; set; } = null!;

[Inject]
public NavigationManager Navigation { get; set; } = null!;

public UserDto User { get; set; } = new();

public ICollection<RoleDto> Roles { get; set; } = new List<RoleDto>();

protected override async Task OnParametersSetAsync()


{
Roles = await RolesClient.GetRolesAsync();

User = await UsersClient.GetUserAsync(UserId);


}

public void ToggleSelectedRole(string roleName)


{
if (User.Roles.Contains(roleName))
{
User.Roles.Remove(roleName);
}
else
{
User.Roles.Add(roleName);
}

StateHasChanged();
}

public async Task UpdateUser()


{
await UsersClient.PutUserAsync(User.Id, User);

Navigation.NavigateTo("/admin/users");
}
}

@page "/admin/users"
@attribute [Authorize(Permissions.ViewUsers | Permissions.ManageUsers)]

<PageTitle>Users</PageTitle>

<h1>Users</h1>

<p>This is a description.</p>

<table class="table table-striped table-hover w-75">


<thead>
<tr>
<th>Username</th>
<th>Email</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var user in Users)
{
<tr>
<td>@user.UserName</td>
<td>@user.Email</td>
<td>
<FlexibleAuthorizeView
Permissions="@Permissions.ManageUsers">
<a href="/admin/users/@user.Id">Edit</a>
</FlexibleAuthorizeView>
</td>
</tr>
}
</tbody>
</table>
using FlexibleAuth.Client.Services;
using FlexibleAuth.Shared;
using Microsoft.AspNetCore.Components;

namespace FlexibleAuth.Client.Pages.Admin.Users;

public partial class Index


{
[Inject] public IUsersClient UsersClient { get; set; } = null!;

public ICollection<UserDto> Users { get; set; } = new List<UserDto>();

protected override async Task OnInitializedAsync()


{
Users = await UsersClient.GetUsersAsync();
}
}

@page "/authentication/{action}"
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<RemoteAuthenticatorView Action="@Action" />

@code{
[Parameter] public string? Action { get; set; }
}

@page "/claims"
@attribute [Authorize]

<PageTitle>Claims</PageTitle>
<h1>Claims</h1>

<p>This component displays available claims.</p>

<AuthorizeView>
<ul>
@foreach (var claim in context.User.Claims)
{
<li><b>@claim.Type</b>: @claim.Value</li>
}
</ul>
</AuthorizeView>
@page "/counter"
@attribute [Authorize(Permissions.Counter)]

<PageTitle>Counter</PageTitle>

<h1>Counter</h1>

<p role="status">Current count: @currentCount</p>

<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>

@code {
private int currentCount = 0;

private void IncrementCount()


{
currentCount++;
}
}

@page "/fetchdata"
@attribute [Authorize(Permissions.Forecast)]

@inject HttpClient Http

<PageTitle>Weather forecast</PageTitle>

<h1>Weather forecast</h1>

<p>This component demonstrates fetching data from the server.</p>

@if (forecasts == null)


{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}

@code {
private WeatherForecast[]? forecasts;

protected override async Task OnInitializedAsync()


{
try
{
forecasts = await
Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
}
catch (AccessTokenNotAvailableException exception)
{
exception.Redirect();
}
}
}

@page "/"

<PageTitle>Index</PageTitle>

<h1>Hello, world!</h1>

Welcome to your new app.

<SurveyPrompt Title="How is Blazor working for you?" />

//----------------------
// <auto-generated>
// Generated using the NSwag toolchain v13.18.2.0 (NJsonSchema v10.8.0.0
(Newtonsoft.Json v13.0.0.0)) (http://NSwag.org)
// </auto-generated>
//----------------------

using FlexibleAuth.Shared;
using Microsoft.AspNetCore.Mvc;

#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited


member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended."
#pragma warning disable 114 // Disable "CS0114
'{derivedDto}.RaisePropertyChanged(String)' hides inherited member
'dtoBase.RaisePropertyChanged(String)'. To make the current member override that
implementation, add the override keyword. Otherwise add the new keyword."
#pragma warning disable 472 // Disable "CS0472 The result of the expression is always
'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?'
#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag
in the XML comment for ...
#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible
type or member ..."
#pragma warning disable 8073 // Disable "CS8073 The result of the expression is always
'false' since a value of type 'T' is never equal to 'null' of type 'T?'"
#pragma warning disable 3016 // Disable "CS3016 Arrays as attribute arguments is not CLS-
compliant"
#pragma warning disable 8603 // Disable "CS8603 Possible null reference return"

namespace FlexibleAuth.Client.Services
{
using System = global::System;

[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.18.2.0 (NJsonSchema


v10.8.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial interface IWeatherForecastClient
{
/// <exception cref="ApiException">A server side error occurred.</exception>

System.Threading.Tasks.Task<System.Collections.Generic.ICollection<WeatherForecast>>
GetAsync();

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>

System.Threading.Tasks.Task<System.Collections.Generic.ICollection<WeatherForecast>>
GetAsync(System.Threading.CancellationToken cancellationToken);

}
[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.18.2.0 (NJsonSchema
v10.8.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class WeatherForecastClient : IWeatherForecastClient
{
private System.Net.Http.HttpClient _httpClient;
private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;

public WeatherForecastClient(System.Net.Http.HttpClient httpClient)


{
_httpClient = httpClient;
_settings = new
System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings);
}

private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()


{
var settings = new Newtonsoft.Json.JsonSerializerSettings();
UpdateJsonSerializerSettings(settings);
return settings;
}

protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return


_settings.Value; } }

partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings


settings);

partial void PrepareRequest(System.Net.Http.HttpClient client,


System.Net.Http.HttpRequestMessage request, string url);
partial void PrepareRequest(System.Net.Http.HttpClient client,
System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
partial void ProcessResponse(System.Net.Http.HttpClient client,
System.Net.Http.HttpResponseMessage response);

/// <exception cref="ApiException">A server side error occurred.</exception>


public virtual
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<WeatherForecast>>
GetAsync()
{
return GetAsync(System.Threading.CancellationToken.None);
}

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<WeatherForecast>>
GetAsync(System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append("WeatherForecast");

var client_ = _httpClient;


var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");

request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValu
e.Parse("application/json"));

PrepareRequest(client_, request_, urlBuilder_);

var url_ = urlBuilder_.ToString();


request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);

PrepareRequest(client_, request_, url_);

var response_ = await client_.SendAsync(request_,


System.Net.Http.HttpCompletionOption.ResponseHeadersRead,
cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_
=> h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}

ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;


if (status_ == 200)
{
var objectResponse_ = await
ReadObjectResponseAsync<System.Collections.Generic.ICollection<WeatherForecast>>(res
ponse_, headers_, cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.",
status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
{
var responseData_ = response_.Content == null ? null : await
response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not
expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}

protected struct ObjectResponseResult<T>


{
public ObjectResponseResult(T responseObject, string responseText)
{
this.Object = responseObject;
this.Text = responseText;
}

public T Object { get; }

public string Text { get; }


}

public bool ReadResponseAsString { get; set; }

protected virtual async System.Threading.Tasks.Task<ObjectResponseResult<T>>


ReadObjectResponseAsync<T>(System.Net.Http.HttpResponseMessage response,
System.Collections.Generic.IReadOnlyDictionary<string,
System.Collections.Generic.IEnumerable<string>> headers,
System.Threading.CancellationToken cancellationToken)
{
if (response == null || response.Content == null)
{
return new ObjectResponseResult<T>(default(T), string.Empty);
}

if (ReadResponseAsString)
{
var responseText = await
response.Content.ReadAsStringAsync().ConfigureAwait(false);
try
{
var typedBody =
Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText, JsonSerializerSettings);
return new ObjectResponseResult<T>(typedBody, responseText);
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body string as " +
typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, responseText,
headers, exception);
}
}
else
{
try
{
using (var responseStream = await
response.Content.ReadAsStreamAsync().ConfigureAwait(false))
using (var streamReader = new System.IO.StreamReader(responseStream))
using (var jsonTextReader = new
Newtonsoft.Json.JsonTextReader(streamReader))
{
var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings);
var typedBody = serializer.Deserialize<T>(jsonTextReader);
return new ObjectResponseResult<T>(typedBody, string.Empty);
}
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body stream as " +
typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, string.Empty,
headers, exception);
}
}
}

private string ConvertToString(object value, System.Globalization.CultureInfo


cultureInfo)
{
if (value == null)
{
return "";
}

if (value is System.Enum)
{
var name = System.Enum.GetName(value.GetType(), value);
if (name != null)
{
var field =
System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(
name);
if (field != null)
{
var attribute =
System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field,
typeof(System.Runtime.Serialization.EnumMemberAttribute))
as System.Runtime.Serialization.EnumMemberAttribute;
if (attribute != null)
{
return attribute.Value != null ? attribute.Value : name;
}
}

var converted = System.Convert.ToString(System.Convert.ChangeType(value,


System.Enum.GetUnderlyingType(value.GetType()), cultureInfo));
return converted == null ? string.Empty : converted;
}
}
else if (value is bool)
{
return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant();
}
else if (value is byte[])
{
return System.Convert.ToBase64String((byte[]) value);
}
else if (value.GetType().IsArray)
{
var array = System.Linq.Enumerable.OfType<object>((System.Array) value);
return string.Join(",", System.Linq.Enumerable.Select(array, o =>
ConvertToString(o, cultureInfo)));
}

var result = System.Convert.ToString(value, cultureInfo);


return result == null ? "" : result;
}
}

[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.18.2.0 (NJsonSchema


v10.8.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial interface IAccessControlClient
{
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<AccessControlVm> GetConfigurationAsync();

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<AccessControlVm>
GetConfigurationAsync(System.Threading.CancellationToken cancellationToken);

/// <exception cref="ApiException">A server side error occurred.</exception>


System.Threading.Tasks.Task UpdateConfigurationAsync(RoleDto updatedRole);

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task UpdateConfigurationAsync(RoleDto updatedRole,
System.Threading.CancellationToken cancellationToken);

[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.18.2.0 (NJsonSchema


v10.8.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class AccessControlClient : IAccessControlClient
{
private System.Net.Http.HttpClient _httpClient;
private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;

public AccessControlClient(System.Net.Http.HttpClient httpClient)


{
_httpClient = httpClient;
_settings = new
System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings);
}
private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()
{
var settings = new Newtonsoft.Json.JsonSerializerSettings();
UpdateJsonSerializerSettings(settings);
return settings;
}

protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return


_settings.Value; } }

partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings


settings);

partial void PrepareRequest(System.Net.Http.HttpClient client,


System.Net.Http.HttpRequestMessage request, string url);
partial void PrepareRequest(System.Net.Http.HttpClient client,
System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
partial void ProcessResponse(System.Net.Http.HttpClient client,
System.Net.Http.HttpResponseMessage response);

/// <exception cref="ApiException">A server side error occurred.</exception>


public virtual System.Threading.Tasks.Task<AccessControlVm> GetConfigurationAsync()
{
return GetConfigurationAsync(System.Threading.CancellationToken.None);
}

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task<AccessControlVm>
GetConfigurationAsync(System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append("api/Admin/AccessControl");

var client_ = _httpClient;


var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");

request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValu
e.Parse("application/json"));
PrepareRequest(client_, request_, urlBuilder_);

var url_ = urlBuilder_.ToString();


request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);

PrepareRequest(client_, request_, url_);

var response_ = await client_.SendAsync(request_,


System.Net.Http.HttpCompletionOption.ResponseHeadersRead,
cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_
=> h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}

ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;


if (status_ == 200)
{
var objectResponse_ = await
ReadObjectResponseAsync<AccessControlVm>(response_, headers_,
cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.",
status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
{
var responseData_ = response_.Content == null ? null : await
response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not
expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}

/// <exception cref="ApiException">A server side error occurred.</exception>


public virtual System.Threading.Tasks.Task UpdateConfigurationAsync(RoleDto
updatedRole)
{
return UpdateConfigurationAsync(updatedRole,
System.Threading.CancellationToken.None);
}

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task UpdateConfigurationAsync(RoleDto
updatedRole, System.Threading.CancellationToken cancellationToken)
{
if (updatedRole == null)
throw new System.ArgumentNullException("updatedRole");

var urlBuilder_ = new System.Text.StringBuilder();


urlBuilder_.Append("api/Admin/AccessControl");

var client_ = _httpClient;


var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(updatedRole,
_settings.Value);
var content_ = new System.Net.Http.StringContent(json_);
content_.Headers.ContentType =
System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
request_.Content = content_;
request_.Method = new System.Net.Http.HttpMethod("PUT");

PrepareRequest(client_, request_, urlBuilder_);


var url_ = urlBuilder_.ToString();
request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);

PrepareRequest(client_, request_, url_);

var response_ = await client_.SendAsync(request_,


System.Net.Http.HttpCompletionOption.ResponseHeadersRead,
cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_
=> h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}

ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;


if (status_ == 204)
{
return;
}
else
{
var responseData_ = response_.Content == null ? null : await
response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not
expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
protected struct ObjectResponseResult<T>
{
public ObjectResponseResult(T responseObject, string responseText)
{
this.Object = responseObject;
this.Text = responseText;
}

public T Object { get; }

public string Text { get; }


}

public bool ReadResponseAsString { get; set; }

protected virtual async System.Threading.Tasks.Task<ObjectResponseResult<T>>


ReadObjectResponseAsync<T>(System.Net.Http.HttpResponseMessage response,
System.Collections.Generic.IReadOnlyDictionary<string,
System.Collections.Generic.IEnumerable<string>> headers,
System.Threading.CancellationToken cancellationToken)
{
if (response == null || response.Content == null)
{
return new ObjectResponseResult<T>(default(T), string.Empty);
}

if (ReadResponseAsString)
{
var responseText = await
response.Content.ReadAsStringAsync().ConfigureAwait(false);
try
{
var typedBody =
Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText, JsonSerializerSettings);
return new ObjectResponseResult<T>(typedBody, responseText);
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body string as " +
typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, responseText,
headers, exception);
}
}
else
{
try
{
using (var responseStream = await
response.Content.ReadAsStreamAsync().ConfigureAwait(false))
using (var streamReader = new System.IO.StreamReader(responseStream))
using (var jsonTextReader = new
Newtonsoft.Json.JsonTextReader(streamReader))
{
var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings);
var typedBody = serializer.Deserialize<T>(jsonTextReader);
return new ObjectResponseResult<T>(typedBody, string.Empty);
}
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body stream as " +
typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, string.Empty,
headers, exception);
}
}
}

private string ConvertToString(object value, System.Globalization.CultureInfo


cultureInfo)
{
if (value == null)
{
return "";
}

if (value is System.Enum)
{
var name = System.Enum.GetName(value.GetType(), value);
if (name != null)
{
var field =
System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(
name);
if (field != null)
{
var attribute =
System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field,
typeof(System.Runtime.Serialization.EnumMemberAttribute))
as System.Runtime.Serialization.EnumMemberAttribute;
if (attribute != null)
{
return attribute.Value != null ? attribute.Value : name;
}
}

var converted = System.Convert.ToString(System.Convert.ChangeType(value,


System.Enum.GetUnderlyingType(value.GetType()), cultureInfo));
return converted == null ? string.Empty : converted;
}
}
else if (value is bool)
{
return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant();
}
else if (value is byte[])
{
return System.Convert.ToBase64String((byte[]) value);
}
else if (value.GetType().IsArray)
{
var array = System.Linq.Enumerable.OfType<object>((System.Array) value);
return string.Join(",", System.Linq.Enumerable.Select(array, o =>
ConvertToString(o, cultureInfo)));
}

var result = System.Convert.ToString(value, cultureInfo);


return result == null ? "" : result;
}
}

[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.18.2.0 (NJsonSchema


v10.8.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial interface IRolesClient
{
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<RoleDto>>
GetRolesAsync();

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<RoleDto>>
GetRolesAsync(System.Threading.CancellationToken cancellationToken);

/// <exception cref="ApiException">A server side error occurred.</exception>


System.Threading.Tasks.Task<RoleDto> PostRoleAsync(RoleDto newRole);
/// <param name="cancellationToken">A cancellation token that can be used by other
objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<RoleDto> PostRoleAsync(RoleDto newRole,
System.Threading.CancellationToken cancellationToken);

/// <exception cref="ApiException">A server side error occurred.</exception>


System.Threading.Tasks.Task PutRoleAsync(string id, RoleDto updatedRole);

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task PutRoleAsync(string id, RoleDto updatedRole,
System.Threading.CancellationToken cancellationToken);

/// <exception cref="ApiException">A server side error occurred.</exception>


System.Threading.Tasks.Task DeleteRoleAsync(string id);

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task DeleteRoleAsync(string id,
System.Threading.CancellationToken cancellationToken);

[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.18.2.0 (NJsonSchema


v10.8.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class RolesClient : IRolesClient
{
private System.Net.Http.HttpClient _httpClient;
private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;

public RolesClient(System.Net.Http.HttpClient httpClient)


{
_httpClient = httpClient;
_settings = new
System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings);
}

private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()


{
var settings = new Newtonsoft.Json.JsonSerializerSettings();
UpdateJsonSerializerSettings(settings);
return settings;
}
protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return
_settings.Value; } }

partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings


settings);

partial void PrepareRequest(System.Net.Http.HttpClient client,


System.Net.Http.HttpRequestMessage request, string url);
partial void PrepareRequest(System.Net.Http.HttpClient client,
System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
partial void ProcessResponse(System.Net.Http.HttpClient client,
System.Net.Http.HttpResponseMessage response);

/// <exception cref="ApiException">A server side error occurred.</exception>


public virtual
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<RoleDto>>
GetRolesAsync()
{
return GetRolesAsync(System.Threading.CancellationToken.None);
}

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<RoleDto>>
GetRolesAsync(System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append("api/Admin/Roles");

var client_ = _httpClient;


var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");

request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValu
e.Parse("application/json"));

PrepareRequest(client_, request_, urlBuilder_);

var url_ = urlBuilder_.ToString();


request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);
PrepareRequest(client_, request_, url_);

var response_ = await client_.SendAsync(request_,


System.Net.Http.HttpCompletionOption.ResponseHeadersRead,
cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_
=> h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}

ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;


if (status_ == 200)
{
var objectResponse_ = await
ReadObjectResponseAsync<System.Collections.Generic.ICollection<RoleDto>>(response_,
headers_, cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.",
status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
{
var responseData_ = response_.Content == null ? null : await
response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not
expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}

/// <exception cref="ApiException">A server side error occurred.</exception>


public virtual System.Threading.Tasks.Task<RoleDto> PostRoleAsync(RoleDto newRole)
{
return PostRoleAsync(newRole, System.Threading.CancellationToken.None);
}

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task<RoleDto> PostRoleAsync(RoleDto
newRole, System.Threading.CancellationToken cancellationToken)
{
if (newRole == null)
throw new System.ArgumentNullException("newRole");

var urlBuilder_ = new System.Text.StringBuilder();


urlBuilder_.Append("api/Admin/Roles");

var client_ = _httpClient;


var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(newRole,
_settings.Value);
var content_ = new System.Net.Http.StringContent(json_);
content_.Headers.ContentType =
System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
request_.Content = content_;
request_.Method = new System.Net.Http.HttpMethod("POST");

request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValu
e.Parse("application/json"));

PrepareRequest(client_, request_, urlBuilder_);

var url_ = urlBuilder_.ToString();


request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);

PrepareRequest(client_, request_, url_);


var response_ = await client_.SendAsync(request_,
System.Net.Http.HttpCompletionOption.ResponseHeadersRead,
cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_
=> h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}

ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;


if (status_ == 200)
{
var objectResponse_ = await
ReadObjectResponseAsync<RoleDto>(response_, headers_,
cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.",
status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
{
var responseData_ = response_.Content == null ? null : await
response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not
expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}

/// <exception cref="ApiException">A server side error occurred.</exception>


public virtual System.Threading.Tasks.Task PutRoleAsync(string id, RoleDto
updatedRole)
{
return PutRoleAsync(id, updatedRole, System.Threading.CancellationToken.None);
}

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task PutRoleAsync(string id, RoleDto
updatedRole, System.Threading.CancellationToken cancellationToken)
{
if (updatedRole == null)
throw new System.ArgumentNullException("updatedRole");

var urlBuilder_ = new System.Text.StringBuilder();


urlBuilder_.Append("api/Admin/Roles/{id}");
urlBuilder_.Replace("{id}", System.Uri.EscapeDataString(ConvertToString(id,
System.Globalization.CultureInfo.InvariantCulture)));

var client_ = _httpClient;


var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(updatedRole,
_settings.Value);
var content_ = new System.Net.Http.StringContent(json_);
content_.Headers.ContentType =
System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
request_.Content = content_;
request_.Method = new System.Net.Http.HttpMethod("PUT");

PrepareRequest(client_, request_, urlBuilder_);

var url_ = urlBuilder_.ToString();


request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);

PrepareRequest(client_, request_, url_);


var response_ = await client_.SendAsync(request_,
System.Net.Http.HttpCompletionOption.ResponseHeadersRead,
cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_
=> h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}

ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;


if (status_ == 204)
{
return;
}
else
if (status_ == 400)
{
var objectResponse_ = await
ReadObjectResponseAsync<ProblemDetails>(response_, headers_,
cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.",
status_, objectResponse_.Text, headers_, null);
}
throw new ApiException<ProblemDetails>("A server side error occurred.",
status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
}
else
{
var responseData_ = response_.Content == null ? null : await
response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not
expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}

/// <exception cref="ApiException">A server side error occurred.</exception>


public virtual System.Threading.Tasks.Task DeleteRoleAsync(string id)
{
return DeleteRoleAsync(id, System.Threading.CancellationToken.None);
}

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task DeleteRoleAsync(string id,
System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append("api/Admin/Roles/{id}");
urlBuilder_.Replace("{id}", System.Uri.EscapeDataString(ConvertToString(id,
System.Globalization.CultureInfo.InvariantCulture)));

var client_ = _httpClient;


var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("DELETE");

PrepareRequest(client_, request_, urlBuilder_);

var url_ = urlBuilder_.ToString();


request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);

PrepareRequest(client_, request_, url_);

var response_ = await client_.SendAsync(request_,


System.Net.Http.HttpCompletionOption.ResponseHeadersRead,
cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_
=> h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}

ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;


if (status_ == 204)
{
return;
}
else
if (status_ == 404)
{
var objectResponse_ = await
ReadObjectResponseAsync<ProblemDetails>(response_, headers_,
cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.",
status_, objectResponse_.Text, headers_, null);
}
throw new ApiException<ProblemDetails>("A server side error occurred.",
status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
}
else
{
var responseData_ = response_.Content == null ? null : await
response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not
expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}

protected struct ObjectResponseResult<T>


{
public ObjectResponseResult(T responseObject, string responseText)
{
this.Object = responseObject;
this.Text = responseText;
}

public T Object { get; }

public string Text { get; }


}

public bool ReadResponseAsString { get; set; }

protected virtual async System.Threading.Tasks.Task<ObjectResponseResult<T>>


ReadObjectResponseAsync<T>(System.Net.Http.HttpResponseMessage response,
System.Collections.Generic.IReadOnlyDictionary<string,
System.Collections.Generic.IEnumerable<string>> headers,
System.Threading.CancellationToken cancellationToken)
{
if (response == null || response.Content == null)
{
return new ObjectResponseResult<T>(default(T), string.Empty);
}

if (ReadResponseAsString)
{
var responseText = await
response.Content.ReadAsStringAsync().ConfigureAwait(false);
try
{
var typedBody =
Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText, JsonSerializerSettings);
return new ObjectResponseResult<T>(typedBody, responseText);
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body string as " +
typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, responseText,
headers, exception);
}
}
else
{
try
{
using (var responseStream = await
response.Content.ReadAsStreamAsync().ConfigureAwait(false))
using (var streamReader = new System.IO.StreamReader(responseStream))
using (var jsonTextReader = new
Newtonsoft.Json.JsonTextReader(streamReader))
{
var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings);
var typedBody = serializer.Deserialize<T>(jsonTextReader);
return new ObjectResponseResult<T>(typedBody, string.Empty);
}
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body stream as " +
typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, string.Empty,
headers, exception);
}
}
}

private string ConvertToString(object value, System.Globalization.CultureInfo


cultureInfo)
{
if (value == null)
{
return "";
}

if (value is System.Enum)
{
var name = System.Enum.GetName(value.GetType(), value);
if (name != null)
{
var field =
System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(
name);
if (field != null)
{
var attribute =
System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field,
typeof(System.Runtime.Serialization.EnumMemberAttribute))
as System.Runtime.Serialization.EnumMemberAttribute;
if (attribute != null)
{
return attribute.Value != null ? attribute.Value : name;
}
}

var converted = System.Convert.ToString(System.Convert.ChangeType(value,


System.Enum.GetUnderlyingType(value.GetType()), cultureInfo));
return converted == null ? string.Empty : converted;
}
}
else if (value is bool)
{
return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant();
}
else if (value is byte[])
{
return System.Convert.ToBase64String((byte[]) value);
}
else if (value.GetType().IsArray)
{
var array = System.Linq.Enumerable.OfType<object>((System.Array) value);
return string.Join(",", System.Linq.Enumerable.Select(array, o =>
ConvertToString(o, cultureInfo)));
}

var result = System.Convert.ToString(value, cultureInfo);


return result == null ? "" : result;
}
}

[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.18.2.0 (NJsonSchema


v10.8.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial interface IUsersClient
{
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<UserDto>>
GetUsersAsync();

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<UserDto>>
GetUsersAsync(System.Threading.CancellationToken cancellationToken);

/// <exception cref="ApiException">A server side error occurred.</exception>


System.Threading.Tasks.Task<UserDto> GetUserAsync(string id);

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task<UserDto> GetUserAsync(string id,
System.Threading.CancellationToken cancellationToken);

/// <exception cref="ApiException">A server side error occurred.</exception>


System.Threading.Tasks.Task PutUserAsync(string id, UserDto updatedUser);

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
System.Threading.Tasks.Task PutUserAsync(string id, UserDto updatedUser,
System.Threading.CancellationToken cancellationToken);

[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.18.2.0 (NJsonSchema


v10.8.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class UsersClient : IUsersClient
{
private System.Net.Http.HttpClient _httpClient;
private System.Lazy<Newtonsoft.Json.JsonSerializerSettings> _settings;

public UsersClient(System.Net.Http.HttpClient httpClient)


{
_httpClient = httpClient;
_settings = new
System.Lazy<Newtonsoft.Json.JsonSerializerSettings>(CreateSerializerSettings);
}

private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings()


{
var settings = new Newtonsoft.Json.JsonSerializerSettings();
UpdateJsonSerializerSettings(settings);
return settings;
}

protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return


_settings.Value; } }
partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings
settings);

partial void PrepareRequest(System.Net.Http.HttpClient client,


System.Net.Http.HttpRequestMessage request, string url);
partial void PrepareRequest(System.Net.Http.HttpClient client,
System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder);
partial void ProcessResponse(System.Net.Http.HttpClient client,
System.Net.Http.HttpResponseMessage response);

/// <exception cref="ApiException">A server side error occurred.</exception>


public virtual
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<UserDto>>
GetUsersAsync()
{
return GetUsersAsync(System.Threading.CancellationToken.None);
}

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<UserDto>>
GetUsersAsync(System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append("api/Admin/Users");

var client_ = _httpClient;


var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");

request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValu
e.Parse("application/json"));

PrepareRequest(client_, request_, urlBuilder_);

var url_ = urlBuilder_.ToString();


request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);

PrepareRequest(client_, request_, url_);


var response_ = await client_.SendAsync(request_,
System.Net.Http.HttpCompletionOption.ResponseHeadersRead,
cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_
=> h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}

ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;


if (status_ == 200)
{
var objectResponse_ = await
ReadObjectResponseAsync<System.Collections.Generic.ICollection<UserDto>>(response_,
headers_, cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.",
status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
{
var responseData_ = response_.Content == null ? null : await
response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not
expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}

/// <exception cref="ApiException">A server side error occurred.</exception>


public virtual System.Threading.Tasks.Task<UserDto> GetUserAsync(string id)
{
return GetUserAsync(id, System.Threading.CancellationToken.None);
}

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task<UserDto> GetUserAsync(string id,
System.Threading.CancellationToken cancellationToken)
{
var urlBuilder_ = new System.Text.StringBuilder();
urlBuilder_.Append("api/Admin/Users/{id}");
urlBuilder_.Replace("{id}", System.Uri.EscapeDataString(ConvertToString(id,
System.Globalization.CultureInfo.InvariantCulture)));

var client_ = _httpClient;


var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
request_.Method = new System.Net.Http.HttpMethod("GET");

request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValu
e.Parse("application/json"));

PrepareRequest(client_, request_, urlBuilder_);

var url_ = urlBuilder_.ToString();


request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);

PrepareRequest(client_, request_, url_);

var response_ = await client_.SendAsync(request_,


System.Net.Http.HttpCompletionOption.ResponseHeadersRead,
cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_
=> h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}

ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;


if (status_ == 200)
{
var objectResponse_ = await
ReadObjectResponseAsync<UserDto>(response_, headers_,
cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.",
status_, objectResponse_.Text, headers_, null);
}
return objectResponse_.Object;
}
else
{
var responseData_ = response_.Content == null ? null : await
response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not
expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}

/// <exception cref="ApiException">A server side error occurred.</exception>


public virtual System.Threading.Tasks.Task PutUserAsync(string id, UserDto
updatedUser)
{
return PutUserAsync(id, updatedUser, System.Threading.CancellationToken.None);
}

/// <param name="cancellationToken">A cancellation token that can be used by other


objects or threads to receive notice of cancellation.</param>
/// <exception cref="ApiException">A server side error occurred.</exception>
public virtual async System.Threading.Tasks.Task PutUserAsync(string id, UserDto
updatedUser, System.Threading.CancellationToken cancellationToken)
{
if (updatedUser == null)
throw new System.ArgumentNullException("updatedUser");

var urlBuilder_ = new System.Text.StringBuilder();


urlBuilder_.Append("api/Admin/Users/{id}");
urlBuilder_.Replace("{id}", System.Uri.EscapeDataString(ConvertToString(id,
System.Globalization.CultureInfo.InvariantCulture)));

var client_ = _httpClient;


var disposeClient_ = false;
try
{
using (var request_ = new System.Net.Http.HttpRequestMessage())
{
var json_ = Newtonsoft.Json.JsonConvert.SerializeObject(updatedUser,
_settings.Value);
var content_ = new System.Net.Http.StringContent(json_);
content_.Headers.ContentType =
System.Net.Http.Headers.MediaTypeHeaderValue.Parse("application/json");
request_.Content = content_;
request_.Method = new System.Net.Http.HttpMethod("PUT");

PrepareRequest(client_, request_, urlBuilder_);

var url_ = urlBuilder_.ToString();


request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute);

PrepareRequest(client_, request_, url_);

var response_ = await client_.SendAsync(request_,


System.Net.Http.HttpCompletionOption.ResponseHeadersRead,
cancellationToken).ConfigureAwait(false);
var disposeResponse_ = true;
try
{
var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_
=> h_.Key, h_ => h_.Value);
if (response_.Content != null && response_.Content.Headers != null)
{
foreach (var item_ in response_.Content.Headers)
headers_[item_.Key] = item_.Value;
}

ProcessResponse(client_, response_);

var status_ = (int)response_.StatusCode;


if (status_ == 204)
{
return;
}
else
if (status_ == 400)
{
var objectResponse_ = await
ReadObjectResponseAsync<ProblemDetails>(response_, headers_,
cancellationToken).ConfigureAwait(false);
if (objectResponse_.Object == null)
{
throw new ApiException("Response was null which was not expected.",
status_, objectResponse_.Text, headers_, null);
}
throw new ApiException<ProblemDetails>("A server side error occurred.",
status_, objectResponse_.Text, headers_, objectResponse_.Object, null);
}
else
{
var responseData_ = response_.Content == null ? null : await
response_.Content.ReadAsStringAsync().ConfigureAwait(false);
throw new ApiException("The HTTP status code of the response was not
expected (" + status_ + ").", status_, responseData_, headers_, null);
}
}
finally
{
if (disposeResponse_)
response_.Dispose();
}
}
}
finally
{
if (disposeClient_)
client_.Dispose();
}
}
protected struct ObjectResponseResult<T>
{
public ObjectResponseResult(T responseObject, string responseText)
{
this.Object = responseObject;
this.Text = responseText;
}

public T Object { get; }

public string Text { get; }


}

public bool ReadResponseAsString { get; set; }

protected virtual async System.Threading.Tasks.Task<ObjectResponseResult<T>>


ReadObjectResponseAsync<T>(System.Net.Http.HttpResponseMessage response,
System.Collections.Generic.IReadOnlyDictionary<string,
System.Collections.Generic.IEnumerable<string>> headers,
System.Threading.CancellationToken cancellationToken)
{
if (response == null || response.Content == null)
{
return new ObjectResponseResult<T>(default(T), string.Empty);
}

if (ReadResponseAsString)
{
var responseText = await
response.Content.ReadAsStringAsync().ConfigureAwait(false);
try
{
var typedBody =
Newtonsoft.Json.JsonConvert.DeserializeObject<T>(responseText, JsonSerializerSettings);
return new ObjectResponseResult<T>(typedBody, responseText);
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body string as " +
typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, responseText,
headers, exception);
}
}
else
{
try
{
using (var responseStream = await
response.Content.ReadAsStreamAsync().ConfigureAwait(false))
using (var streamReader = new System.IO.StreamReader(responseStream))
using (var jsonTextReader = new
Newtonsoft.Json.JsonTextReader(streamReader))
{
var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings);
var typedBody = serializer.Deserialize<T>(jsonTextReader);
return new ObjectResponseResult<T>(typedBody, string.Empty);
}
}
catch (Newtonsoft.Json.JsonException exception)
{
var message = "Could not deserialize the response body stream as " +
typeof(T).FullName + ".";
throw new ApiException(message, (int)response.StatusCode, string.Empty,
headers, exception);
}
}
}

private string ConvertToString(object value, System.Globalization.CultureInfo


cultureInfo)
{
if (value == null)
{
return "";
}

if (value is System.Enum)
{
var name = System.Enum.GetName(value.GetType(), value);
if (name != null)
{
var field =
System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(
name);
if (field != null)
{
var attribute =
System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field,
typeof(System.Runtime.Serialization.EnumMemberAttribute))
as System.Runtime.Serialization.EnumMemberAttribute;
if (attribute != null)
{
return attribute.Value != null ? attribute.Value : name;
}
}

var converted = System.Convert.ToString(System.Convert.ChangeType(value,


System.Enum.GetUnderlyingType(value.GetType()), cultureInfo));
return converted == null ? string.Empty : converted;
}
}
else if (value is bool)
{
return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant();
}
else if (value is byte[])
{
return System.Convert.ToBase64String((byte[]) value);
}
else if (value.GetType().IsArray)
{
var array = System.Linq.Enumerable.OfType<object>((System.Array) value);
return string.Join(",", System.Linq.Enumerable.Select(array, o =>
ConvertToString(o, cultureInfo)));
}

var result = System.Convert.ToString(value, cultureInfo);


return result == null ? "" : result;
}
}

[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.18.2.0 (NJsonSchema


v10.8.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class ApiException : System.Exception
{
public int StatusCode { get; private set; }

public string Response { get; private set; }

public System.Collections.Generic.IReadOnlyDictionary<string,
System.Collections.Generic.IEnumerable<string>> Headers { get; private set; }

public ApiException(string message, int statusCode, string response,


System.Collections.Generic.IReadOnlyDictionary<string,
System.Collections.Generic.IEnumerable<string>> headers, System.Exception
innerException)
: base(message + "\n\nStatus: " + statusCode + "\nResponse: \n" + ((response == null)
? "(null)" : response.Substring(0, response.Length >= 512 ? 512 : response.Length)),
innerException)
{
StatusCode = statusCode;
Response = response;
Headers = headers;
}

public override string ToString()


{
return string.Format("HTTP Response: \n\n{0}\n\n{1}", Response, base.ToString());
}
}

[System.CodeDom.Compiler.GeneratedCode("NSwag", "13.18.2.0 (NJsonSchema


v10.8.0.0 (Newtonsoft.Json v13.0.0.0))")]
public partial class ApiException<TResult> : ApiException
{
public TResult Result { get; private set; }

public ApiException(string message, int statusCode, string response,


System.Collections.Generic.IReadOnlyDictionary<string,
System.Collections.Generic.IEnumerable<string>> headers, TResult result, System.Exception
innerException)
: base(message, statusCode, response, headers, innerException)
{
Result = result;
}
}

#pragma warning restore 1591


#pragma warning restore 1573
#pragma warning restore 472
#pragma warning restore 114
#pragma warning restore 108
#pragma warning restore 3016
#pragma warning restore 8603using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Components;

namespace FlexibleAuth.Client.Shared;

public class FlexibleAuthorizeView :


Microsoft.AspNetCore.Components.Authorization.AuthorizeView
{
[Parameter]
public Permissions Permissions
{
get
{
return string.IsNullOrEmpty(Policy) ? Permissions.None :
PolicyNameHelper.GetPermissionsFrom(Policy);
}
set
{
Policy = PolicyNameHelper.GeneratePolicyNameFor(value);
}
}
}

@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication

@inject NavigationManager Navigation

<AuthorizeView>
<Authorized>
<a href="authentication/profile">Hello, @context.User.Identity?.Name!</a>
<button class="nav-link btn btn-link" @onclick="BeginLogOut">Log
out</button>
</Authorized>
<NotAuthorized>
<a href="authentication/register">Register</a>
<a href="authentication/login">Log in</a>
</NotAuthorized>
</AuthorizeView>

@code{
private void BeginLogOut()
{
Navigation.NavigateToLogout("authentication/logout");
}
}

@inherits LayoutComponentBase

<div class="page">
<div class="sidebar">
<NavMenu />
</div>

<main>
<div class="top-row px-4 auth">
<LoginDisplay />
<a href="https://docs.microsoft.com/aspnet/"
target="_blank">About</a>
</div>

<article class="content px-4">


@Body
</article>
</main>
</div>

.page {
position: relative;
display: flex;
flex-direction: column;
}

main {
flex: 1;
}

.sidebar {
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
}

.top-row {
background-color: #f7f7f7;
border-bottom: 1px solid #d6d5d5;
justify-content: flex-end;
height: 3.5rem;
display: flex;
align-items: center;
}

.top-row ::deep a, .top-row ::deep .btn-link {


white-space: nowrap;
margin-left: 1.5rem;
text-decoration: none;
}

.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {


text-decoration: underline;
}

.top-row ::deep a:first-child {


overflow: hidden;
text-overflow: ellipsis;
}

@media (max-width: 640.98px) {


.top-row:not(.auth) {
display: none;
}

.top-row.auth {
justify-content: space-between;
}

.top-row ::deep a, .top-row ::deep .btn-link {


margin-left: 0;
}
}

@media (min-width: 641px) {


.page {
flex-direction: row;
}

.sidebar {
width: 250px;
height: 100vh;
position: sticky;
top: 0;
}

.top-row {
position: sticky;
top: 0;
z-index: 1;
}

.top-row.auth ::deep a:first-child {


flex: 1;
text-align: right;
width: 0;
}

.top-row, article {
padding-left: 2rem !important;
padding-right: 1.5rem !important;
}
}

@using FlexibleAuth.Shared.Authorization
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">FlexibleAuth</a>
<button title="Navigation menu" class="navbar-toggler"
@onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</div>
<div class="@NavMenuCssClass" @onclick="ToggleNavMenu">
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="oi oi-home" aria-hidden="true"></span> Home
</NavLink>
</div>
<FlexibleAuthorizeView Permissions="@Permissions.Counter">
<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true"></span> Counter
</NavLink>
</div>
</FlexibleAuthorizeView>
<FlexibleAuthorizeView Permissions="@Permissions.Forecast">
<div class="nav-item px-3">
<NavLink class="nav-link" href="fetchdata">
<span class="oi oi-list-rich" aria-hidden="true"></span>
Fetch data
</NavLink>
</div>
</FlexibleAuthorizeView>
<FlexibleAuthorizeView Permissions="@(Permissions.ViewUsers |
Permissions.ManageUsers)">
<div class="nav-item px-3">
<NavLink class="nav-link" href="/admin/users">
<span class="oi oi-people" aria-hidden="true"></span> Users
</NavLink>
</div>
</FlexibleAuthorizeView>
<AuthorizeView>
<div class="nav-item px-3">
<NavLink class="nav-link" href="claims">
<span class="oi oi-document" aria-hidden="true"></span>
Claims
</NavLink>
</div>
</AuthorizeView>
<FlexibleAuthorizeView Permissions="@(Permissions.ViewRoles |
Permissions.ManageRoles)">
<div class="nav-item px-3">
<NavLink class="nav-link" href="admin/roles">
<span class="oi oi-badge" aria-hidden="true"></span> Roles
</NavLink>
</div>
</FlexibleAuthorizeView>
<FlexibleAuthorizeView Permissions="@(Permissions.ViewAccessControl |
Permissions.ConfigureAccessControl)">
<div class="nav-item px-3">
<NavLink class="nav-link" href="admin/access-control">
<span class="oi oi-lock-locked" aria-hidden="true"></span>
Access Control
</NavLink>
</div>
</FlexibleAuthorizeView>
</nav>
</div>

@code {
private bool collapseNavMenu = true;

private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;

private void ToggleNavMenu()


{
collapseNavMenu = !collapseNavMenu;
}
}

.navbar-toggler {
background-color: rgba(255, 255, 255, 0.1);
}

.top-row {
height: 3.5rem;
background-color: rgba(0,0,0,0.4);
}

.navbar-brand {
font-size: 1.1rem;
}

.oi {
width: 2rem;
font-size: 1.1rem;
vertical-align: text-top;
top: -2px;
}

.nav-item {
font-size: 0.9rem;
padding-bottom: 0.5rem;
}

.nav-item:first-of-type {
padding-top: 1rem;
}

.nav-item:last-of-type {
padding-bottom: 1rem;
}
.nav-item ::deep a {
color: #d7d7d7;
border-radius: 4px;
height: 3rem;
display: flex;
align-items: center;
line-height: 3rem;
}

.nav-item ::deep a.active {


background-color: rgba(255,255,255,0.25);
color: white;
}

.nav-item ::deep a:hover {


background-color: rgba(255,255,255,0.1);
color: white;
}

@media (min-width: 641px) {


.navbar-toggler {
display: none;
}

.collapse {
/* Never collapse the sidebar for wide screens */
display: block;
}
}

@inject NavigationManager Navigation

@code {
protected override void OnInitialized()
{

Navigation.NavigateTo($"authentication/login?returnUrl={Uri.EscapeDataString(Navi
gation.Uri)}");
}
}
<div class="alert alert-secondary mt-4">
<span class="oi oi-pencil me-2" aria-hidden="true"></span>
<strong>@Title</strong>

<span class="text-nowrap">
Please take our
<a target="_blank" class="font-weight-bold link-dark"
href="https://go.microsoft.com/fwlink/?linkid=2148851">brief survey</a>
</span>
and tell us what you think.
</div>

@code {
// Demonstrates how a parent component can supply parameters
[Parameter]
public string? Title { get; set; }
}

using FlexibleAuth.Client;
using FlexibleAuth.Client.Authorization;
using FlexibleAuth.Client.Services;
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;

var builder = WebAssemblyHostBuilder.CreateDefault(args);


builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");

builder.Services.AddHttpClient("FlexibleAuth.ServerAPI", client =>


client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress))
.AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

// Supply HttpClient instances that include access tokens when making requests to
the server project
builder.Services.AddScoped(sp =>
sp.GetRequiredService<IHttpClientFactory>().CreateClient("FlexibleAuth.ServerAPI"
));

builder.Services
.AddApiAuthorization()
.AddAccountClaimsPrincipalFactory<CustomAccountClaimsPrincipalFactory>();

builder.Services.AddSingleton<IAuthorizationHandler,
PermissionAuthorizationHandler>();
builder.Services.AddSingleton<IAuthorizationPolicyProvider,
FlexibleAuthorizationPolicyProvider>();

builder.Services.Scan(scan => scan


.FromAssemblyOf<IAccessControlClient>()
.AddClasses(classes =>
classes.InExactNamespaceOf<IAccessControlClient>())
.AsImplementedInterfaces()
.WithScopedLifetime());

await builder.Build().RunAsync();

You might also like