Revize 00bc20f8
Přidáno uživatelem Dominik Chlouba před téměř 4 roky(ů)
Leuze.sln | ||
---|---|---|
35 | 35 |
EndProject |
36 | 36 |
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Leuze.Tests.Core.Domain", "tests\Core\Leuze.Tests.Core.Domain\Leuze.Tests.Core.Domain.csproj", "{8ECAEA01-61F3-402D-B94E-E54FC0C94C8E}" |
37 | 37 |
EndProject |
38 |
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Leuze.Core.Infrastructure.ActiveDirectory", "src\Core\Infrastructure\Leuze.Core.Infrastructure.ActiveDirectory\Leuze.Core.Infrastructure.ActiveDirectory.csproj", "{1407144F-48F6-404E-A890-961B739D030D}" |
|
39 |
EndProject |
|
40 | 38 |
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Leuze.Tests.Core.Infrastructure.ActiveDirectory", "tests\Core\Leuze.Tests.Core.Infrastructure.ActiveDirectory\Leuze.Tests.Core.Infrastructure.ActiveDirectory.csproj", "{C1813611-5FF2-4E70-B7E5-A4E8553F0B66}" |
41 | 39 |
EndProject |
42 | 40 |
Global |
... | ... | |
77 | 75 |
{8ECAEA01-61F3-402D-B94E-E54FC0C94C8E}.Debug|Any CPU.Build.0 = Debug|Any CPU |
78 | 76 |
{8ECAEA01-61F3-402D-B94E-E54FC0C94C8E}.Release|Any CPU.ActiveCfg = Release|Any CPU |
79 | 77 |
{8ECAEA01-61F3-402D-B94E-E54FC0C94C8E}.Release|Any CPU.Build.0 = Release|Any CPU |
80 |
{1407144F-48F6-404E-A890-961B739D030D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
|
81 |
{1407144F-48F6-404E-A890-961B739D030D}.Debug|Any CPU.Build.0 = Debug|Any CPU |
|
82 |
{1407144F-48F6-404E-A890-961B739D030D}.Release|Any CPU.ActiveCfg = Release|Any CPU |
|
83 |
{1407144F-48F6-404E-A890-961B739D030D}.Release|Any CPU.Build.0 = Release|Any CPU |
|
84 | 78 |
{C1813611-5FF2-4E70-B7E5-A4E8553F0B66}.Debug|Any CPU.ActiveCfg = Debug|Any CPU |
85 | 79 |
{C1813611-5FF2-4E70-B7E5-A4E8553F0B66}.Debug|Any CPU.Build.0 = Debug|Any CPU |
86 | 80 |
{C1813611-5FF2-4E70-B7E5-A4E8553F0B66}.Release|Any CPU.ActiveCfg = Release|Any CPU |
... | ... | |
102 | 96 |
{D037B7D3-CA28-4EBD-9E2F-3F3D347950CF} = {C5588326-929D-42B3-912B-9D838373B48E} |
103 | 97 |
{B74BED5E-F175-4A6E-B4AC-8625E0E4E287} = {C5588326-929D-42B3-912B-9D838373B48E} |
104 | 98 |
{8ECAEA01-61F3-402D-B94E-E54FC0C94C8E} = {B74BED5E-F175-4A6E-B4AC-8625E0E4E287} |
105 |
{1407144F-48F6-404E-A890-961B739D030D} = {6A0F1F61-D0EB-4132-B722-5787D7046CC0} |
|
106 | 99 |
{C1813611-5FF2-4E70-B7E5-A4E8553F0B66} = {B74BED5E-F175-4A6E-B4AC-8625E0E4E287} |
107 | 100 |
EndGlobalSection |
108 | 101 |
GlobalSection(ExtensibilityGlobals) = postSolution |
docs/Leuze.Core.Application.Identity.xml | ||
---|---|---|
68 | 68 |
|
69 | 69 |
</summary> |
70 | 70 |
</member> |
71 |
<member name="P:Leuze.Core.Application.Identity.ApplicationRole.UserRoles">
|
|
71 |
<member name="P:Leuze.Core.Application.Identity.ApplicationRole.Users"> |
|
72 | 72 |
<summary> |
73 | 73 |
|
74 | 74 |
</summary> |
... | ... | |
90 | 90 |
|
91 | 91 |
</summary> |
92 | 92 |
</member> |
93 |
<member name="M:Leuze.Core.Application.Identity.ApplicationRole.ChangeName(System.String)"> |
|
94 |
<summary> |
|
95 |
|
|
96 |
</summary> |
|
97 |
<param name="name"></param> |
|
98 |
</member> |
|
93 | 99 |
<member name="T:Leuze.Core.Application.Identity.ApplicationRoleClaim"> |
94 | 100 |
<summary> |
95 | 101 |
|
... | ... | |
105 | 111 |
|
106 | 112 |
</summary> |
107 | 113 |
</member> |
108 |
<member name="M:Leuze.Core.Application.Identity.ApplicationUser.#ctor(System.String,System.String)"> |
|
114 |
<member name="M:Leuze.Core.Application.Identity.ApplicationUser.#ctor(System.String,System.String,System.Boolean)">
|
|
109 | 115 |
<summary> |
110 | 116 |
|
111 | 117 |
</summary> |
112 | 118 |
<param name="userName"></param> |
113 | 119 |
<param name="email"></param> |
120 |
<param name="isAdUser"></param> |
|
114 | 121 |
</member> |
115 |
<member name="P:Leuze.Core.Application.Identity.ApplicationUser.UserRoles"> |
|
122 |
<member name="P:Leuze.Core.Application.Identity.ApplicationUser.IsAdUser"> |
|
123 |
<summary> |
|
124 |
|
|
125 |
</summary> |
|
126 |
</member> |
|
127 |
<member name="P:Leuze.Core.Application.Identity.ApplicationUser.Roles"> |
|
116 | 128 |
<summary> |
117 | 129 |
|
118 | 130 |
</summary> |
... | ... | |
147 | 159 |
|
148 | 160 |
</summary> |
149 | 161 |
</member> |
162 |
<member name="T:Leuze.Core.Application.Identity.IApplicationUserProvider"> |
|
163 |
<summary> |
|
164 |
An application service that provides currently authenticated user from presentation layer such as ASP.NET application or Console App. |
|
165 |
</summary> |
|
166 |
</member> |
|
167 |
<member name="P:Leuze.Core.Application.Identity.IApplicationUserProvider.UserId"> |
|
168 |
<summary> |
|
169 |
The current user identifier. |
|
170 |
</summary> |
|
171 |
</member> |
|
172 |
<member name="P:Leuze.Core.Application.Identity.IApplicationUserProvider.User"> |
|
173 |
<summary> |
|
174 |
The current user ClaimsPrincipal. |
|
175 |
</summary> |
|
176 |
</member> |
|
177 |
<member name="P:Leuze.Core.Application.Identity.IApplicationUserProvider.IsAuthenticated"> |
|
178 |
<summary> |
|
179 |
Checks whether the user is authenticated. |
|
180 |
</summary> |
|
181 |
</member> |
|
150 | 182 |
</members> |
151 | 183 |
</doc> |
src/Core/Application/Leuze.Core.Application.Identity/ApplicationRole.cs | ||
---|---|---|
21 | 21 |
/// <param name="name"></param> |
22 | 22 |
public ApplicationRole(string name) => (Name, NormalizedName) = (name, name.ToUpper()); |
23 | 23 |
|
24 |
private List<ApplicationPermission> _permissions = new List<ApplicationPermission>(); |
|
25 |
|
|
24 | 26 |
/// <summary> |
25 | 27 |
/// |
26 | 28 |
/// </summary> |
27 |
public ICollection<ApplicationPermission> Permissions { get; private set; } = new List<ApplicationPermission>(); |
|
29 |
public IReadOnlyCollection<ApplicationPermission> Permissions => _permissions.AsReadOnly(); |
|
30 |
|
|
31 |
private List<ApplicationUser> _users = new List<ApplicationUser>(); |
|
28 | 32 |
|
29 | 33 |
/// <summary> |
30 | 34 |
/// |
31 | 35 |
/// </summary> |
32 |
public ICollection<ApplicationUserRole> UserRoles { get; private set; } = new List<ApplicationUserRole>();
|
|
36 |
public IReadOnlyCollection<ApplicationUser> Users => _users.AsReadOnly();
|
|
33 | 37 |
|
34 | 38 |
/// <summary> |
35 | 39 |
/// |
36 | 40 |
/// </summary> |
37 | 41 |
/// <param name="permission"></param> |
38 |
public void AssignPermission(ApplicationPermission permission) => Permissions.Add(permission);
|
|
42 |
public void AssignPermission(ApplicationPermission permission) => _permissions.Add(permission);
|
|
39 | 43 |
|
40 | 44 |
/// <summary> |
41 | 45 |
/// |
42 | 46 |
/// </summary> |
43 | 47 |
/// <param name="permission"></param> |
44 |
public void RemovePermission(ApplicationPermission permission) => Permissions.Remove(permission);
|
|
48 |
public void RemovePermission(ApplicationPermission permission) => _permissions.Remove(permission);
|
|
45 | 49 |
|
46 | 50 |
/// <summary> |
47 | 51 |
/// |
48 | 52 |
/// </summary> |
49 |
public void ClearPermissions() => Permissions.Clear(); |
|
53 |
public void ClearPermissions() => _permissions.Clear(); |
|
54 |
|
|
55 |
/// <summary> |
|
56 |
/// |
|
57 |
/// </summary> |
|
58 |
/// <param name="name"></param> |
|
59 |
public void ChangeName(string name) => (Name, NormalizedName) = (name, name.ToUpper()); |
|
50 | 60 |
} |
51 | 61 |
} |
src/Core/Application/Leuze.Core.Application.Identity/ApplicationUser.cs | ||
---|---|---|
20 | 20 |
/// </summary> |
21 | 21 |
/// <param name="userName"></param> |
22 | 22 |
/// <param name="email"></param> |
23 |
public ApplicationUser(string userName, string email) => (UserName, Email) = (userName, email); |
|
23 |
/// <param name="isAdUser"></param> |
|
24 |
public ApplicationUser(string userName, string email, bool isAdUser) |
|
25 |
=> (UserName, Email, IsAdUser) = (userName, email, isAdUser); |
|
24 | 26 |
|
25 | 27 |
/// <summary> |
26 | 28 |
/// |
27 | 29 |
/// </summary> |
28 |
public ICollection<ApplicationUserRole> UserRoles { get; private set; } = new List<ApplicationUserRole>(); |
|
30 |
public bool IsAdUser { get; private set; } |
|
31 |
|
|
32 |
private List<ApplicationRole> _roles = new List<ApplicationRole>(); |
|
33 |
|
|
34 |
/// <summary> |
|
35 |
/// |
|
36 |
/// </summary> |
|
37 |
public IReadOnlyCollection<ApplicationRole> Roles => _roles.AsReadOnly(); |
|
29 | 38 |
|
30 | 39 |
} |
31 | 40 |
} |
src/Core/Application/Leuze.Core.Application.Identity/ApplicationUserRole.cs | ||
---|---|---|
6 | 6 |
/// <summary> |
7 | 7 |
/// |
8 | 8 |
/// </summary> |
9 |
public sealed class ApplicationUserRole : IdentityUserRole<Guid>
|
|
9 |
public class ApplicationUserRole : IdentityUserRole<Guid> |
|
10 | 10 |
{ |
11 | 11 |
/// <summary> |
12 | 12 |
/// |
13 | 13 |
/// </summary> |
14 |
public ApplicationUser User { get; set; } = null!; |
|
14 |
public virtual ApplicationUser User { get; set; } = null!;
|
|
15 | 15 |
|
16 | 16 |
/// <summary> |
17 | 17 |
/// |
18 | 18 |
/// </summary> |
19 |
public ApplicationRole Role { get; set; } = null!; |
|
19 |
public virtual ApplicationRole Role { get; set; } = null!;
|
|
20 | 20 |
|
21 | 21 |
} |
22 | 22 |
} |
src/Core/Application/Leuze.Core.Application.Identity/IApplicationUserProvider.cs | ||
---|---|---|
1 |
using System.Security.Claims; |
|
2 |
|
|
3 |
namespace Leuze.Core.Application.Identity |
|
4 |
{ |
|
5 |
/// <summary> |
|
6 |
/// An application service that provides currently authenticated user from presentation layer such as ASP.NET application or Console App. |
|
7 |
/// </summary> |
|
8 |
public interface IApplicationUserProvider |
|
9 |
{ |
|
10 |
/// <summary> |
|
11 |
/// The current user identifier. |
|
12 |
/// </summary> |
|
13 |
string? UserId { get; } |
|
14 |
|
|
15 |
/// <summary> |
|
16 |
/// The current user ClaimsPrincipal. |
|
17 |
/// </summary> |
|
18 |
public ClaimsPrincipal? User { get; } |
|
19 |
|
|
20 |
/// <summary> |
|
21 |
/// Checks whether the user is authenticated. |
|
22 |
/// </summary> |
|
23 |
bool IsAuthenticated { get; } |
|
24 |
} |
|
25 |
} |
src/Core/Application/Leuze.Core.Application.UI/Leuze.Core.Application.UI.csproj | ||
---|---|---|
23 | 23 |
|
24 | 24 |
<ItemGroup> |
25 | 25 |
<PackageReference Include="BlazorStyled" Version="3.1.0" /> |
26 |
<PackageReference Include="Microsoft.AspNetCore.Authentication.Cookies" Version="2.2.0" /> |
|
26 | 27 |
</ItemGroup> |
27 | 28 |
|
28 | 29 |
<ItemGroup> |
src/Core/Application/Leuze.Core.Application.UI/Pages/Counter.razor | ||
---|---|---|
1 |
@page "/counter" |
|
2 |
|
|
3 |
<h1>Counter</h1> |
|
4 |
|
|
5 |
<p>Current count: @currentCount</p> |
|
6 |
|
|
7 |
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button> |
|
8 |
|
|
9 |
@code { |
|
10 |
private int currentCount = 0; |
|
11 |
|
|
12 |
private void IncrementCount() |
|
13 |
{ |
|
14 |
currentCount++; |
|
15 |
} |
|
16 |
} |
src/Core/Application/Leuze.Core.Application.UI/Pages/Index.razor | ||
---|---|---|
1 | 1 |
@page "/" |
2 | 2 |
@layout MainLayout |
3 |
@attribute [Authorize] |
|
3 | 4 |
|
4 | 5 |
<h1>Hello, world!</h1> |
5 | 6 |
|
src/Core/Application/Leuze.Core.Application.UI/Shared/MainLayout.razor | ||
---|---|---|
1 | 1 |
@inherits LayoutComponentBase |
2 | 2 |
@inject NavigationManager _navManager |
3 |
@inject AuthenticationStateProvider AuthenticationStateProvider |
|
3 | 4 |
<div class="top-row px-4"> |
4 |
<img src="Resources/Icons/logo.svg" alt="logo" style="width:111px;height:28px;"/> |
|
5 |
<img src="Resources/Icons/sign-out.svg" style="width:18px;height:20px;"/> |
|
5 |
<img src="Resources/Icons/logo.svg" alt="logo" style="width:111px;height:28px;" /> |
|
6 |
<div> |
|
7 |
@Name |
|
8 |
<a href="/MicrosoftIdentity/Account/SignOut"> |
|
9 |
<img src="Resources/Icons/sign-out.svg" style="width:18px;height:20px;" /> |
|
10 |
</a> |
|
11 |
</div> |
|
6 | 12 |
</div> |
7 | 13 |
|
8 | 14 |
|
... | ... | |
11 | 17 |
<NavMenu /> |
12 | 18 |
</div> |
13 | 19 |
|
14 |
<div class="main"> |
|
15 |
<div class="content px-4"> |
|
16 |
@Body |
|
17 |
</div> |
|
20 |
<div class="main"> |
|
21 |
<div class="content px-4"> |
|
22 |
@Body |
|
18 | 23 |
</div> |
19 | 24 |
</div> |
25 |
</div> |
|
26 |
|
|
27 |
@code { |
|
20 | 28 |
|
21 |
@code {
|
|
29 |
private string Name { get; set; } = string.Empty;
|
|
22 | 30 |
|
23 |
/*protected override void OnAfterRender(bool firstRender)
|
|
31 |
protected override async Task OnInitializedAsync()
|
|
24 | 32 |
{ |
25 |
base.OnAfterRender(firstRender); |
|
26 |
if (firstRender) _navManager.NavigateTo("account/login"); |
|
27 |
}*/ |
|
33 |
base.OnInitialized(); |
|
34 |
var identity = await AuthenticationStateProvider.GetAuthenticationStateAsync(); |
|
35 |
Name = identity.User.Identity!.Name!; |
|
36 |
} |
|
28 | 37 |
} |
src/Core/Application/Leuze.Core.Application/Authentication/ApplicationUserProvider.cs | ||
---|---|---|
1 |
using Leuze.Core.Application.Identity; |
|
2 |
using Microsoft.AspNetCore.Http; |
|
3 |
using System; |
|
4 |
using System.Collections.Generic; |
|
5 |
using System.Linq; |
|
6 |
using System.Security.Claims; |
|
7 |
using System.Text; |
|
8 |
using System.Threading.Tasks; |
|
9 |
|
|
10 |
namespace Leuze.Core.Application.Authentication |
|
11 |
{ |
|
12 |
/// <inheritdoc /> |
|
13 |
public class ApplicationUserProvider : IApplicationUserProvider |
|
14 |
{ |
|
15 |
/// <summary> |
|
16 |
/// A public constructor with required http context accessor to get user claims. |
|
17 |
/// </summary> |
|
18 |
/// <param name="httpContextAccessor">The HTTP Context accessor.</param> |
|
19 |
public ApplicationUserProvider(IHttpContextAccessor httpContextAccessor) |
|
20 |
{ |
|
21 |
UserId = httpContextAccessor.HttpContext?.User?.FindFirstValue(ClaimTypes.NameIdentifier); |
|
22 |
User = httpContextAccessor.HttpContext?.User; |
|
23 |
IsAuthenticated = UserId != null; |
|
24 |
} |
|
25 |
|
|
26 |
/// <inheritdoc /> |
|
27 |
public string? UserId { get; } |
|
28 |
|
|
29 |
/// <inheritdoc /> |
|
30 |
public ClaimsPrincipal? User { get; } |
|
31 |
|
|
32 |
/// <inheritdoc /> |
|
33 |
public bool IsAuthenticated { get; } |
|
34 |
} |
|
35 |
} |
src/Core/Application/Leuze.Core.Application/Authentication/DomainUserProvider.cs | ||
---|---|---|
1 |
namespace Leuze.Core.Application.Authentication |
|
1 |
using Leuze.Core.Application.Identity; |
|
2 |
using Leuze.Core.Domain.Domains.Users; |
|
3 |
using Leuze.Core.Domain.Domains.Users.Services.Abstractions; |
|
4 |
using Leuze.Core.Domain.Repositories; |
|
5 |
using System; |
|
6 |
using System.Threading.Tasks; |
|
7 |
|
|
8 |
namespace Leuze.Core.Application.Authentication |
|
2 | 9 |
{ |
3 | 10 |
/// <inheritdoc /> |
4 |
public class DomainUserProvider// : IDomainUserProvider
|
|
11 |
public class DomainUserProvider : IDomainUserProvider |
|
5 | 12 |
{ |
6 |
/*private readonly IApplicationUserProvider _userProvider;
|
|
7 |
private readonly IStorage _unitOfWork;
|
|
13 |
private readonly IApplicationUserProvider _userProvider; |
|
14 |
private readonly IDomainUserRepository _domainUserRepository;
|
|
8 | 15 |
|
9 |
public DomainUserProvider(IApplicationUserProvider userProvider, IStorage unitOfWork) |
|
16 |
/// <summary> |
|
17 |
/// |
|
18 |
/// </summary> |
|
19 |
/// <param name="userProvider"></param> |
|
20 |
/// <param name="domainUserRepository"></param> |
|
21 |
public DomainUserProvider(IApplicationUserProvider userProvider, IDomainUserRepository domainUserRepository) |
|
10 | 22 |
{ |
11 | 23 |
_userProvider = userProvider; |
12 |
_unitOfWork = unitOfWork;
|
|
24 |
_domainUserRepository = domainUserRepository;
|
|
13 | 25 |
} |
14 | 26 |
|
15 | 27 |
/// <inheritdoc /> |
... | ... | |
21 | 33 |
if (CurrentUserId is null) |
22 | 34 |
return null; |
23 | 35 |
|
24 |
return null; |
|
25 |
//TODO: Implement |
|
26 |
//return await _unitOfWork.DomainUsers.FindAsync(CurrentUserId); |
|
36 |
return await _domainUserRepository.GetOptionalByIdAsync(CurrentUserId); |
|
37 |
} |
|
38 |
|
|
39 |
/// <inheritdoc /> |
|
40 |
public async Task<DomainUser> GetRequiredCurrentUserAsync() |
|
41 |
{ |
|
42 |
if (CurrentUserId is null) |
|
43 |
throw new UnauthorizedAccessException(); |
|
44 |
|
|
45 |
var user = await _domainUserRepository.GetByIdAsync(CurrentUserId.Value); |
|
46 |
|
|
47 |
if (user is null) |
|
48 |
throw new UnauthorizedAccessException(); |
|
49 |
|
|
50 |
return user; |
|
27 | 51 |
} |
28 | 52 |
|
29 | 53 |
/// <summary> |
... | ... | |
39 | 63 |
return userId; |
40 | 64 |
|
41 | 65 |
return null; |
42 |
}*/
|
|
66 |
} |
|
43 | 67 |
} |
44 | 68 |
} |
src/Core/Application/Leuze.Core.Application/Authentication/IApplicationUserProvider.cs | ||
---|---|---|
1 |
namespace Leuze.Core.Application.Authentication |
|
2 |
{ |
|
3 |
/// <summary> |
|
4 |
/// An application service that provides currently authenticated user from presentation layer such as ASP.NET application or Console App. |
|
5 |
/// </summary> |
|
6 |
public interface IApplicationUserProvider |
|
7 |
{ |
|
8 |
/*/// <summary> |
|
9 |
/// The current user identifier. |
|
10 |
/// </summary> |
|
11 |
string? UserId { get; } |
|
12 |
|
|
13 |
/// <summary> |
|
14 |
/// The current user ClaimsPrincipal. |
|
15 |
/// </summary> |
|
16 |
public ClaimsPrincipal? User { get; } |
|
17 |
|
|
18 |
/// <summary> |
|
19 |
/// Checks whether the user is authenticated. |
|
20 |
/// </summary> |
|
21 |
bool IsAuthenticated { get; }*/ |
|
22 |
} |
|
23 |
} |
src/Core/Application/Leuze.Core.Application/Authorization/PermissionAuthorizationHandler.cs | ||
---|---|---|
1 |
using Leuze.Core.Application.Identity; |
|
2 |
using Microsoft.AspNetCore.Authorization; |
|
3 |
using Microsoft.AspNetCore.Identity; |
|
4 |
using System.Threading.Tasks; |
|
5 |
|
|
6 |
namespace Leuze.Core.Application.Authorization |
|
7 |
{ |
|
8 |
/// <summary> |
|
9 |
/// Permission-based authorization handler. |
|
10 |
/// </summary> |
|
11 |
public class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement> |
|
12 |
{ |
|
13 |
private readonly UserManager<ApplicationUser> _userManager; |
|
14 |
private readonly PermissionManager _permissionManager; |
|
15 |
|
|
16 |
/// <summary> |
|
17 |
/// Handler constructor with required dependencies. |
|
18 |
/// </summary> |
|
19 |
/// <param name="userManager">The user manager.</param> |
|
20 |
/// <param name="permissionManager">The permission manager.</param> |
|
21 |
public PermissionAuthorizationHandler(UserManager<ApplicationUser> userManager, PermissionManager permissionManager) |
|
22 |
=> (_userManager, _permissionManager) = (userManager, permissionManager); |
|
23 |
|
|
24 |
/// <inheritdoc /> |
|
25 |
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement) |
|
26 |
{ |
|
27 |
if (context.User.Identity is null || !context.User.Identity.IsAuthenticated) |
|
28 |
{ |
|
29 |
context.Fail(); |
|
30 |
return; |
|
31 |
} |
|
32 |
|
|
33 |
// Get all the roles the user belongs to and check if any of the roles has the permission required |
|
34 |
// for the authorization to succeed. |
|
35 |
var user = await _userManager.GetUserAsync(context.User); |
|
36 |
if (user is null) |
|
37 |
{ |
|
38 |
context.Fail(); |
|
39 |
return; |
|
40 |
} |
|
41 |
|
|
42 |
var hasPermission = await _permissionManager.HasPermissionAsync(user.Id, requirement.PermissionName); |
|
43 |
if (hasPermission) context.Succeed(requirement); |
|
44 |
else context.Fail(); |
|
45 |
} |
|
46 |
} |
|
47 |
} |
src/Core/Application/Leuze.Core.Application/Authorization/PermissionManager.cs | ||
---|---|---|
1 |
using Leuze.Core.Domain.Repositories; |
|
2 |
using System; |
|
3 |
using System.Threading.Tasks; |
|
4 |
|
|
5 |
namespace Leuze.Core.Application.Authorization |
|
6 |
{ |
|
7 |
/// <summary> |
|
8 |
/// |
|
9 |
/// </summary> |
|
10 |
public class PermissionManager |
|
11 |
{ |
|
12 |
private readonly IUserRepository _userRepository; |
|
13 |
|
|
14 |
/// <summary> |
|
15 |
/// |
|
16 |
/// </summary> |
|
17 |
/// <param name="userRepository"></param> |
|
18 |
public PermissionManager(IUserRepository userRepository) |
|
19 |
=> _userRepository = userRepository; |
|
20 |
|
|
21 |
/// <summary> |
|
22 |
/// |
|
23 |
/// </summary> |
|
24 |
/// <param name="id"></param> |
|
25 |
/// <param name="permission"></param> |
|
26 |
/// <returns></returns> |
|
27 |
public async Task<bool> HasPermissionAsync(Guid id, string permission) |
|
28 |
=> await _userRepository.HasPermissionAsync(id, permission); |
|
29 |
|
|
30 |
} |
|
31 |
} |
src/Core/Application/Leuze.Core.Application/Authorization/PermissionPolicyProvider.cs | ||
---|---|---|
1 |
using Microsoft.AspNetCore.Authorization; |
|
2 |
using Microsoft.Extensions.Options; |
|
3 |
using System; |
|
4 |
using System.Threading.Tasks; |
|
5 |
|
|
6 |
namespace Leuze.Core.Application.Authorization |
|
7 |
{ |
|
8 |
/// <summary> |
|
9 |
/// Authorization policy provider for permission based authorization. |
|
10 |
/// <para> |
|
11 |
/// Provider creates policies dynamically when the permission policies are used. |
|
12 |
/// </para> |
|
13 |
/// </summary> |
|
14 |
public class PermissionPolicyProvider : IAuthorizationPolicyProvider |
|
15 |
{ |
|
16 |
/// <summary> |
|
17 |
/// Fallback authorization policy provider. |
|
18 |
/// </summary> |
|
19 |
public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; } |
|
20 |
|
|
21 |
/// <summary> |
|
22 |
/// Creates an permission policy provider that creates policies dynamically based on permission in the application. |
|
23 |
/// </summary> |
|
24 |
/// <param name="options">Authorization configuration.</param> |
|
25 |
public PermissionPolicyProvider(IOptions<AuthorizationOptions> options) |
|
26 |
=> FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options); |
|
27 |
|
|
28 |
/// <inheritdoc /> |
|
29 |
public Task<AuthorizationPolicy> GetDefaultPolicyAsync() => FallbackPolicyProvider.GetDefaultPolicyAsync(); |
|
30 |
|
|
31 |
/// <inheritdoc /> |
|
32 |
public Task<AuthorizationPolicy?> GetFallbackPolicyAsync() => FallbackPolicyProvider.GetFallbackPolicyAsync(); |
|
33 |
|
|
34 |
/// <inheritdoc /> |
|
35 |
public Task<AuthorizationPolicy?> GetPolicyAsync(string policyName) |
|
36 |
{ |
|
37 |
if (policyName.StartsWith("PRIVILEGE.", StringComparison.OrdinalIgnoreCase)) |
|
38 |
{ |
|
39 |
var policy = new AuthorizationPolicyBuilder(); |
|
40 |
policy.AddRequirements(new PermissionRequirement(policyName.Replace("PRIVILEGE.", ""))); |
|
41 |
return Task.FromResult(policy.Build())!; |
|
42 |
} |
|
43 |
|
|
44 |
// Policy is not for permissions, try the default provider. |
|
45 |
return FallbackPolicyProvider.GetPolicyAsync(policyName); |
|
46 |
} |
|
47 |
} |
|
48 |
} |
src/Core/Application/Leuze.Core.Application/Authorization/PermissionRequirement.cs | ||
---|---|---|
1 |
using Microsoft.AspNetCore.Authorization; |
|
2 |
|
|
3 |
namespace Leuze.Core.Application.Authorization |
|
4 |
{ |
|
5 |
/// <summary> |
|
6 |
/// Authorization requirement for permissions in the system. |
|
7 |
/// </summary> |
|
8 |
public class PermissionRequirement : IAuthorizationRequirement |
|
9 |
{ |
|
10 |
/// <summary> |
|
11 |
/// Initializes permission requirement with the permission name. |
|
12 |
/// </summary> |
|
13 |
/// <param name="permissionName">The permission name.</param> |
|
14 |
public PermissionRequirement(string permissionName) |
|
15 |
=> PermissionName = permissionName; |
|
16 |
|
|
17 |
/// <summary> |
|
18 |
/// The permission name. |
|
19 |
/// </summary> |
|
20 |
public string PermissionName { get; private set; } |
|
21 |
} |
|
22 |
} |
src/Core/Application/Leuze.Core.Application/CQRS/Auth/Commads/VerifyAdUser.cs | ||
---|---|---|
1 |
using Leuze.Core.Application.Identity; |
|
2 |
using Leuze.Core.Domain.Domains.Users; |
|
3 |
using Leuze.Core.Domain.Repositories; |
|
4 |
using Microsoft.AspNetCore.Identity; |
|
5 |
using System; |
|
6 |
using System.Collections.Generic; |
|
7 |
using System.Linq; |
|
8 |
using System.Text; |
|
9 |
using System.Threading; |
|
10 |
using System.Threading.Tasks; |
|
11 |
|
|
12 |
namespace Leuze.Core.Application.CQRS.Auth.Commands |
|
13 |
{ |
|
14 |
/// <summary> |
|
15 |
/// |
|
16 |
/// </summary> |
|
17 |
public static class VerifyAdUser |
|
18 |
{ |
|
19 |
/// <summary> |
|
20 |
/// |
|
21 |
/// </summary> |
|
22 |
public record Command(string Email, string Name) : IBaseRequest<Response>; |
|
23 |
|
|
24 |
/// <summary> |
|
25 |
/// |
|
26 |
/// </summary> |
|
27 |
public record Response(ApplicationUser User); |
|
28 |
|
|
29 |
/// <summary> |
|
30 |
/// |
|
31 |
/// </summary> |
|
32 |
public class Handler : IBaseRequestHandler<Command, Response> |
|
33 |
{ |
|
34 |
private readonly IUserRepository _userRepository; |
|
35 |
private readonly IDomainUserRepository _domainUserRepository; |
|
36 |
|
|
37 |
/// <summary> |
|
38 |
/// |
|
39 |
/// </summary> |
|
40 |
/// <param name="userRepository"></param> |
|
41 |
/// <param name="domainUserRepository"></param> |
|
42 |
/// <param name="userManager"></param> |
|
43 |
public Handler(IUserRepository userRepository, IDomainUserRepository domainUserRepository) |
|
44 |
=> (_userRepository, _domainUserRepository) = (userRepository, domainUserRepository); |
|
45 |
|
|
46 |
/// <summary> |
|
47 |
/// |
|
48 |
/// </summary> |
|
49 |
/// <param name="request"></param> |
|
50 |
/// <param name="cancellationToken"></param> |
|
51 |
/// <returns></returns> |
|
52 |
public async Task<RequestResponse<Response>> Handle(Command request, CancellationToken cancellationToken) |
|
53 |
{ |
|
54 |
var user = await _userRepository.GetAdByEmailAsync(request.Email); |
|
55 |
|
|
56 |
if(user is not null) |
|
57 |
{ |
|
58 |
var domainUser = await _domainUserRepository.GetByIdAsync(user.Id); |
|
59 |
|
|
60 |
if (domainUser is null) return RequestResponse<Response>.CreateErrorResponse($"Domain user with ID '{user.Id}' not found"); |
|
61 |
if(domainUser.Name.FullName != request.Name) |
|
62 |
{ |
|
63 |
domainUser.ChangeName(new(request.Name)); |
|
64 |
await _domainUserRepository.UpdateAsync(domainUser); |
|
65 |
} |
|
66 |
return RequestResponse<Response>.CreateSuccessResponse(new(user)); |
|
67 |
} |
|
68 |
|
|
69 |
var canCreate = await _userRepository.CanCreateByEmailAsync(request.Email); |
|
70 |
if(!canCreate) return RequestResponse<Response>.CreateErrorResponse($"User with email '{request.Email}' already exists"); |
|
71 |
|
|
72 |
user = new(request.Email, request.Email, true); |
|
73 |
await _userRepository.AddAsync(user); |
|
74 |
|
|
75 |
// Have to be loaded with Leuze DB context - otherwise want to create duplicate record in DB, but user must be created using UserManager (it's safe) |
|
76 |
user = await _userRepository.GetAdByEmailAsync(request.Email); |
|
77 |
|
|
78 |
DomainUser newDomainUser = new(user, new(request.Name), new(request.Email)); |
|
79 |
await _domainUserRepository.AddAsync(newDomainUser); |
|
80 |
|
|
81 |
return RequestResponse<Response>.CreateSuccessResponse(new(user)); |
|
82 |
} |
|
83 |
} |
|
84 |
|
|
85 |
} |
|
86 |
} |
src/Core/Application/Leuze.Core.Application/CQRS/Auth/Commads/VerifyLocalUser.cs | ||
---|---|---|
1 |
using Leuze.Core.Application.Identity; |
|
2 |
using Microsoft.AspNetCore.Identity; |
|
3 |
using System; |
|
4 |
using System.Collections.Generic; |
|
5 |
using System.Linq; |
|
6 |
using System.Text; |
|
7 |
using System.Threading; |
|
8 |
using System.Threading.Tasks; |
|
9 |
|
|
10 |
namespace Leuze.Core.Application.CQRS.Auth.Commads |
|
11 |
{ |
|
12 |
/// <summary> |
|
13 |
/// |
|
14 |
/// </summary> |
|
15 |
public static class VerifyLocalUser |
|
16 |
{ |
|
17 |
/// <summary> |
|
18 |
/// |
|
19 |
/// </summary> |
|
20 |
public record Command(string Email, string Password) : IBaseRequest<Response>; |
|
21 |
|
|
22 |
/// <summary> |
|
23 |
/// |
|
24 |
/// </summary> |
|
25 |
public record Response(); |
|
26 |
|
|
27 |
/// <summary> |
|
28 |
/// |
|
29 |
/// </summary> |
|
30 |
public class Handler : IBaseRequestHandler<Command, Response> |
|
31 |
{ |
|
32 |
private readonly SignInManager<ApplicationUser> _signInManager; |
|
33 |
private readonly UserManager<ApplicationUser> _userManager; |
|
34 |
|
|
35 |
/// <summary> |
|
36 |
/// |
|
37 |
/// </summary> |
|
38 |
/// <param name="signInManager"></param> |
|
39 |
/// <param name="userManager"></param> |
|
40 |
public Handler(SignInManager<ApplicationUser> signInManager, UserManager<ApplicationUser> userManager) |
|
41 |
=> (_signInManager, _userManager) = (signInManager, userManager); |
|
42 |
|
|
43 |
/// <summary> |
|
44 |
/// |
|
45 |
/// </summary> |
|
46 |
/// <param name="request"></param> |
|
47 |
/// <param name="cancellationToken"></param> |
|
48 |
/// <returns></returns> |
|
49 |
public async Task<RequestResponse<Response>> Handle(Command request, CancellationToken cancellationToken) |
|
50 |
{ |
|
51 |
var user = await _userManager.FindByEmailAsync(request.Email); |
|
52 |
if (user is null) |
|
53 |
return RequestResponse<Response>.CreateErrorResponse($"Invalid email or password"); |
|
54 |
|
|
55 |
var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, false); |
|
56 |
if(!result.Succeeded) |
|
57 |
return RequestResponse<Response>.CreateErrorResponse($"Invalid email or password"); |
|
58 |
|
|
59 |
await _signInManager.SignInAsync(user, true); |
|
60 |
|
|
61 |
return RequestResponse<Response>.CreateSuccessResponse(new()); |
|
62 |
} |
|
63 |
} |
|
64 |
|
|
65 |
} |
|
66 |
} |
src/Core/Application/Leuze.Core.Application/CQRS/Users/Commands/CreateLocalUser.cs | ||
---|---|---|
1 |
using Leuze.Core.Application.Configuration; |
|
2 |
using Leuze.Core.Application.Identity; |
|
3 |
using Leuze.Core.Domain.Domains.Users; |
|
4 |
using Leuze.Core.Domain.Repositories; |
|
5 |
using Microsoft.AspNetCore.Http; |
|
6 |
using Microsoft.AspNetCore.Identity; |
|
7 |
using Microsoft.AspNetCore.Identity.UI.Services; |
|
8 |
using Microsoft.Extensions.Options; |
|
9 |
using System; |
|
10 |
using System.Collections.Generic; |
|
11 |
using System.Threading; |
|
12 |
using System.Threading.Tasks; |
|
13 |
|
|
14 |
namespace Leuze.Core.Application.CQRS.Users.Commands |
|
15 |
{ |
|
16 |
/// <summary> |
|
17 |
/// |
|
18 |
/// </summary> |
|
19 |
public static class CreateLocalUser |
|
20 |
{ |
|
21 |
/// <summary> |
|
22 |
/// |
|
23 |
/// </summary> |
|
24 |
public record Command(string Name, string Email, Guid? SeniorUserId, IList<Guid> Roles) : IBaseRequest<Response>; |
|
25 |
|
|
26 |
/// <summary> |
|
27 |
/// |
|
28 |
/// </summary> |
|
29 |
public record Response(); |
|
30 |
|
|
31 |
/// <summary> |
|
32 |
/// |
|
33 |
/// </summary> |
|
34 |
public class Handler : IBaseRequestHandler<Command, Response> |
|
35 |
{ |
|
36 |
private readonly IDomainUserRepository _domainUserRepository; |
|
37 |
private readonly IUserRepository _userRepository; |
|
38 |
private readonly UserManager<ApplicationUser> _userManager; |
|
39 |
private readonly AppSettings _appSettings; |
|
40 |
private readonly IHttpContextAccessor _httpContextAccessor; |
|
41 |
|
|
42 |
/// <summary> |
|
43 |
/// |
|
44 |
/// </summary> |
|
45 |
/// <param name="domainUserRepository"></param> |
|
46 |
/// <param name="userManager"></param> |
|
47 |
/// <param name="emailSender"></param> |
|
48 |
/// <param name="options"></param> |
|
49 |
/// <param name="httpContextAccessor"></param> |
|
50 |
/// <param name="userRepository"></param> |
|
51 |
public Handler(IDomainUserRepository domainUserRepository, UserManager<ApplicationUser> userManager, |
|
52 |
IOptions<AppSettings> options, IHttpContextAccessor httpContextAccessor, IUserRepository userRepository) |
|
53 |
=> (_domainUserRepository, _userManager, _appSettings, _httpContextAccessor, _userRepository) |
|
54 |
= (domainUserRepository, userManager, options.Value, httpContextAccessor, userRepository); |
|
55 |
|
|
56 |
/// <summary> |
|
57 |
/// |
|
58 |
/// </summary> |
|
59 |
/// <param name="request"></param> |
|
60 |
/// <param name="cancellationToken"></param> |
|
61 |
/// <returns></returns> |
|
62 |
public async Task<RequestResponse<Response>> Handle(Command request, CancellationToken cancellationToken) |
|
63 |
{ |
|
64 |
var user = await _userManager.FindByEmailAsync(request.Email); |
|
65 |
if (user is not null) |
|
66 |
return RequestResponse<Response>.CreateErrorResponse($"User with email '{request.Email}' already exists"); |
|
67 |
|
|
68 |
user = new ApplicationUser(request.Email, request.Email, false); |
|
69 |
var result = await _userManager.CreateAsync(user); |
|
70 |
if (!result.Succeeded) |
|
71 |
return RequestResponse<Response>.CreateErrorResponse($"User with username '{request.Email}' failed to create"); |
|
72 |
|
|
73 |
user = await _userRepository.GetByIdAsync(user.Id); |
|
74 |
|
|
75 |
DomainUser? senior = null!; |
|
76 |
if (request.SeniorUserId.HasValue) senior = await _domainUserRepository.GetOptionalByIdAsync(request.SeniorUserId); |
|
77 |
|
|
78 |
DomainUser domainUser = new(user, new(request.Name), new(request.Email)); |
|
79 |
|
|
80 |
await _domainUserRepository.AddAsync(domainUser); |
|
81 |
|
|
82 |
var resetToken = await _userManager.GeneratePasswordResetTokenAsync(user); |
|
83 |
|
|
84 |
/*await _emailSender.SendAsync(new NewUserTemplate( |
|
85 |
null!, |
|
86 |
new MailAddress(domainUser.Email.GetEmailAddress()), |
|
87 |
"Vytvořen účet - Leuze", |
|
88 |
new() { ResetLink = $"{_httpContextAccessor.HttpContext!.Request.Scheme}://{_httpContextAccessor.HttpContext!.Request.Host}/{_appSettings.Authentication.ResetUrl}/?token={resetToken}&user={user.Email}" } |
|
89 |
));*/ |
|
90 |
|
|
91 |
return RequestResponse<Response>.CreateSuccessResponse(new()); |
|
92 |
} |
|
93 |
} |
|
94 |
|
|
95 |
} |
|
96 |
} |
src/Core/Application/Leuze.Core.Application/CQRS/Users/Queries/GetFilteredUsers.cs | ||
---|---|---|
1 |
using Leuze.Core.Domain.Domains.Users.DTOs; |
|
2 |
using Leuze.Core.Domain.Repositories; |
|
3 |
using System; |
|
4 |
using System.Collections.Generic; |
|
5 |
using System.Linq; |
|
6 |
using System.Text; |
|
7 |
using System.Threading; |
|
8 |
using System.Threading.Tasks; |
|
9 |
|
|
10 |
namespace Leuze.Core.Application.CQRS.Users.Queries |
|
11 |
{ |
|
12 |
/// <summary> |
|
13 |
/// |
|
14 |
/// </summary> |
|
15 |
public static class GetFilteredUsers |
|
16 |
{ |
|
17 |
/// <summary> |
|
18 |
/// |
|
19 |
/// </summary> |
|
20 |
public record Query(int PageNumber, int PageSize) : IBaseRequest<Response>; |
|
21 |
|
|
22 |
/// <summary> |
|
23 |
/// |
|
24 |
/// </summary> |
|
25 |
public record Response(List<UserDto> List, int Total); |
|
26 |
|
|
27 |
/// <summary> |
|
28 |
/// |
|
29 |
/// </summary> |
|
30 |
public class Handler : IBaseRequestHandler<Query, Response> |
|
31 |
{ |
|
32 |
private readonly IDomainUserRepository _domainUserRepository; |
|
33 |
|
|
34 |
/// <summary> |
|
35 |
/// |
|
36 |
/// </summary> |
|
37 |
/// <param name="domainUserRepository"></param> |
|
38 |
public Handler(IDomainUserRepository domainUserRepository) |
|
39 |
=> (_domainUserRepository) = (domainUserRepository); |
|
40 |
|
|
41 |
/// <summary> |
|
42 |
/// |
|
43 |
/// </summary> |
|
44 |
/// <param name="request"></param> |
|
45 |
/// <param name="cancellationToken"></param> |
|
46 |
/// <returns></returns> |
|
47 |
public async Task<RequestResponse<Response>> Handle(Query request, CancellationToken cancellationToken) |
|
48 |
{ |
|
49 |
var result = await _domainUserRepository.GetFilteredListAsync(request.PageNumber, request.PageSize); |
|
50 |
return RequestResponse<Response>.CreateSuccessResponse(new(result.List, result.Total)); |
|
51 |
} |
|
52 |
} |
|
53 |
|
|
54 |
} |
|
55 |
} |
src/Core/Application/Leuze.Core.Application/Configuration/Actions.cs | ||
---|---|---|
16 | 16 |
using Microsoft.AspNetCore.Authorization; |
17 | 17 |
using Microsoft.AspNetCore.Mvc.Authorization; |
18 | 18 |
using Microsoft.Identity.Web.UI; |
19 |
using System.Threading.Tasks; |
|
20 |
using System.Security.Claims; |
|
21 |
using Microsoft.AspNetCore.Authentication; |
|
22 |
using Microsoft.AspNetCore.Authentication.Cookies; |
|
23 |
using Microsoft.AspNetCore.Http; |
|
24 |
using Leuze.Core.Application.Identity; |
|
25 |
using Microsoft.AspNetCore.Identity; |
|
26 |
using Leuze.Core.Domain.Repositories; |
|
27 |
using Leuze.Core.Application.CQRS.Auth.Commands; |
|
28 |
using Leuze.Core.Application.Configuration.Extensions; |
|
19 | 29 |
|
20 | 30 |
namespace Leuze.Core.Application.Configuration |
21 | 31 |
{ |
... | ... | |
51 | 61 |
|
52 | 62 |
applicationBuilder.UseHttpsRedirection(); |
53 | 63 |
applicationBuilder.UseStaticFiles(); |
54 |
applicationBuilder.UseCookiePolicy(); |
|
55 | 64 |
applicationBuilder.UseRouting(); |
56 | 65 |
applicationBuilder.UseAuthentication(); |
57 | 66 |
applicationBuilder.UseAuthorization(); |
... | ... | |
94 | 103 |
appSettingsSection.Bind(appSettings); |
95 | 104 |
services.Configure<AppSettings>(appSettingsSection); |
96 | 105 |
|
97 |
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) |
|
98 |
.AddMicrosoftIdentityWebApp(configuration.GetSection("AzureAd")); |
|
106 |
services.AddAzureAdAuthentication(configuration); |
|
99 | 107 |
services.AddControllersWithViews() |
100 | 108 |
.AddMicrosoftIdentityUI(); |
101 | 109 |
|
102 |
// Options with default policy causes infinite redirect |
|
103 |
services.AddAuthorization(); |
|
110 |
services.AddCustomAuthorization(); |
|
104 | 111 |
services.AddRazorPages(); |
105 | 112 |
services.AddServerSideBlazor() |
106 | 113 |
.AddMicrosoftIdentityConsentHandler(); |
src/Core/Application/Leuze.Core.Application/Configuration/Extensions/CustomAuthenticationExtensions.cs | ||
---|---|---|
1 |
using Leuze.Core.Application.Authentication; |
|
2 |
using Leuze.Core.Application.CQRS.Auth.Commands; |
|
3 |
using Leuze.Core.Application.Identity; |
|
4 |
using Leuze.Core.Domain.Domains.Users.Services.Abstractions; |
|
5 |
using MediatR; |
|
6 |
using Microsoft.AspNetCore.Authentication.OpenIdConnect; |
|
7 |
using Microsoft.AspNetCore.Identity; |
|
8 |
using Microsoft.Extensions.Configuration; |
|
9 |
using Microsoft.Extensions.DependencyInjection; |
|
10 |
using Microsoft.Identity.Web; |
|
11 |
using Serilog; |
|
12 |
using System; |
|
13 |
using System.Linq; |
|
14 |
using System.Security.Claims; |
|
15 |
using System.Threading.Tasks; |
|
16 |
|
|
17 |
namespace Leuze.Core.Application.Configuration.Extensions |
|
18 |
{ |
|
19 |
/// <summary> |
|
20 |
/// |
|
21 |
/// </summary> |
|
22 |
public static class CustomAuthenticationExtensions |
|
23 |
{ |
|
24 |
/// <summary> |
|
25 |
/// |
|
26 |
/// </summary> |
|
27 |
/// <param name="services"></param> |
|
28 |
/// <param name="configuration"></param> |
|
29 |
public static void AddAzureAdAuthentication(this IServiceCollection services, IConfiguration configuration) |
|
30 |
{ |
|
31 |
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) |
|
32 |
.AddMicrosoftIdentityWebApp(options => |
|
33 |
{ |
|
34 |
configuration.Bind("AzureAd", options); |
|
35 |
options.Events = new OpenIdConnectEvents |
|
36 |
{ |
|
37 |
OnRedirectToIdentityProvider = async ctxt => |
|
38 |
{ |
|
39 |
await Task.Yield(); |
|
40 |
}, |
|
41 |
OnAuthenticationFailed = async ctxt => |
|
42 |
{ |
|
43 |
await Task.Yield(); |
|
44 |
}, |
|
45 |
OnTicketReceived = async ctxt => |
|
46 |
{ |
|
47 |
if (ctxt.Principal?.Identity is ClaimsIdentity identity) |
|
48 |
{ |
|
49 |
var manager = ctxt.HttpContext.RequestServices.GetRequiredService<SignInManager<ApplicationUser>>(); |
|
50 |
var mediator = ctxt.HttpContext.RequestServices.GetRequiredService<IMediator>(); |
|
51 |
|
|
52 |
var result = await mediator.Send(new VerifyAdUser.Command(identity.Name!, identity.Claims.Single(o => o.Type == "name").Value)); |
|
53 |
|
|
54 |
if (result.IsSuccess && result.Result is not null) |
|
55 |
await manager.SignInAsync(result.Result.User, true); |
|
56 |
} |
|
57 |
await Task.Yield(); |
|
58 |
}, |
|
59 |
OnRedirectToIdentityProviderForSignOut = async ctxt => |
|
60 |
{ |
|
61 |
var manager = ctxt.HttpContext.RequestServices.GetRequiredService<SignInManager<ApplicationUser>>(); |
|
62 |
await manager.SignOutAsync(); |
|
63 |
await Task.Yield(); |
|
64 |
} |
|
65 |
}; |
|
66 |
}); |
|
67 |
|
|
68 |
services.AddScoped<IDomainUserProvider, DomainUserProvider>(); |
|
69 |
services.AddScoped<IApplicationUserProvider, ApplicationUserProvider>(); |
|
70 |
} |
|
71 |
|
|
72 |
} |
|
73 |
} |
src/Core/Application/Leuze.Core.Application/Configuration/Extensions/CustomAuthorizationExtensions.cs | ||
---|---|---|
1 |
using Leuze.Core.Application.Authorization; |
|
2 |
using Microsoft.AspNetCore.Authorization; |
|
3 |
using Microsoft.Extensions.DependencyInjection; |
|
4 |
|
|
5 |
namespace Leuze.Core.Application.Configuration.Extensions |
|
6 |
{ |
|
7 |
/// <summary> |
|
8 |
/// |
|
9 |
/// </summary> |
|
10 |
public static class CustomAuthorizationExtensions |
|
11 |
{ |
|
12 |
|
|
13 |
/// <summary> |
|
14 |
/// Configures authorization policies. |
|
15 |
/// </summary> |
|
16 |
/// <param name="services">The service collection.</param> |
|
17 |
public static void AddCustomAuthorization(this IServiceCollection services) |
|
18 |
{ |
|
19 |
services.AddAuthorization(); |
|
20 |
|
|
21 |
services.AddTransient<PermissionManager>(); |
|
22 |
services.AddSingleton<IAuthorizationPolicyProvider, PermissionPolicyProvider>(); |
|
23 |
services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>(); |
|
24 |
} |
|
25 |
|
|
26 |
} |
|
27 |
} |
src/Core/Application/Leuze.Core.Application/Leuze.Core.Application.csproj | ||
---|---|---|
19 | 19 |
</PropertyGroup> |
20 | 20 |
|
21 | 21 |
<ItemGroup> |
22 |
<Folder Include="Authorization\" /> |
|
23 | 22 |
<Folder Include="CQRS\Roles\Queries\" /> |
24 | 23 |
</ItemGroup> |
25 | 24 |
|
... | ... | |
38 | 37 |
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="5.0.5" /> |
39 | 38 |
<PackageReference Include="Microsoft.Identity.Web" Version="1.8.2" /> |
40 | 39 |
<PackageReference Include="Microsoft.Identity.Web.UI" Version="1.8.2" /> |
40 |
<PackageReference Include="Serilog" Version="2.10.0" /> |
|
41 | 41 |
</ItemGroup> |
42 | 42 |
|
43 | 43 |
<ItemGroup> |
src/Core/Domain/Leuze.Core.Domain/Domains/Shared/ValueObjects/PersonFullName.cs | ||
---|---|---|
13 | 13 |
/// <summary> |
14 | 14 |
/// Creates a <see cref="PersonFullName"/> with required properties. |
15 | 15 |
/// </summary> |
16 |
/// <param name="firstName">The first name.</param> |
|
17 |
/// <param name="lastName">The last name.</param> |
|
18 |
public PersonFullName(string firstName, string lastName) => (FirstName, LastName) = (firstName, lastName); |
|
16 |
/// <param name="fullName">The full name.</param> |
|
17 |
public PersonFullName(string fullName) => (FullName) = (fullName); |
|
19 | 18 |
|
20 | 19 |
/// <summary> |
21 |
/// The first name.
|
|
20 |
/// The full name.
|
|
22 | 21 |
/// </summary> |
23 |
public string FirstName { get; private set; } = null!; |
|
24 |
|
|
25 |
/// <summary> |
|
26 |
/// The last name. |
|
27 |
/// </summary> |
|
28 |
public string LastName { get; private set; } = null!; |
|
22 |
public string FullName { get; private set; } = null!; |
|
29 | 23 |
|
30 | 24 |
/// <summary> |
31 | 25 |
/// Gets the full name of the person. |
32 | 26 |
/// </summary> |
33 | 27 |
/// <returns>The full name.</returns> |
34 |
public override string ToString() => $"{FirstName} {LastName}";
|
|
28 |
public override string ToString() => $"{FullName}";
|
|
35 | 29 |
|
36 | 30 |
/// <summary> |
37 | 31 |
/// Gets a full name. |
src/Core/Domain/Leuze.Core.Domain/Domains/Users/DTOs/UserDto.cs | ||
---|---|---|
1 |
using System; |
|
2 |
|
|
3 |
namespace Leuze.Core.Domain.Domains.Users.DTOs |
|
4 |
{ |
|
5 |
/// <summary> |
|
6 |
/// |
|
7 |
/// </summary> |
|
8 |
public record UserDto(Guid Id, string Name, string Email, bool IsAdUser); |
|
9 |
} |
src/Core/Domain/Leuze.Core.Domain/Domains/Users/DomainUser.cs | ||
---|---|---|
1 | 1 |
using Leuze.Core.Application.Identity; |
2 |
using Leuze.Core.Domain.Domains.Shared.ValueObjects; |
|
2 | 3 |
using System; |
3 | 4 |
|
4 | 5 |
namespace Leuze.Core.Domain.Domains.Users |
... | ... | |
18 | 19 |
|
19 | 20 |
#pragma warning restore 8618 |
20 | 21 |
|
21 |
private DomainUser(Guid userId) => (UserId) = (userId); |
|
22 |
|
|
23 | 22 |
/// <summary> |
24 | 23 |
/// |
25 | 24 |
/// </summary> |
26 |
/// <param name="userId"></param> |
|
27 |
/// <returns></returns> |
|
28 |
public static DomainUser NewUser(Guid userId) => new(userId); |
|
25 |
/// <param name="user"></param> |
|
26 |
/// <param name="name"></param> |
|
27 |
/// <param name="email"></param> |
|
28 |
public DomainUser(ApplicationUser user, PersonFullName name, EmailAddress email) |
|
29 |
=> (UserId, User, EmailAddress, Name) = (user.Id, user, email, name); |
|
29 | 30 |
|
30 | 31 |
|
31 | 32 |
/// <summary> |
... | ... | |
37 | 38 |
/// |
38 | 39 |
/// </summary> |
39 | 40 |
public ApplicationUser User { get; private set; } = null!; |
41 |
|
|
42 |
/// <summary> |
|
43 |
/// |
|
44 |
/// </summary> |
|
45 |
public PersonFullName Name { get; private set; } |
|
46 |
|
|
47 |
/// <summary> |
|
48 |
/// |
|
49 |
/// </summary> |
|
50 |
public EmailAddress EmailAddress { get; private set; } |
|
51 |
|
|
52 |
/// <summary> |
|
53 |
/// |
|
54 |
/// </summary> |
|
55 |
/// <param name="name"></param> |
|
56 |
public void ChangeName(PersonFullName name) => Name = name; |
|
40 | 57 |
} |
41 | 58 |
} |
src/Core/Domain/Leuze.Core.Domain/Leuze.Core.Domain.csproj | ||
---|---|---|
28 | 28 |
<ProjectReference Include="..\..\Application\Leuze.Core.Application.Identity\Leuze.Core.Application.Identity.csproj" /> |
29 | 29 |
</ItemGroup> |
30 | 30 |
|
31 |
<ItemGroup> |
|
32 |
<Folder Include="Services\" /> |
|
33 |
</ItemGroup> |
|
34 |
|
|
31 | 35 |
</Project> |
src/Core/Domain/Leuze.Core.Domain/Repositories/IDomainUserRepository.cs | ||
---|---|---|
1 |
using ExtCore.Data.Abstractions; |
|
2 |
using Leuze.Core.Domain.Domains.Users; |
|
3 |
using Leuze.Core.Domain.Domains.Users.DTOs; |
|
4 |
using System; |
|
5 |
using System.Collections.Generic; |
|
6 |
using System.Threading.Tasks; |
|
7 |
|
|
8 |
namespace Leuze.Core.Domain.Repositories |
|
9 |
{ |
|
10 |
/// <summary> |
|
11 |
/// |
|
12 |
/// </summary> |
|
13 |
public interface IDomainUserRepository : IRepository |
|
14 |
{ |
|
15 |
/// <summary> |
|
16 |
/// |
|
17 |
/// </summary> |
|
18 |
/// <param name="id"></param> |
|
19 |
/// <returns></returns> |
|
20 |
Task<DomainUser> GetByIdAsync(Guid id); |
|
21 |
|
|
22 |
/// <summary> |
|
23 |
/// |
|
24 |
/// </summary> |
|
25 |
/// <param name="domainUser"></param> |
|
26 |
/// <returns></returns> |
|
27 |
Task AddAsync(DomainUser domainUser); |
|
28 |
|
|
29 |
/// <summary> |
|
30 |
/// |
|
31 |
/// </summary> |
|
32 |
/// <param name="domainUser"></param> |
|
33 |
/// <returns></returns> |
|
34 |
Task UpdateAsync(DomainUser domainUser); |
|
35 |
|
|
36 |
/// <summary> |
|
37 |
/// |
|
38 |
/// </summary> |
|
39 |
/// <param name="pageNumber"></param> |
|
40 |
/// <param name="pageSize"></param> |
|
41 |
/// <returns></returns> |
|
42 |
Task<(List<UserDto> List, int Total)> GetFilteredListAsync(int pageNumber, int pageSize); |
|
43 |
|
|
44 |
/// <summary> |
|
45 |
/// |
|
46 |
/// </summary> |
|
47 |
/// <param name="currentUserId"></param> |
|
48 |
/// <returns></returns> |
|
49 |
Task<DomainUser?> GetOptionalByIdAsync(Guid? currentUserId); |
|
50 |
} |
|
51 |
} |
src/Core/Domain/Leuze.Core.Domain/Repositories/IUserRepository.cs | ||
---|---|---|
1 | 1 |
using ExtCore.Data.Abstractions; |
2 |
using Leuze.Core.Application.Identity; |
|
3 |
using System; |
|
4 |
using System.Threading.Tasks; |
|
2 | 5 |
|
3 | 6 |
namespace Leuze.Core.Domain.Repositories |
4 | 7 |
{ |
... | ... | |
7 | 10 |
/// </summary> |
8 | 11 |
public interface IUserRepository : IRepository |
9 | 12 |
{ |
13 |
/// <summary> |
|
14 |
/// |
|
15 |
/// </summary> |
|
16 |
/// <param name="entity"></param> |
|
17 |
/// <returns></returns> |
|
18 |
Task AddAsync(ApplicationUser entity); |
|
19 |
|
|
20 |
/// <summary> |
|
21 |
/// |
|
22 |
/// </summary> |
|
23 |
/// <param name="email"></param> |
|
24 |
/// <returns></returns> |
|
25 |
Task<ApplicationUser> GetAdByEmailAsync(string email); |
|
26 |
|
|
27 |
/// <summary> |
|
28 |
/// |
|
29 |
/// </summary> |
|
30 |
/// <param name="email"></param> |
|
31 |
/// <returns></returns> |
|
32 |
Task<bool> CanCreateByEmailAsync(string email); |
|
33 |
|
|
34 |
/// <summary> |
|
35 |
/// |
|
36 |
/// </summary> |
|
37 |
/// <param name="id"></param> |
|
38 |
/// <param name="permission"></param> |
|
39 |
/// <returns></returns> |
|
40 |
Task<bool> HasPermissionAsync(Guid id, string permission); |
|
41 |
|
|
42 |
/// <summary> |
|
43 |
/// |
|
44 |
/// </summary> |
|
45 |
/// <param name="id"></param> |
|
46 |
/// <returns></returns> |
|
47 |
Task<ApplicationUser> GetByIdAsync(Guid id); |
|
10 | 48 |
} |
11 | 49 |
} |
src/Core/Domain/Leuze.Core.Domain/Services/IActiveDirectory.cs | ||
---|---|---|
1 |
namespace Leuze.Core.Domain.Services |
|
2 |
{ |
|
3 |
/// <summary> |
|
4 |
/// |
|
5 |
/// </summary> |
|
6 |
public interface IActiveDirectory |
|
7 |
{ |
|
8 |
} |
|
9 |
} |
src/Core/Infrastructure/Leuze.Core.Infrastructure.ActiveDirectory/DependencyInjection.cs | ||
---|---|---|
1 |
using ExtCore.Infrastructure.Actions; |
|
2 |
using Leuze.Core.Domain.Services; |
|
3 |
using Leuze.Core.Infrastructure.ActiveDirectory.Services; |
|
4 |
using Microsoft.AspNetCore.Builder; |
|
5 |
using Microsoft.Extensions.DependencyInjection; |
|
6 |
using System; |
|
7 |
|
|
8 |
namespace Leuze.Core.Infrastructure.ActiveDirectory |
|
9 |
{ |
|
10 |
/// <summary> |
|
11 |
/// |
|
12 |
/// </summary> |
|
13 |
public class ServicesConfiguration : IConfigureServicesAction |
|
14 |
{ |
|
15 |
/// <summary> |
|
16 |
/// |
|
17 |
/// </summary> |
|
18 |
public int Priority => 1000; |
|
19 |
|
|
20 |
/// <summary> |
|
21 |
/// |
|
22 |
/// </summary> |
|
23 |
/// <param name="services"></param> |
|
24 |
/// <param name="serviceProvider"></param> |
|
25 |
public void Execute(IServiceCollection services, IServiceProvider serviceProvider) |
|
26 |
{ |
|
27 |
services.AddTransient<IActiveDirectory, AdService>(); |
|
28 |
} |
|
29 |
} |
|
30 |
|
|
31 |
/// <summary> |
|
32 |
/// |
|
33 |
/// </summary> |
|
34 |
public class ApplicationConfiguration : IConfigureAction |
|
35 |
{ |
|
36 |
/// <summary> |
|
37 |
/// |
|
38 |
/// </summary> |
|
39 |
public int Priority => 11000; |
|
40 |
|
|
41 |
/// <summary> |
|
42 |
/// |
|
43 |
/// </summary> |
|
44 |
/// <param name="applicationBuilder"></param> |
|
45 |
/// <param name="serviceProvider"></param> |
|
46 |
public void Execute(IApplicationBuilder applicationBuilder, IServiceProvider serviceProvider) |
|
47 |
{ |
|
48 |
} |
|
49 |
} |
|
50 |
} |
src/Core/Infrastructure/Leuze.Core.Infrastructure.ActiveDirectory/Leuze.Core.Infrastructure.ActiveDirectory.csproj | ||
---|---|---|
1 |
<Project Sdk="Microsoft.NET.Sdk"> |
|
2 |
|
|
3 |
<PropertyGroup> |
|
4 |
<AssemblyName>Leuze.Core.Infrastructure.ActiveDirectory</AssemblyName> |
|
5 |
<RootNamespace>Leuze.Core.Infrastructure.ActiveDirectory</RootNamespace> |
|
6 |
<Product></Product> |
|
7 |
<Description></Description> |
|
8 |
</PropertyGroup> |
|
9 |
|
|
10 |
<PropertyGroup> |
|
11 |
<TargetFramework>net5.0</TargetFramework> |
|
12 |
<Nullable>enable</Nullable> |
|
13 |
<GenerateDocumentationFile>true</GenerateDocumentationFile> |
|
14 |
</PropertyGroup> |
|
15 |
|
|
16 |
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> |
|
17 |
<OutputPath>..\..\..\Presentation\Leuze.Modules\</OutputPath> |
|
18 |
<DocumentationFile>..\..\..\..\docs\Leuze.Core.Infrastructure.ActiveDirectory.xml</DocumentationFile> |
|
19 |
</PropertyGroup> |
|
20 |
|
|
21 |
<ItemGroup> |
|
22 |
<PackageReference Include="ExtCore.Infrastructure" Version="6.0.0" /> |
|
23 |
</ItemGroup> |
|
24 |
|
|
25 |
<ItemGroup> |
|
26 |
<ProjectReference Include="..\..\Domain\Leuze.Core.Domain\Leuze.Core.Domain.csproj" /> |
|
27 |
</ItemGroup> |
|
28 |
|
|
29 |
</Project> |
src/Core/Infrastructure/Leuze.Core.Infrastructure.ActiveDirectory/Services/AdService.cs | ||
---|---|---|
1 |
using Leuze.Core.Domain.Services; |
Také k dispozici: Unified diff
Removed unused Azure AD project, updated identity core, custom authorization middleware - permission oriented authorization
ref #8556