Skip to content

Commit 65364d9

Browse files
authored
Merge pull request #4 from paulomonteirodev/master
implemented generic Key to IdentityUser
2 parents 973e55c + 729246b commit 65364d9

14 files changed

Lines changed: 240 additions & 36 deletions

src/NetDevPack.Identity/Abstractions.cs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,17 @@ public static IdentityBuilder AddDefaultIdentity(this IServiceCollection service
2626
return services.AddDefaultIdentity<IdentityUser>(options);
2727
}
2828

29-
public static IdentityBuilder AddCustomIdentity<TIdentityUser>(this IServiceCollection services, Action<IdentityOptions> options = null) where TIdentityUser : IdentityUser
29+
public static IdentityBuilder AddCustomIdentity<TIdentityUser>(this IServiceCollection services, Action<IdentityOptions> options = null)
30+
where TIdentityUser : IdentityUser
31+
{
32+
if (services == null) throw new ArgumentException(nameof(services));
33+
34+
return services.AddDefaultIdentity<TIdentityUser>(options);
35+
}
36+
37+
public static IdentityBuilder AddCustomIdentity<TIdentityUser,TKey>(this IServiceCollection services, Action<IdentityOptions> options = null)
38+
where TIdentityUser : IdentityUser<TKey>
39+
where TKey : IEquatable<TKey>
3040
{
3141
if (services == null) throw new ArgumentException(nameof(services));
3242

@@ -38,7 +48,15 @@ public static IdentityBuilder AddDefaultRoles(this IdentityBuilder builder)
3848
return builder.AddRoles<IdentityRole>();
3949
}
4050

41-
public static IdentityBuilder AddCustomRoles<TRole>(this IdentityBuilder builder) where TRole : IdentityRole
51+
public static IdentityBuilder AddCustomRoles<TRole>(this IdentityBuilder builder)
52+
where TRole : IdentityRole
53+
{
54+
return builder.AddRoles<TRole>();
55+
}
56+
57+
public static IdentityBuilder AddCustomRoles<TRole, TKey>(this IdentityBuilder builder)
58+
where TRole : IdentityRole<TKey>
59+
where TKey : IEquatable<TKey>
4260
{
4361
return builder.AddRoles<TRole>();
4462
}

src/NetDevPack.Identity/Jwt/JwtBuilder.cs

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010

1111
namespace NetDevPack.Identity.Jwt
1212
{
13-
public class JwtBuilder<TIdentityUser> where TIdentityUser : IdentityUser
13+
public class JwtBuilder<TIdentityUser, TKey>
14+
where TIdentityUser : IdentityUser<TKey>
15+
where TKey : IEquatable<TKey>
1416
{
1517
private UserManager<TIdentityUser> _userManager;
1618
private AppJwtSettings _appJwtSettings;
@@ -19,19 +21,19 @@ public class JwtBuilder<TIdentityUser> where TIdentityUser : IdentityUser
1921
private ICollection<Claim> _jwtClaims;
2022
private ClaimsIdentity _identityClaims;
2123

22-
public JwtBuilder<TIdentityUser> WithUserManager(UserManager<TIdentityUser> userManager)
24+
public JwtBuilder<TIdentityUser, TKey> WithUserManager(UserManager<TIdentityUser> userManager)
2325
{
2426
_userManager = userManager ?? throw new ArgumentException(nameof(userManager));
2527
return this;
2628
}
2729

28-
public JwtBuilder<TIdentityUser> WithJwtSettings(AppJwtSettings appJwtSettings)
30+
public JwtBuilder<TIdentityUser, TKey> WithJwtSettings(AppJwtSettings appJwtSettings)
2931
{
3032
_appJwtSettings = appJwtSettings ?? throw new ArgumentException(nameof(appJwtSettings));
3133
return this;
3234
}
3335

34-
public JwtBuilder<TIdentityUser> WithEmail(string email)
36+
public JwtBuilder<TIdentityUser, TKey> WithEmail(string email)
3537
{
3638
if (string.IsNullOrEmpty(email)) throw new ArgumentException(nameof(email));
3739

@@ -43,9 +45,9 @@ public JwtBuilder<TIdentityUser> WithEmail(string email)
4345
return this;
4446
}
4547

46-
public JwtBuilder<TIdentityUser> WithJwtClaims()
48+
public JwtBuilder<TIdentityUser, TKey> WithJwtClaims()
4749
{
48-
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Sub, _user.Id));
50+
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Sub, _user.Id.ToString()));
4951
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Email, _user.Email));
5052
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()));
5153
_jwtClaims.Add(new Claim(JwtRegisteredClaimNames.Nbf, ToUnixEpochDate(DateTime.UtcNow).ToString()));
@@ -56,15 +58,15 @@ public JwtBuilder<TIdentityUser> WithJwtClaims()
5658
return this;
5759
}
5860

