Skip to content

Commit e262bcd

Browse files
Merge pull request #4 from SubathraKaliamoorthy/main
Updated target framework version
2 parents 23bcbf8 + 812c026 commit e262bcd

File tree

142 files changed

+63840
-2372
lines changed

Some content is hidden

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

142 files changed

+63840
-2372
lines changed

App.razor

Lines changed: 0 additions & 12 deletions
This file was deleted.

Areas/Identity/Pages/Account/LogOut.cshtml

Lines changed: 0 additions & 15 deletions
This file was deleted.

Areas/Identity/Pages/Shared/_LoginPartial.cshtml

Lines changed: 0 additions & 27 deletions
This file was deleted.

Areas/Identity/RevalidatingIdentityAuthenticationStateProvider.cs

Lines changed: 0 additions & 75 deletions
This file was deleted.

Authentication.sln

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,18 @@
1-
<Project Sdk="Microsoft.NET.Sdk.Web">
2-
3-
<PropertyGroup>
4-
<TargetFramework>net7.0</TargetFramework>
5-
<Nullable>enable</Nullable>
6-
<ImplicitUsings>enable</ImplicitUsings>
7-
</PropertyGroup>
8-
9-
<ItemGroup>
10-
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="7.0.15" />
11-
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="7.0.15" />
12-
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="7.0.15" />
13-
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.15" />
14-
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.15">
15-
<PrivateAssets>all</PrivateAssets>
16-
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
17-
</PackageReference>
18-
</ItemGroup>
19-
20-
</Project>
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<UserSecretsId>aspnet-BlazorAppAuthentication-ef272b2a-aadd-4010-961b-8cabcbf74820</UserSecretsId>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="9.0.7" />
12+
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="9.0.7" />
13+
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="9.0.7" />
14+
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="9.0.7" />
15+
<PackageReference Include="Syncfusion.Blazor" Version="*" />
16+
</ItemGroup>
17+
18+
</Project>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
using System.Security.Claims;
2+
using System.Text.Json;
3+
using BlazorAppAuthentication.Components.Account.Pages;
4+
using BlazorAppAuthentication.Components.Account.Pages.Manage;
5+
using BlazorAppAuthentication.Data;
6+
using Microsoft.AspNetCore.Authentication;
7+
using Microsoft.AspNetCore.Components.Authorization;
8+
using Microsoft.AspNetCore.Http.Extensions;
9+
using Microsoft.AspNetCore.Identity;
10+
using Microsoft.AspNetCore.Mvc;
11+
using Microsoft.Extensions.Primitives;
12+
13+
namespace Microsoft.AspNetCore.Routing
14+
{
15+
internal static class IdentityComponentsEndpointRouteBuilderExtensions
16+
{
17+
// These endpoints are required by the Identity Razor components defined in the /Components/Account/Pages directory of this project.
18+
public static IEndpointConventionBuilder MapAdditionalIdentityEndpoints(this IEndpointRouteBuilder endpoints)
19+
{
20+
ArgumentNullException.ThrowIfNull(endpoints);
21+
22+
var accountGroup = endpoints.MapGroup("/Account");
23+
24+
accountGroup.MapPost("/PerformExternalLogin", (
25+
HttpContext context,
26+
[FromServices] SignInManager<ApplicationUser> signInManager,
27+
[FromForm] string provider,
28+
[FromForm] string returnUrl) =>
29+
{
30+
IEnumerable<KeyValuePair<string, StringValues>> query = [
31+
new("ReturnUrl", returnUrl),
32+
new("Action", ExternalLogin.LoginCallbackAction)];
33+
34+
var redirectUrl = UriHelper.BuildRelative(
35+
context.Request.PathBase,
36+
"/Account/ExternalLogin",
37+
QueryString.Create(query));
38+
39+
var properties = signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
40+
return TypedResults.Challenge(properties, [provider]);
41+
});
42+
43+
accountGroup.MapPost("/Logout", async (
44+
ClaimsPrincipal user,
45+
[FromServices] SignInManager<ApplicationUser> signInManager,
46+
[FromForm] string returnUrl) =>
47+
{
48+
await signInManager.SignOutAsync();
49+
return TypedResults.LocalRedirect($"~/{returnUrl}");
50+
});
51+
52+
var manageGroup = accountGroup.MapGroup("/Manage").RequireAuthorization();
53+
54+
manageGroup.MapPost("/LinkExternalLogin", async (
55+
HttpContext context,
56+
[FromServices] SignInManager<ApplicationUser> signInManager,
57+
[FromForm] string provider) =>
58+
{
59+
// Clear the existing external cookie to ensure a clean login process
60+
await context.SignOutAsync(IdentityConstants.ExternalScheme);
61+
62+
var redirectUrl = UriHelper.BuildRelative(
63+
context.Request.PathBase,
64+
"/Account/Manage/ExternalLogins",
65+
QueryString.Create("Action", ExternalLogins.LinkLoginCallbackAction));
66+
67+
var properties = signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, signInManager.UserManager.GetUserId(context.User));
68+
return TypedResults.Challenge(properties, [provider]);
69+
});
70+
71+
var loggerFactory = endpoints.ServiceProvider.GetRequiredService<ILoggerFactory>();
72+
var downloadLogger = loggerFactory.CreateLogger("DownloadPersonalData");
73+
74+
manageGroup.MapPost("/DownloadPersonalData", async (
75+
HttpContext context,
76+
[FromServices] UserManager<ApplicationUser> userManager,
77+
[FromServices] AuthenticationStateProvider authenticationStateProvider) =>
78+
{
79+
var user = await userManager.GetUserAsync(context.User);
80+
if (user is null)
81+
{
82+
return Results.NotFound($"Unable to load user with ID '{userManager.GetUserId(context.User)}'.");
83+
}
84+
85+
var userId = await userManager.GetUserIdAsync(user);
86+
downloadLogger.LogInformation("User with ID '{UserId}' asked for their personal data.", userId);
87+
88+
// Only include personal data for download
89+
var personalData = new Dictionary<string, string>();
90+
var personalDataProps = typeof(ApplicationUser).GetProperties().Where(
91+
prop => Attribute.IsDefined(prop, typeof(PersonalDataAttribute)));
92+
foreach (var p in personalDataProps)
93+
{
94+
personalData.Add(p.Name, p.GetValue(user)?.ToString() ?? "null");
95+
}
96+
97+
var logins = await userManager.GetLoginsAsync(user);
98+
foreach (var l in logins)
99+
{
100+
personalData.Add($"{l.LoginProvider} external login provider key", l.ProviderKey);
101+
}
102+
103+
personalData.Add("Authenticator Key", (await userManager.GetAuthenticatorKeyAsync(user))!);
104+
var fileBytes = JsonSerializer.SerializeToUtf8Bytes(personalData);
105+
106+
context.Response.Headers.TryAdd("Content-Disposition", "attachment; filename=PersonalData.json");
107+
return TypedResults.File(fileBytes, contentType: "application/json", fileDownloadName: "PersonalData.json");
108+
});
109+
110+
return accountGroup;
111+
}
112+
}
113+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using BlazorAppAuthentication.Data;
2+
using Microsoft.AspNetCore.Identity;
3+
using Microsoft.AspNetCore.Identity.UI.Services;
4+
5+
namespace BlazorAppAuthentication.Components.Account
6+
{
7+
// Remove the "else if (EmailSender is IdentityNoOpEmailSender)" block from RegisterConfirmation.razor after updating with a real implementation.
8+
internal sealed class IdentityNoOpEmailSender : IEmailSender<ApplicationUser>
9+
{
10+
private readonly IEmailSender emailSender = new NoOpEmailSender();
11+
12+
public Task SendConfirmationLinkAsync(ApplicationUser user, string email, string confirmationLink) =>
13+
emailSender.SendEmailAsync(email, "Confirm your email", $"Please confirm your account by <a href='{confirmationLink}'>clicking here</a>.");
14+
15+
public Task SendPasswordResetLinkAsync(ApplicationUser user, string email, string resetLink) =>
16+
emailSender.SendEmailAsync(email, "Reset your password", $"Please reset your password by <a href='{resetLink}'>clicking here</a>.");
17+
18+
public Task SendPasswordResetCodeAsync(ApplicationUser user, string email, string resetCode) =>
19+
emailSender.SendEmailAsync(email, "Reset your password", $"Please reset your password using the following code: {resetCode}");
20+
}
21+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System.Diagnostics.CodeAnalysis;
2+
using Microsoft.AspNetCore.Components;
3+
4+
namespace BlazorAppAuthentication.Components.Account
5+
{
6+
internal sealed class IdentityRedirectManager(NavigationManager navigationManager)
7+
{
8+
public const string StatusCookieName = "Identity.StatusMessage";
9+
10+
private static readonly CookieBuilder StatusCookieBuilder = new()
11+
{
12+
SameSite = SameSiteMode.Strict,
13+
HttpOnly = true,
14+
IsEssential = true,
15+
MaxAge = TimeSpan.FromSeconds(5),
16+
};
17+
18+
[DoesNotReturn]
19+
public void RedirectTo(string? uri)
20+
{
21+
uri ??= "";
22+
23+
// Prevent open redirects.
24+
if (!Uri.IsWellFormedUriString(uri, UriKind.Relative))
25+
{
26+
uri = navigationManager.ToBaseRelativePath(uri);
27+
}
28+
29+
// During static rendering, NavigateTo throws a NavigationException which is handled by the framework as a redirect.
30+
// So as long as this is called from a statically rendered Identity component, the InvalidOperationException is never thrown.
31+
navigationManager.NavigateTo(uri);
32+
throw new InvalidOperationException($"{nameof(IdentityRedirectManager)} can only be used during static rendering.");
33+
}
34+
35+
[DoesNotReturn]
36+
public void RedirectTo(string uri, Dictionary<string, object?> queryParameters)
37+
{
38+
var uriWithoutQuery = navigationManager.ToAbsoluteUri(uri).GetLeftPart(UriPartial.Path);
39+
var newUri = navigationManager.GetUriWithQueryParameters(uriWithoutQuery, queryParameters);
40+
RedirectTo(newUri);
41+
}
42+
43+
[DoesNotReturn]
44+
public void RedirectToWithStatus(string uri, string message, HttpContext context)
45+
{
46+
context.Response.Cookies.Append(StatusCookieName, message, StatusCookieBuilder.Build(context));
47+
RedirectTo(uri);
48+
}
49+
50+
private string CurrentPath => navigationManager.ToAbsoluteUri(navigationManager.Uri).GetLeftPart(UriPartial.Path);
51+
52+
[DoesNotReturn]
53+
public void RedirectToCurrentPage() => RedirectTo(CurrentPath);
54+
55+
[DoesNotReturn]
56+
public void RedirectToCurrentPageWithStatus(string message, HttpContext context)
57+
=> RedirectToWithStatus(CurrentPath, message, context);
58+
}
59+
}

0 commit comments

Comments
 (0)