Skip to content

Commit a939fe7

Browse files
author
Carlos Cañizares Estévez
committed
MVC App: Authentication against IdentityService and Order Api basic integration.
1 parent 87186a8 commit a939fe7

25 files changed

Lines changed: 981 additions & 540 deletions

docker-compose.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,10 @@ services:
6666
- ordering.data
6767

6868
ordering.data:
69-
image: eshop/ordering.data.sqlserver.linux
69+
image: microsoft/mssql-server-linux
70+
environment:
71+
- SA_PASSWORD=Pass@word
72+
- ACCEPT_EULA=Y
7073
ports:
7174
- "5432:1433"
7275

src/Services/Identity/eShopOnContainers.Identity/Configuration/Config.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,55 @@ public static IEnumerable<Client> GetClients()
6161
"orders",
6262
"basket"
6363
}
64+
},
65+
new Client
66+
{
67+
ClientId = "xamarin",
68+
ClientName = "eShop Xamarin OpenId Client",
69+
AllowedGrantTypes = GrantTypes.Implicit,
70+
AllowAccessTokensViaBrowser = true,
71+
72+
RedirectUris = { "http://localhost:5003/callback.html" },
73+
PostLogoutRedirectUris = { "http://localhost:5003/index.html" },
74+
AllowedCorsOrigins = { "http://localhost:5003" },
75+
76+
AllowedScopes =
77+
{
78+
StandardScopes.OpenId.Name,
79+
StandardScopes.Profile.Name,
80+
"orders",
81+
"basket"
82+
}
83+
},
84+
new Client
85+
{
86+
ClientId = "mvc",
87+
ClientName = "MVC Client",
88+
ClientSecrets = new List<Secret>
89+
{
90+
new Secret("secret".Sha256())
91+
},
92+
ClientUri = "http://localhost:2114",
93+
94+
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
95+
96+
RedirectUris = new List<string>
97+
{
98+
"http://localhost:2114/signin-oidc"
99+
},
100+
PostLogoutRedirectUris = new List<string>
101+
{
102+
"http://localhost:2114/"
103+
},
104+
LogoutUri = "http://localhost:2114/signout-oidc",
105+
AllowedScopes = new List<string>
106+
{
107+
StandardScopes.OpenId.Name,
108+
StandardScopes.Profile.Name,
109+
StandardScopes.OfflineAccess.Name,
110+
"orders",
111+
"basket",
112+
},
64113
}
65114
};
66115
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Security.Principal;
5+
using System.Threading.Tasks;
6+
7+
namespace eShopOnContainers.Identity.Extensions
8+
{
9+
//public static class PrincipalExtensions
10+
//{
11+
// public static string GetSubjectId(this IPrincipal principal)
12+
// {
13+
// return principal.Identity.GetSubjectId();
14+
// }
15+
//}
16+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
using IdentityServer4.Services;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Threading.Tasks;
6+
using IdentityServer4.Models;
7+
using Microsoft.AspNetCore.Identity;
8+
using eShopOnContainers.Identity.Models;
9+
using System.Security.Claims;
10+
using IdentityModel;
11+
12+
namespace eShopOnContainers.Identity.Services
13+
{
14+
public class ProfileService : IProfileService
15+
{
16+
private readonly UserManager<ApplicationUser> _userManager;
17+
18+
public ProfileService(UserManager<ApplicationUser> userManager)
19+
{
20+
_userManager = userManager;
21+
}
22+
23+
async public Task GetProfileDataAsync(ProfileDataRequestContext context)
24+
{
25+
var subject = context.Subject;
26+
if (subject == null) throw new ArgumentNullException(nameof(context.Subject));
27+
28+
var subjectId = subject.Claims.Where(x => x.Type == "sub").FirstOrDefault().Value;
29+
30+
var user = await _userManager.FindByIdAsync(subjectId);
31+
if (user == null)
32+
throw new ArgumentException("Invalid subject identifier");
33+
34+
var claims = GetClaimsFromUser(user);
35+
context.IssuedClaims = claims.ToList();
36+
}
37+
38+
async public Task IsActiveAsync(IsActiveContext context)
39+
{
40+
var subject = context.Subject;
41+
if (subject == null) throw new ArgumentNullException(nameof(context.Subject));
42+
43+
var subjectId = subject.Claims.Where(x => x.Type == "sub").FirstOrDefault().Value;
44+
var user = await _userManager.FindByIdAsync(subjectId);
45+
46+
context.IsActive = false;
47+
48+
if (user != null)
49+
{
50+
if (_userManager.SupportsUserSecurityStamp)
51+
{
52+
var security_stamp = subject.Claims.Where(c => c.Type == "security_stamp").Select(c => c.Value).SingleOrDefault();
53+
if (security_stamp != null)
54+
{
55+
var db_security_stamp = await _userManager.GetSecurityStampAsync(user);
56+
if (db_security_stamp != security_stamp)
57+
return;
58+
}
59+
}
60+
61+
context.IsActive =
62+
!user.LockoutEnabled ||
63+
!user.LockoutEnd.HasValue ||
64+
user.LockoutEnd <= DateTime.Now;
65+
}
66+
}
67+
68+
private IEnumerable<Claim> GetClaimsFromUser(ApplicationUser user)
69+
{
70+
var claims = new List<Claim>
71+
{
72+
new Claim(JwtClaimTypes.Subject, user.Id),
73+
new Claim(JwtClaimTypes.PreferredUserName, user.UserName)
74+
};
75+
76+
if (!string.IsNullOrWhiteSpace(user.Name))
77+
claims.Add(new Claim("name", user.Name));
78+
79+
if (!string.IsNullOrWhiteSpace(user.Name))
80+
claims.Add(new Claim("last_name", user.LastName));
81+
82+
if (!string.IsNullOrWhiteSpace(user.CardNumber))
83+
claims.Add(new Claim("card_number", user.CardNumber));
84+
85+
if (!string.IsNullOrWhiteSpace(user.CardHolderName))
86+
claims.Add(new Claim("card_holder", user.CardHolderName));
87+
88+
if (!string.IsNullOrWhiteSpace(user.SecurityNumber))
89+
claims.Add(new Claim("card_security_number", user.SecurityNumber));
90+
91+
if (!string.IsNullOrWhiteSpace(user.City))
92+
claims.Add(new Claim("address_city", user.City));
93+
94+
if (!string.IsNullOrWhiteSpace(user.Country))
95+
claims.Add(new Claim("address_country", user.Country));
96+
97+
if (!string.IsNullOrWhiteSpace(user.State))
98+
claims.Add(new Claim("address_state", user.State));
99+
100+
if (!string.IsNullOrWhiteSpace(user.Street))
101+
claims.Add(new Claim("address_street", user.Street));
102+
103+
if (!string.IsNullOrWhiteSpace(user.ZipCode))
104+
claims.Add(new Claim("address_zip_code", user.ZipCode));
105+
106+
if (_userManager.SupportsUserEmail)
107+
{
108+
claims.AddRange(new[]
109+
{
110+
new Claim(JwtClaimTypes.Email, user.Email),
111+
new Claim(JwtClaimTypes.EmailVerified, user.EmailConfirmed ? "true" : "false", ClaimValueTypes.Boolean)
112+
});
113+
}
114+
115+
if (_userManager.SupportsUserPhoneNumber && !string.IsNullOrWhiteSpace(user.PhoneNumber))
116+
{
117+
claims.AddRange(new[]
118+
{
119+
new Claim(JwtClaimTypes.PhoneNumber, user.PhoneNumber),
120+
new Claim(JwtClaimTypes.PhoneNumberVerified, user.PhoneNumberConfirmed ? "true" : "false", ClaimValueTypes.Boolean)
121+
});
122+
}
123+
124+
return claims;
125+
}
126+
}
127+
}

src/Services/Identity/eShopOnContainers.Identity/Startup.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using eShopOnContainers.Identity.Models;
1414
using eShopOnContainers.Identity.Services;
1515
using eShopOnContainers.Identity.Configuration;
16+
using IdentityServer4.Services;
1617

1718
namespace eShopOnContainers.Identity
1819
{
@@ -47,6 +48,7 @@ public void ConfigureServices(IServiceCollection services)
4748
services.AddIdentity<ApplicationUser, IdentityRole>()
4849
.AddEntityFrameworkStores<ApplicationDbContext>()
4950
.AddDefaultTokenProviders();
51+
5052

5153
services.AddMvc();
5254

@@ -59,7 +61,8 @@ public void ConfigureServices(IServiceCollection services)
5961
.AddTemporarySigningCredential()
6062
.AddInMemoryScopes(Config.GetScopes())
6163
.AddInMemoryClients(Config.GetClients())
62-
.AddAspNetIdentity<ApplicationUser>();
64+
.AddAspNetIdentity<ApplicationUser>()
65+
.Services.AddTransient<IProfileService, ProfileService>();
6366

6467
//Configuration Settings:
6568
services.AddOptions();
@@ -89,6 +92,7 @@ public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerF
8992

9093
// Adds IdentityServer
9194
app.UseIdentityServer();
95+
9296
app.UseMvc(routes =>
9397
{
9498
routes.MapRoute(

src/Services/Identity/eShopOnContainers.Identity/appsettings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"ConnectionStrings": {
3-
"DefaultConnection": "Server=identity.data;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word"
4-
//"DefaultConnection": "Server=127.0.0.1,5433;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word"
3+
//"DefaultConnection": "Server=identity.data;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word"
4+
"DefaultConnection": "Server=127.0.0.1,5433;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word"
55
},
66
"ClientsCallBackUrls": {
77
"Spa": "http://localhost:5003"
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
{
2-
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;"
2+
//"ConnectionString": "Server=tcp:ordering.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;"
3+
"ConnectionString": "Server=tcp:127.0.0.1,5432;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;"
34
}

0 commit comments

Comments
 (0)