Skip to content

Commit

Permalink
Added Authentication and Authorization (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
csharpfritz authored Aug 11, 2023
1 parent f5a2ee9 commit 86cd619
Show file tree
Hide file tree
Showing 55 changed files with 2,729 additions and 100 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore

# User database in SQLite
TagzApp.Web.db

# User-specific files
*.rsuser
*.suo
Expand Down
3 changes: 2 additions & 1 deletion src/TagzApp.Providers.TwitchChat/TwitchChatProvider.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using System.Collections.Concurrent;
using System.Web;

namespace TagzApp.Providers.TwitchChat;

Expand Down Expand Up @@ -62,7 +63,7 @@ private async Task ListenForMessages(IChatClient chatClient = null)
ProfileImageUri = new Uri(profileUrl),
DisplayName = args.DisplayName
},
Text = args.Message,
Text = HttpUtility.HtmlEncode(args.Message),
Type = ContentType.Chat,
Timestamp = args.Timestamp
});
Expand Down
37 changes: 37 additions & 0 deletions src/TagzApp.Web/Areas/Admin/Pages/AssignRole.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
@page
@using TagzApp.Web.Areas.Admin.Pages;
@model TagzApp.Web.Areas.Admin.Pages.AssignRoleModel
@{
ViewData["ActivePage"] = ManageNavPages.Users;
}


<form method="post" class="mt-3">
<div class="form-group mb-3">
<label for="user">User:</label>
<label id="user" name="user">@Model.CurrentUser.Email</label>
</div>

<div class="form-group">
<label for="role">Assigned Roles:</label>
<p>
<select id="role" name="role" multiple class="mb-3">
@foreach (var role in Model.Roles)
{
@if (Model.UserRoles.Contains(role.Name))
{
<option value="@role" selected>@role</option>
}
else
{
<option value="@role">@role</option>
}
}
</select>
</p>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Assign Role</button>
</div>

</form>
68 changes: 68 additions & 0 deletions src/TagzApp.Web/Areas/Admin/Pages/AssignRole.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;

namespace TagzApp.Web.Areas.Admin.Pages;


public class AssignRoleModel : PageModel
{

public string UserId { get; set; } // new property for user id
public IdentityUser? CurrentUser { get; private set; }
public List<string> UserRoles { get; private set; }
public List<IdentityRole> Roles { get; private set; }

private readonly UserManager<IdentityUser> _userManager; // needed to access roles of a user
private readonly RoleManager<IdentityRole> _RoleManager;

public AssignRoleModel(UserManager<IdentityUser> userManager, RoleManager<IdentityRole> roleManager)
{
_userManager = userManager; // assign user manager to the private variable
_RoleManager = roleManager;
}

public async Task OnGet(string userId) // using route parameter
{
UserId = userId; // assign user id to the new property

CurrentUser = await _userManager.FindByIdAsync(userId); // get user by id

var roles = await _userManager.GetRolesAsync(CurrentUser); // get roles assigned to the user

UserRoles = new List<string>(roles); // store in a list

Roles = await _RoleManager.Roles.ToListAsync(); // retrieve all roles in a list

}
public async Task<IActionResult> OnPostAsync(List<string> role, string userId)
{
var user = await _userManager.FindByIdAsync(userId); // get user by id
if (user == null)
{
return NotFound($"Unable to load user with ID '{userId}'.");
}

var userRoles = await _userManager.GetRolesAsync(user); // get existing roles for user
var result = await _userManager.RemoveFromRolesAsync(user, userRoles); // remove existing roles

if (!result.Succeeded)
{
ModelState.AddModelError("Error", "Failed to remove existing role(s)");
return Page();
}

result = await _userManager.AddToRolesAsync(user, role); // assign new roles
if (!result.Succeeded)
{
ModelState.AddModelError("Error", "Failed to assign role(s)");
return Page();
}

return RedirectToPage(new { userId = userId });
}



}
9 changes: 9 additions & 0 deletions src/TagzApp.Web/Areas/Admin/Pages/Index.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@page
@using TagzApp.Web.Areas.Admin.Pages;
@model TagzApp.Web.Areas.Admin.Pages.IndexModel
@{
ViewData["ActivePage"] = ManageNavPages.Index;
}


This is the first Admin page
12 changes: 12 additions & 0 deletions src/TagzApp.Web/Areas/Admin/Pages/Index.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace TagzApp.Web.Areas.Admin.Pages
{
public class IndexModel : PageModel
{
public void OnGet()
{
}
}
}
32 changes: 32 additions & 0 deletions src/TagzApp.Web/Areas/Admin/Pages/ManageNavPages.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
#nullable disable

using System;
using Microsoft.AspNetCore.Mvc.Rendering;