59-
public JwtBuilder<TIdentityUser> WithUserClaims()
61+
public JwtBuilder<TIdentityUser, TKey> WithUserClaims()
6062
{
6163
_userClaims = _userManager.GetClaimsAsync(_user).Result;
6264
_identityClaims.AddClaims(_userClaims);
6365

6466
return this;
6567
}
6668

67-
public JwtBuilder<TIdentityUser> WithUserRoles()
69+
public JwtBuilder<TIdentityUser, TKey> WithUserRoles()
6870
{
6971
var userRoles = _userManager.GetRolesAsync(_user).Result;
7072
userRoles.ToList().ForEach(r => _identityClaims.AddClaim(new Claim("role", r)));
@@ -89,13 +91,13 @@ public string BuildToken()
8991
return tokenHandler.WriteToken(token);
9092
}
9193

92-
public UserResponse BuildUserResponse()
94+
public UserResponse<TKey> BuildUserResponse()
9395
{
94-
var user = new UserResponse
96+
var user = new UserResponse<TKey>
9597
{
9698
AccessToken = BuildToken(),
9799
ExpiresIn = TimeSpan.FromHours(_appJwtSettings.Expiration).TotalSeconds,
98-
UserToken = new UserToken
100+
UserToken = new UserToken<TKey>
99101
{
100102
Id = _user.Id,
101103
Email = _user.Email,
@@ -111,8 +113,7 @@ private static long ToUnixEpochDate(DateTime date)
111113
.TotalSeconds);
112114
}
113115

114-
public sealed class JwtBuilder : JwtBuilder<IdentityUser>
115-
{
116-
117-
}
116+
public class JwtBuilder<TIdentityUser> : JwtBuilder<TIdentityUser, string> where TIdentityUser : IdentityUser<string> { }
117+
118+
public sealed class JwtBuilder : JwtBuilder<IdentityUser> { }
118119
}
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,14 @@
11
namespace NetDevPack.Identity.Jwt.Model
22
{
3-
public class UserResponse
3+
public class UserResponse<TKey>
44
{
55
public string AccessToken { get; set; }
66
public double ExpiresIn { get; set; }
7-
public UserToken UserToken { get; set; }
7+
public UserToken<TKey> UserToken { get; set; }
8+
}
9+
10+
public class UserResponse : UserResponse<string>
11+
{
12+
813
}
914
}

src/NetDevPack.Identity/Jwt/Model/UserToken.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,15 @@
22

33
namespace NetDevPack.Identity.Jwt.Model
44
{
5-
public class UserToken
5+
public class UserToken<T>
66
{
7-
public string Id { get; set; }
7+
public T Id { get; set; }
88
public string Email { get; set; }
99
public IEnumerable<UserClaim> Claims { get; set; }
1010
}
11+
12+
public class UserToken : UserToken<string>
13+
{
14+
15+
}
1116
}

src/NetDevPack.Identity/NetDevPack.Identity.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<Authors>EduardoPires</Authors>
1818
<RepositoryType>Public</RepositoryType>
1919
<PackageLicenseExpression>MIT</PackageLicenseExpression>
20-
<Version>1.1.1</Version>
20+
<Version>1.2.0</Version>
2121
</PropertyGroup>
2222

