Using FlexibleAuth
Using FlexibleAuth
Models;
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
using System.Security.Claims;
namespace FlexibleAuth.Server.Authorization;
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;
[HttpGet]
[Authorize(Permissions.ViewAccessControl)]
public async Task<ActionResult<AccessControlVm>> GetConfiguration()
{
var roles = await _roleManager.Roles
.ToListAsync();
[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;
// 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);
// 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();
}
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;
// 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();
}
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();
}
if (user == null)
{
return NotFound();
}
user.UserName = updatedUser.UserName;
user.Email = updatedUser.Email;
await _userManager.UpdateAsync(user);
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;
}
[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"
};
[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; }
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)
{
}
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;
public DbInitializer(
ApplicationDbContext context,
UserManager<User> userManager,
RoleManager<Role> roleManager)
{
_context = context;
_userManager = userManager;
_roleManager = roleManager;
}
// 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
});
await _context.SaveChangesAsync();
}
}
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Identity;
namespace FlexibleAuth.Server.Models;
using FlexibleAuth.Shared;
using Microsoft.AspNetCore.Identity;
namespace FlexibleAuth.Server.Models;
<!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; }
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>();
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;
namespace System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Options;
namespace FlexibleAuth.Shared.Authorization;
public FlexibleAuthorizationPolicyProvider(IOptions<AuthorizationOptions>
options)
: base(options)
{
_options = options.Value;
}
_options.AddPolicy(policyName!, policy);
}
return policy;
}
}
using FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;
namespace FlexibleAuth.Shared.Authorization;
using Microsoft.AspNetCore.Authorization;
using System.Security.Claims;
namespace FlexibleAuth.Shared.Authorization;
if (permissionClaim == null)
{
return Task.CompletedTask;
}
return Task.CompletedTask;
}
}
using Microsoft.AspNetCore.Authorization;
namespace FlexibleAuth.Shared.Authorization;
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;
namespace FlexibleAuth.Shared.Authorization;
return (Permissions)permissionsValue;
}
}
using FlexibleAuth.Shared.Authorization;
namespace FlexibleAuth.Shared;
AvailablePermissions.Add(permission);
}
}
using FlexibleAuth.Shared.Authorization;
namespace FlexibleAuth.Shared;
namespace FlexibleAuth.Shared;
@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;
if (account != null)
{
foreach (var property in account.AdditionalProperties)
{
var key = property.Key;
var value = property.Value;
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>
namespace FlexibleAuth.Client.Pages.Admin.AccessControl;
await AccessControlClient.UpdateConfigurationAsync(role);
}
}
@page "/admin/roles"
@attribute [Authorize(Permissions.ViewRoles)]
<PageTitle>Roles</PageTitle>
<h1>Roles</h1>
<p>This is a description.</p>
namespace FlexibleAuth.Client.Pages.Admin.Roles;
Roles.Add(role);
}
newRoleName = string.Empty;
}
roleToEdit = null;
}
@page "/admin/users/{userId}"
@attribute [Authorize(Permissions.ManageUsers)]
<PageTitle>Users - Edit</PageTitle>
<h1>Edit</h1>
<h2>User</h2>
<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>
<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;
[Inject]
public IUsersClient UsersClient { get; set; } = null!;
[Inject]
public IRolesClient RolesClient { get; set; } = null!;
[Inject]
public NavigationManager Navigation { get; set; } = null!;
StateHasChanged();
}
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>
namespace FlexibleAuth.Client.Pages.Admin.Users;
@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>
<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>
@code {
private int currentCount = 0;
@page "/fetchdata"
@attribute [Authorize(Permissions.Forecast)]
<PageTitle>Weather forecast</PageTitle>
<h1>Weather forecast</h1>
@code {
private WeatherForecast[]? forecasts;
@page "/"
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
//----------------------
// <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;
namespace FlexibleAuth.Client.Services
{
using System = global::System;
System.Threading.Tasks.Task<System.Collections.Generic.ICollection<WeatherForecast>>
GetAsync();
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;
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValu
e.Parse("application/json"));
ProcessResponse(client_, response_);
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);
}
}
}
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;
}
}
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValu
e.Parse("application/json"));
PrepareRequest(client_, request_, urlBuilder_);
ProcessResponse(client_, response_);
ProcessResponse(client_, response_);
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);
}
}
}
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;
}
}
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValu
e.Parse("application/json"));
ProcessResponse(client_, response_);
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValu
e.Parse("application/json"));
ProcessResponse(client_, response_);
ProcessResponse(client_, response_);
ProcessResponse(client_, response_);
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);
}
}
}
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;
}
}
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValu
e.Parse("application/json"));
ProcessResponse(client_, response_);
request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValu
e.Parse("application/json"));
ProcessResponse(client_, response_);
ProcessResponse(client_, response_);
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);
}
}
}
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;
}
}
public System.Collections.Generic.IReadOnlyDictionary<string,
System.Collections.Generic.IEnumerable<string>> Headers { get; private set; }
namespace FlexibleAuth.Client.Shared;
@using Microsoft.AspNetCore.Components.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
<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>
.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.auth {
justify-content: space-between;
}
.sidebar {
width: 250px;
height: 100vh;
position: sticky;
top: 0;
}
.top-row {
position: sticky;
top: 0;
z-index: 1;
}
.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;
.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;
}
.collapse {
/* Never collapse the sidebar for wide screens */
display: block;
}
}
@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;
// 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>();
await builder.Build().RunAsync();