namespace TagzApp.Web.Areas.Admin.Pages
{
/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static class ManageNavPages
{

public static string Index => "Index";

public static string Users => "Users";

/// <summary>
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
/// directly from your code. This API may change or be removed in future releases.
/// </summary>
public static string PageNavClass(ViewContext viewContext, string page)
{
var activePage = viewContext.ViewData["ActivePage"] as string
?? System.IO.Path.GetFileNameWithoutExtension(viewContext.ActionDescriptor.DisplayName);
return string.Equals(activePage, page, StringComparison.OrdinalIgnoreCase) ? "active" : null;
}
}
}
28 changes: 28 additions & 0 deletions src/TagzApp.Web/Areas/Admin/Pages/Shared/_Layout.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
@{
if (ViewData.TryGetValue("ParentLayout", out var parentLayout) && parentLayout != null)
{
Layout = parentLayout.ToString();
}
else
{
Layout = "/Pages/Shared/_Layout.cshtml";
}
}

<h1>System Administration</h1>

<div>
<hr />
<div class="row">
<div class="col-md-3">
<partial name="_ManageNav" />
</div>
<div class="col-md-9">
@RenderBody()
</div>
</div>
</div>

@section Scripts {
@RenderSection("Scripts", required: false)
}
6 changes: 6 additions & 0 deletions src/TagzApp.Web/Areas/Admin/Pages/Shared/_ManageNav.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
@using TagzApp.Web.Areas.Admin.Pages;

<ul class="nav nav-pills flex-column">
<li class="nav-item"><a class="nav-link @ManageNavPages.PageNavClass(ViewContext, ManageNavPages.Index)" id="index" asp-page="./Index">Home</a></li>
<li class="nav-item"><a class="nav-link @ManageNavPages.PageNavClass(ViewContext, ManageNavPages.Users)" id="index" asp-page="./Users">Users</a></li>
</ul>
23 changes: 23 additions & 0 deletions src/TagzApp.Web/Areas/Admin/Pages/Users.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@page
@using TagzApp.Web.Areas.Admin.Pages;
@model TagzApp.Web.Areas.Admin.Pages.UsersModel
@{
ViewData["ActivePage"] = ManageNavPages.Users;
}

<h1>User Roles Management</h1>

<table>
<tr>
@* <th>User ID</th>
*@ <th>User Email</th>
<th>Action</th>
</tr>
@foreach (var user in Model.Users)
{
<tr>
<td>@user.Email</td>
<td><a href="@Url.Page("AssignRole", new { userId = user.Id })">Assign Roles</a></td>
</tr>
}
</table>
24 changes: 24 additions & 0 deletions src/TagzApp.Web/Areas/Admin/Pages/Users.cshtml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using System.Security;

namespace TagzApp.Web.Areas.Admin.Pages;

public class UsersModel : PageModel
{
private readonly UserManager<IdentityUser> _UserManager;

public UsersModel(UserManager<IdentityUser> userManager)
{
_UserManager = userManager;
}

public List<IdentityUser> Users { get; set; }

public void OnGet()
{
Users = _UserManager.Users.ToList();
}
}
3 changes: 3 additions & 0 deletions src/TagzApp.Web/Areas/Admin/Pages/_ViewImports.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@using TagzApp.Web
@namespace TagzApp.Web.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
3 changes: 3 additions & 0 deletions src/TagzApp.Web/Areas/Admin/Pages/_ViewStart.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@{
Layout = "_Layout";
}
22 changes: 22 additions & 0 deletions src/TagzApp.Web/Areas/Identity/Data/SecurityContext.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace TagzApp.Web.Data;

public class SecurityContext : IdentityDbContext<IdentityUser>
{
public SecurityContext(DbContextOptions<SecurityContext> options)
: base(options)
{
}

protected override void OnModelCreating(ModelBuilder builder)
{

base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
33 changes: 33 additions & 0 deletions src/TagzApp.Web/Areas/Identity/Pages/Account/ExternalLogin.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
@page
@model ExternalLoginModel
@{
ViewData["Title"] = "Register";
}

<h1>@ViewData["Title"]</h1>
<h2 id="external-login-title">Associate your @Model.ProviderDisplayName account.</h2>
<hr />

<p id="external-login-description" class="text-info">
You've successfully authenticated with <strong>@Model.ProviderDisplayName</strong>.
Please enter an email address for this site below and click the Register button to finish
logging in.
</p>

<div class="row">
<div class="col-md-4">
<form asp-page-handler="Confirmation" asp-route-returnUrl="@Model.ReturnUrl" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
<div class="form-floating mb-3">
<input asp-for="Input.Email" class="form-control" autocomplete="email" placeholder="Please enter your email."/>
<label asp-for="Input.Email" class="form-label"></label>
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
<button type="submit" class="w-100 btn btn-lg btn-primary">Register</button>
</form>
</div>
</div>

@section Scripts {
<partial name="_ValidationScriptsPartial" />
}
Loading

0 comments on commit 86cd619

Please sign in to comment.