2323
<ItemGroup>

src/Samples/AspNetCore.Jwt.Sample/AspNetCore.Jwt.Sample.csproj

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<ItemGroup>
1111
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.8" />
1212
<PackageReference Include="NetDevPack" Version="1.0.4" />
13-
<PackageReference Include="NetDevPack.Identity" Version="1.1.1" />
13+
<PackageReference Include="NetDevPack.Identity" Version="1.2.0" />
1414
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.4.1" />
1515
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.4" />
1616
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.4">
@@ -19,5 +19,4 @@
1919
</PackageReference>
2020
</ItemGroup>
2121

22-
2322
</Project>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using Microsoft.AspNetCore.Identity;
2+
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
3+
using Microsoft.EntityFrameworkCore;
4+
using Microsoft.Extensions.Configuration;
5+
using Microsoft.Extensions.DependencyInjection;
6+
using NetDevPack.Identity;
7+
using NetDevPack.Identity.Jwt;
8+
9+
namespace AspNetCore.Jwt.Sample.Config
10+
{
11+
public static class CustomIdentityAndKeyConfig
12+
{
13+
public static void AddCustomIdentityAndKeyConfiguration(this IServiceCollection services, IConfiguration configuration)
14+
{
15+
// Your own EF Identity configuration - Use when you have another database like postgres
16+
services.AddDbContext<MyIntIdentityContext>(options =>
17+
options.UseSqlServer(configuration.GetConnectionString("CustomKeyConnection")));
18+
19+
// Your own Identity configuration
20+
services.AddCustomIdentity<MyIntIdentityUser, int>(options =>
21+
{
22+
options.SignIn.RequireConfirmedEmail = false;
23+
options.Lockout.MaxFailedAccessAttempts = 5;
24+
})
25+
.AddCustomRoles<MyIntIdentityRoles, int>()
26+
.AddCustomEntityFrameworkStores<MyIntIdentityContext>()
27+
.AddDefaultTokenProviders();
28+
29+
// Ours JWT configuration
30+
services.AddJwtConfiguration(configuration, "AppSettings");
31+
}
32+
}
33+
34+
public class MyIntIdentityUser : IdentityUser<int>
35+
{
36+
37+
}
38+
39+
public class MyIntIdentityRoles : IdentityRole<int>
40+
{
41+
42+
}
43+
44+
public class MyIntIdentityContext : IdentityDbContext<MyIntIdentityUser, MyIntIdentityRoles, int>
45+
{
46+
public MyIntIdentityContext(DbContextOptions<MyIntIdentityContext> options) : base(options) { }
47+
}
48+
}

src/Samples/AspNetCore.Jwt.Sample/Config/DependencyInjectionConfig.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
using Microsoft.AspNetCore.Http;
2-
using Microsoft.Extensions.DependencyInjection;
3-
using NetDevPack.Identity.User;
1+
using Microsoft.Extensions.DependencyInjection;
42

53
namespace AspNetCore.Jwt.Sample.Config
64
{

src/Samples/AspNetCore.Jwt.Sample/Controllers/AuthController.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ private UserResponse GetUserResponse(string email)
8888
.WithJwtClaims()
8989
.WithUserClaims()
9090
.WithUserRoles()
91-
.BuildUserResponse();
91+
.BuildUserResponse() as UserResponse;
9292
}
9393

