Skip to content

Commit dcbe058

Browse files
authored
.net 8 migration and refactorings (#201)
* .NET 8 * .NET 8 * Setup of Identity without external dependencies * Update README.md * Update dotnet-core.yml
1 parent 4c348d6 commit dcbe058

File tree

59 files changed

+1093
-354
lines changed

Some content is hidden

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

59 files changed

+1093
-354
lines changed

.github/workflows/dotnet-core.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- name: Setup .NET Core
1717
uses: actions/setup-dotnet@v1
1818
with:
19-
dotnet-version: 6.0.x
19+
dotnet-version: 8.0.x
2020
- name: Install dependencies
2121
run: dotnet restore
2222
- name: Build

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ The Equinox Project is a open-source project written in .NET Core
88
The goal of this project is implement the most common used technologies and share with the technical community the best way to develop great applications with .NET
99

1010
[![Build status](https://ci.appveyor.com/api/projects/status/rl2ja69994rt3ei6?svg=true)](https://ci.appveyor.com/project/EduardoPires/equinoxproject)
11-
![.NET Core](https://github.com/EduardoPires/EquinoxProject/workflows/.NET%20Core/badge.svg)
1211
[![License](https://img.shields.io/github/license/eduardopires/equinoxproject.svg)](LICENSE)
1312
[![Issues open](https://img.shields.io/github/issues/eduardopires/equinoxproject.svg)](https://huboard.com/EduardoPires/EquinoxProject/)
1413

@@ -29,18 +28,17 @@ To know more about how to setup your enviroment visit the [Microsoft .NET Downlo
2928

3029
## Technologies implemented:
3130

32-
- ASP.NET 6.0
31+
- ASP.NET 8.0
3332
- ASP.NET MVC Core
3433
- ASP.NET WebApi Core with JWT Bearer Authentication
3534
- ASP.NET Identity Core
36-
- Entity Framework Core 6.0
35+
- Entity Framework Core 8.0
3736
- .NET Core Native DI
3837
- AutoMapper
3938
- FluentValidator
4039
- MediatR
4140
- Swagger UI with JWT support
4241
- .NET DevPack
43-
- .NET DevPack.Identity
4442

4543
## Architecture:
4644

@@ -56,6 +54,12 @@ To know more about how to setup your enviroment visit the [Microsoft .NET Downlo
5654

5755
## News
5856

57+
**v1.9 - 06/31/2024**
58+
- Migrated for .NET 8.0
59+
- Full refactoring of Web and Api configuration
60+
- Now all ASP.NET Identity configurations are inside the project, without external dependencies
61+
- All dependencies is up to date
62+
5963
**v1.8 - 03/22/2022**
6064
- Migrated for .NET 6.0
6165
- All dependencies is up to date
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFramework>net6.0</TargetFramework>
3+
<TargetFramework>net8.0</TargetFramework>
4+
<Nullable>disable</Nullable>
45
</PropertyGroup>
56
<ItemGroup>
6-
<ProjectReference Include="..\Equinox.Domain\Equinox.Domain.csproj"/>
7-
<ProjectReference Include="..\Equinox.Infra.Data\Equinox.Infra.Data.csproj"/>
7+
<ProjectReference Include="..\Equinox.Domain\Equinox.Domain.csproj" />
8+
<ProjectReference Include="..\Equinox.Infra.Data\Equinox.Infra.Data.csproj" />
89
</ItemGroup>
910
<ItemGroup>
10-
<PackageReference Include="AutoMapper" Version="11.0.1"/>
11+
<PackageReference Include="AutoMapper" Version="13.0.1" />
1112
</ItemGroup>
1213
</Project>

src/Equinox.Domain.Core/Equinox.Domain.Core.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFramework>net6.0</TargetFramework>
3+
<TargetFramework>net8.0</TargetFramework>
4+
<Nullable>disable</Nullable>
45
</PropertyGroup>
56
<ItemGroup>
67
<PackageReference Include="NetDevPack" Version="7.0.1" />

src/Equinox.Domain/Equinox.Domain.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFramework>net6.0</TargetFramework>
3+
<TargetFramework>net8.0</TargetFramework>
4+
<Nullable>disable</Nullable>
45
</PropertyGroup>
56
<ItemGroup>
67
<ProjectReference Include="..\Equinox.Domain.Core\Equinox.Domain.Core.csproj" />
78
<ProjectReference Include="..\Equinox.Infra.CrossCutting.Bus\Equinox.Infra.CrossCutting.Bus.csproj" />
89
</ItemGroup>
910
<ItemGroup>
10-
<PackageReference Include="FluentValidation" Version="10.4.0" />
11+
<PackageReference Include="FluentValidation" Version="11.9.2" />
1112
<PackageReference Include="System.ComponentModel" Version="4.3.0" />
1213
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
1314
<PackageReference Include="System.Security.Claims" Version="4.3.0" />

src/Equinox.Infra.CrossCutting.Bus/Equinox.Infra.CrossCutting.Bus.csproj

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<TargetFramework>net6.0</TargetFramework>
3+
<TargetFramework>net8.0</TargetFramework>
4+
<Nullable>disable</Nullable>
45
</PropertyGroup>
56
<ItemGroup>
6-
<PackageReference Include="mediatr" Version="10.0.1" />
7+
<PackageReference Include="mediatr" Version="12.4.0" />
78
</ItemGroup>
89
<ItemGroup>
910
<ProjectReference Include="..\Equinox.Domain.Core\Equinox.Domain.Core.csproj" />
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
namespace Equinox.Infra.CrossCutting.Identity.API
2+
{
3+
public class AppJwtSettings
4+
{
5+
public string SecretKey { get; set; }
6+
public int Expiration { get; set; } = 1;
7+
public string Issuer { get; set; } = "Equinox.Api";
8+
public string Audience { get; set; } = "Api";
9+
}
10+
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using Equinox.Infra.CrossCutting.Identity.Models;
2+
using Microsoft.AspNetCore.Identity;
3+
using Microsoft.IdentityModel.Tokens;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.IdentityModel.Tokens.Jwt;
7+
using System.Linq;
8+
using System.Security.Claims;
9+
using System.Text;
10+
11+
namespace Equinox.Infra.CrossCutting.Identity.API
12+
{
13+
public class JwtBuilder<TIdentityUser, TKey> where TIdentityUser : IdentityUser<TKey> where TKey : IEquatable<TKey>
14+
{
15+
private UserManager<TIdentityUser> _userManager;
16+
private AppJwtSettings _appJwtSettings;
17+
private TIdentityUser _user;
18+
private ICollection<Claim> _userClaims;
19+
private ICollection<Claim> _jwtClaims;
20+
private ClaimsIdentity _identityClaims;
21+
22+
public JwtBuilder<TIdentityUser, TKey> WithUserManager(UserManager<TIdentityUser> userManager)
23+
{
24+
_userManager = userManager ?? throw new ArgumentException(nameof(userManager));
25+
return this;
26+
}
27+
28+
public JwtBuilder<TIdentityUser, TKey> WithJwtSettings(AppJwtSettings appJwtSettings)
29+
{
30+
_appJwtSettings = appJwtSettings ?? throw new ArgumentException(nameof(appJwtSettings));
31+
return this;
32+
}
33+
34+
public JwtBuilder<TIdentityUser, TKey> WithEmail(string email)
35+
{
36+
if (string.IsNullOrEmpty(email)) throw new ArgumentException(nameof(email));
37+
38+
_user = _userManager.FindByEmailAsync(email).Result;
39+
_userClaims = new List<Claim>();
40+
_jwtClaims = new List<Claim>();
41+
_identityClaims = new ClaimsIdentity();
42+
43+
return this;
44+
}
45+
46+
public JwtBuilder<TIdentityUser, TKey> WithJwtClaims()
47+
{
48+
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Sub, _user.Id.ToString()));
49+
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Email, _user.Email));
50+
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()));
51+
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Nbf, ToUnixEpochDate(DateTime.UtcNow).ToString()));
52+
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Iat, ToUnixEpochDate(DateTime.UtcNow).ToString(), ClaimValueTypes.Integer64));
53+
54+
_identityClaims.AddClaims(_jwtClaims);
55+
56+
return this;
57+
}
58+
59+
public JwtBuilder<TIdentityUser, TKey> WithUserClaims()
60+
{
61+
_userClaims = _userManager.GetClaimsAsync(_user).Result;
62+
_identityClaims.AddClaims(_userClaims);
63+
64+
return this;
65+
}
66+
67+
public JwtBuilder<TIdentityUser, TKey> WithUserRoles()
68+
{
69+
var userRoles = _userManager.GetRolesAsync(_user).Result;
70+
userRoles.ToList().ForEach(r => _identityClaims.AddClaim(new Claim("role", r)));
71+
72+
return this;
73+
}
74+
75+
public string BuildToken()
76+
{
77+
var tokenHandler = new JwtSecurityTokenHandler();
78+
var key = Encoding.ASCII.GetBytes(_appJwtSettings.SecretKey);
79+
var token = tokenHandler.CreateToken(new SecurityTokenDescriptor
80+
{
81+
Issuer = _appJwtSettings.Issuer,
82+
Audience = _appJwtSettings.Audience,
83+
Subject = _identityClaims,
84+
Expires = DateTime.UtcNow.AddHours(_appJwtSettings.Expiration),
85+
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key),
86+
SecurityAlgorithms.HmacSha256Signature)
87+
});
88+
89+
return tokenHandler.WriteToken(token);
90+
}
91+
92+
public UserResponse BuildUserResponse()
93+
{
94+
var user = new UserResponse
95+
{
96+
AccessToken = BuildToken(),
97+
ExpiresIn = TimeSpan.FromHours(_appJwtSettings.Expiration).TotalSeconds,
98+
UserToken = new UserToken
99+
{
100+
Id = _user.Id,
101+
Email = _user.Email,
102+
Claims = _userClaims.Select(c => new UserClaim { Type = c.Type, Value = c.Value })
103+
}
104+
};
105+
106+
return user;
107+
}
108+
109+
private static long ToUnixEpochDate(DateTime date)
110+
=> (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero))
111+
.TotalSeconds);
112+
}
113+
114+
public class JwtBuilder<TIdentityUser> : JwtBuilder<TIdentityUser, string> where TIdentityUser : IdentityUser<string> { }
115+
116+
public sealed class JwtBuilder : JwtBuilder<IdentityUser> { }
117+
}

src/Equinox.Infra.CrossCutting.Identity/ApiIdentityConfig.cs

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System.Linq;
2+
using Microsoft.AspNetCore.Http;
3+
4+
namespace Equinox.Infra.CrossCutting.Identity.Authorization
5+
{
6+
public static class CustomAuthorizationValidation
7+
{
8+
public static bool UserHasValidClaim(HttpContext context, string claimName, string claimValue)
9+
{
10+
return context.User.Identity.IsAuthenticated &&
11+
context.User.Claims.Any(c =>
12+
c.Type == claimName &&
13+
c.Value.Split(',').Select(v => v.Trim()).Contains(claimValue));
14+
}
15+
16+
}
17+
}

0 commit comments

Comments
 (0)