Skip to content

Commit 0798722

Browse files
committed
feat: authn/authz using asp.net identity
1 parent 6cd5e4f commit 0798722

File tree

139 files changed

+8544
-58
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

139 files changed

+8544
-58
lines changed

.tmuxinator.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ windows:
3030
- database:
3131
- printf '\033]2;%s\033\\' 'database'
3232
- cd database
33-
- docker-compose up
33+
- docker compose up
3434
- server:
3535
- printf '\033]2;%s\033\\' 'app'
3636
- cd src/AspNetMartenHtmxVsa

src/.idea/.idea.AspNetMartenHtmxVsa/.idea/indexLayout.xml

-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using Microsoft.AspNetCore.Identity;
2+
3+
namespace AspNetMartenHtmxVsa.Areas.Identity.Data;
4+
5+
// Add profile data for application users by adding properties to the AppUser class
6+
public class AppUser : IdentityUser
7+
{
8+
public string? FirstName { get; set; }
9+
public string? LastName { get; set; }
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
using AspNetMartenHtmxVsa.Areas.Identity.Data;
2+
using Microsoft.AspNetCore.Identity;
3+
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
4+
using Microsoft.EntityFrameworkCore;
5+
6+
namespace AspNetMartenHtmxVsa.Areas.Identity.Data;
7+
8+
public class AppDbContext : IdentityDbContext<AppUser>
9+
{
10+
public AppDbContext(DbContextOptions<AppDbContext> options)
11+
: base(options)
12+
{
13+
}
14+
15+
protected override void OnModelCreating(ModelBuilder builder)
16+
{
17+
base.OnModelCreating(builder);
18+
// Customize the ASP.NET Identity model and override the defaults if needed.
19+
// For example, you can rename the ASP.NET Identity table names and more.
20+
// Add your customizations after calling base.OnModelCreating(builder);
21+
}
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
@page
2+
@model AccessDeniedModel
3+
@{
4+
ViewData["Title"] = "Access denied";
5+
}
6+
7+
<header>
8+
<h1 class="text-danger">@ViewData["Title"]</h1>
9+
<p class="text-danger">You do not have access to this resource.</p>
10+
</header>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
#nullable disable
4+
5+
using Microsoft.AspNetCore.Mvc.RazorPages;
6+
7+
namespace AspNetMartenHtmxVsa.Areas.Identity.Pages.Account
8+
{
9+
/// <summary>
10+
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
11+
/// directly from your code. This API may change or be removed in future releases.
12+
/// </summary>
13+
public class AccessDeniedModel : PageModel
14+
{
15+
/// <summary>
16+
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
17+
/// directly from your code. This API may change or be removed in future releases.
18+
/// </summary>
19+
public void OnGet()
20+
{
21+
}
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@page
2+
@model ConfirmEmailModel
3+
@{
4+
ViewData["Title"] = "Confirm email";
5+
}
6+
7+
<h1>@ViewData["Title"]</h1>
8+
<partial name="~/Areas/Identity/Pages/Account/Manage/_StatusMessage.cshtml" model="Model.StatusMessage" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
#nullable disable
4+
5+
using System;
6+
using System.Linq;
7+
using System.Text;
8+
using System.Threading.Tasks;
9+
using Microsoft.AspNetCore.Authorization;
10+
using AspNetMartenHtmxVsa.Areas.Identity.Data;
11+
using Microsoft.AspNetCore.Identity;
12+
using Microsoft.AspNetCore.Mvc;
13+
using Microsoft.AspNetCore.Mvc.RazorPages;
14+
using Microsoft.AspNetCore.WebUtilities;
15+
16+
namespace AspNetMartenHtmxVsa.Areas.Identity.Pages.Account
17+
{
18+
public class ConfirmEmailModel : PageModel
19+
{
20+
private readonly UserManager<AppUser> _userManager;
21+
22+
public ConfirmEmailModel(UserManager<AppUser> userManager)
23+
{
24+
_userManager = userManager;
25+
}
26+
27+
/// <summary>
28+
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
29+
/// directly from your code. This API may change or be removed in future releases.
30+
/// </summary>
31+
[TempData]
32+
public string StatusMessage { get; set; }
33+
public async Task<IActionResult> OnGetAsync(string userId, string code)
34+
{
35+
if (userId == null || code == null)
36+
{
37+
return RedirectToPage("/Index");
38+
}
39+
40+
var user = await _userManager.FindByIdAsync(userId);
41+
if (user == null)
42+
{
43+
return NotFound($"Unable to load user with ID '{userId}'.");
44+
}
45+
46+
code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
47+
var result = await _userManager.ConfirmEmailAsync(user, code);
48+
StatusMessage = result.Succeeded ? "Thank you for confirming your email." : "Error confirming your email.";
49+
return Page();
50+
}
51+
}
52+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@page
2+
@model ConfirmEmailChangeModel
3+
@{
4+
ViewData["Title"] = "Confirm email change";
5+
}
6+
7+
<h1>@ViewData["Title"]</h1>
8+
<partial name="~/Areas/Identity/Pages/Account/Manage/_StatusMessage.cshtml" model="Model.StatusMessage" />
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
#nullable disable
4+
5+
using System;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using Microsoft.AspNetCore.Authorization;
9+
using AspNetMartenHtmxVsa.Areas.Identity.Data;
10+
using Microsoft.AspNetCore.Identity;
11+
using Microsoft.AspNetCore.Mvc;
12+
using Microsoft.AspNetCore.Mvc.RazorPages;
13+
using Microsoft.AspNetCore.WebUtilities;
14+
15+
namespace AspNetMartenHtmxVsa.Areas.Identity.Pages.Account
16+
{
17+
public class ConfirmEmailChangeModel : PageModel
18+
{
19+
private readonly UserManager<AppUser> _userManager;
20+
private readonly SignInManager<AppUser> _signInManager;
21+
22+
public ConfirmEmailChangeModel(UserManager<AppUser> userManager, SignInManager<AppUser> signInManager)
23+
{
24+
_userManager = userManager;
25+
_signInManager = signInManager;
26+
}
27+
28+
/// <summary>
29+
/// This API supports the ASP.NET Core Identity default UI infrastructure and is not intended to be used
30+
/// directly from your code. This API may change or be removed in future releases.
31+
/// </summary>
32+
[TempData]
33+
public string StatusMessage { get; set; }
34+
35+
public async Task<IActionResult> OnGetAsync(string userId, string email, string code)
36+
{
37+
if (userId == null || email == null || code == null)
38+
{
39+
return RedirectToPage("/Index");
40+
}
41+
42+
var user = await _userManager.FindByIdAsync(userId);
43+
if (user == null)
44+
{
45+
return NotFound($"Unable to load user with ID '{userId}'.");
46+
}
47+
48+
code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code));
49+
var result = await _userManager.ChangeEmailAsync(user, email, code);
50+
if (!result.Succeeded)
51+
{
52+
StatusMessage = "Error changing email.";
53+
return Page();
54+
}
55+
56+
// In our UI email and user name are one and the same, so when we update the email
57+
// we need to update the user name.
58+
var setUserNameResult = await _userManager.SetUserNameAsync(user, email);
59+
if (!setUserNameResult.Succeeded)
60+
{
61+
StatusMessage = "Error changing user name.";
62+
return Page();
63+
}
64+
65+
await _signInManager.RefreshSignInAsync(user);
66+
StatusMessage = "Thank you for confirming your email change.";
67+
return Page();
68+
}
69+
}
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
@page
2+
@model ExternalLoginModel
3+
@{
4+
ViewData["Title"] = "Register";
5+
}
6+
7+
<h1>@ViewData["Title"]</h1>
8+
<h2 id="external-login-title">Associate your @Model.ProviderDisplayName account.</h2>
9+
<hr />
10+
11+
<p id="external-login-description" class="text-info">
12+
You've successfully authenticated with <strong>@Model.ProviderDisplayName</strong>.
13+
Please enter an email address for this site below and click the Register button to finish
14+
logging in.
15+
</p>
16+
17+
<div class="row">
18+
<div class="col-md-4">
19+
<form asp-page-handler="Confirmation" asp-route-returnUrl="@Model.ReturnUrl" method="post">
20+
<div asp-validation-summary="ModelOnly" class="text-danger" role="alert"></div>
21+
<div class="form-floating mb-3">
22+
<input asp-for="Input.Email" class="form-control" autocomplete="email" placeholder="Please enter your email."/>
23+
<label asp-for="Input.Email" class="form-label"></label>
24+
<span asp-validation-for="Input.Email" class="text-danger"></span>
25+
</div>
26+
<button type="submit" class="w-100 btn btn-lg btn-primary">Register</button>
27+
</form>
28+
</div>
29+
</div>
30+
31+
@section Scripts {
32+
<partial name="_ValidationScriptsPartial" />
33+
}

0 commit comments

Comments
 (0)