9494
private string GetFullJwt(string email)
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
using System.Threading.Tasks;
2+
using AspNetCore.Jwt.Sample.Config;
3+
using Microsoft.AspNetCore.Identity;
4+
using Microsoft.AspNetCore.Mvc;
5+
using Microsoft.Extensions.Options;
6+
using NetDevPack.Identity.Jwt;
7+
using NetDevPack.Identity.Jwt.Model;
8+
using NetDevPack.Identity.Model;
9+
10+
namespace AspNetCore.Jwt.Sample.Controllers
11+
{
12+
[Route("api/custom-account-key")]
13+
public class AuthCustomConfigAndKeyController : MainController
14+
{
15+
private readonly SignInManager<MyIntIdentityUser> _signInManager;
16+
private readonly UserManager<MyIntIdentityUser> _userManager;
17+
private readonly AppJwtSettings _appJwtSettings;
18+
19+
public AuthCustomConfigAndKeyController(SignInManager<MyIntIdentityUser> signInManager,
20+
UserManager<MyIntIdentityUser> userManager,
21+
IOptions<AppJwtSettings> appJwtSettings)
22+
{
23+
_signInManager = signInManager;
24+
_userManager = userManager;
25+
_appJwtSettings = appJwtSettings.Value;
26+
}
27+
28+
[HttpPost("register")]
29+
public async Task<ActionResult> Register(RegisterUser registerUser)
30+
{
31+
if (!ModelState.IsValid) return CustomResponse(ModelState);
32+
33+
var user = new MyIntIdentityUser
34+
{
35+
UserName = registerUser.Email,
36+
Email = registerUser.Email,
37+
EmailConfirmed = true
38+
};
39+
40+
var result = await _userManager.CreateAsync(user, registerUser.Password);
41+
42+
if (result.Succeeded)
43+
{
44+
return CustomResponse(GetUserResponse(user.Email));
45+
}
46+
47+
foreach (var error in result.Errors)
48+
{
49+
AddError(error.Description);
50+
}
51+
52+
return CustomResponse();
53+
}
54+
55+
[HttpPost("login")]
56+
public async Task<ActionResult> Login(LoginUser loginUser)
57+
{
58+
if (!ModelState.IsValid) return CustomResponse(ModelState);
59+
60+
var result = await _signInManager.PasswordSignInAsync(loginUser.Email, loginUser.Password, false, true);
61+
62+
if (result.Succeeded)
63+
{
64+
/* ANOTHER OPTIONS */
65+
var userResponse = GetUserResponse(loginUser.Email);
66+
var jwtUserClaims = GetJwtWithUserClaims(loginUser.Email);
67+
var jwtNoClaims = GetJwtWithoutClaims(loginUser.Email);
68+
69+
var fullJwt = GetFullJwt(loginUser.Email);
70+
return CustomResponse(fullJwt);
71+
}
72+
73+
if (result.IsLockedOut)
74+
{
75+
AddError("This user is blocked");
76+
return CustomResponse();
77+
}
78+
79+
AddError("Incorrect user or password");
80+
return CustomResponse();
81+
}
82+
83+
private UserResponse<int> GetUserResponse(string email)
84+
{
85+
return new JwtBuilder<MyIntIdentityUser, int>()
86+
.WithUserManager(_userManager)
87+
.WithJwtSettings(_appJwtSettings)
88+
.WithEmail(email)
89+
.WithJwtClaims()
90+
.WithUserClaims()
91+
.WithUserRoles()
92+
.BuildUserResponse();
93+
}
94+
95+
private string GetFullJwt(string email)
96+
{
97+
return new JwtBuilder<MyIntIdentityUser, int>()
98+
.WithUserManager(_userManager)
99+
.WithJwtSettings(_appJwtSettings)
100+
.WithEmail(email)
101+
.WithJwtClaims()
102+
.WithUserClaims()
103+
.WithUserRoles()
104+
.BuildToken();
105+
}
106+
107+
private string GetJwtWithoutClaims(string email)
108+
{
109+
return new JwtBuilder<MyIntIdentityUser, int>()
110+
.WithUserManager(_userManager)
111+
.WithJwtSettings(_appJwtSettings)
112+
.WithEmail(email)
113+
.BuildToken();
114+
}
115+
116+
private string GetJwtWithUserClaims(string email)
117+
{
118+
return new JwtBuilder<MyIntIdentityUser, int>()
119+
.WithUserManager(_userManager)
120+
.WithJwtSettings(_appJwtSettings)
121+
.WithEmail(email)
122+
.WithUserClaims()
123+
.BuildToken();
124+
}
125+
}
126+
}

0 commit comments

Comments
 (0)