Browse Source

MVC App: Authentication against IdentityService and Order Api basic integration.

pull/49/merge
Carlos Cañizares Estévez 8 years ago
parent
commit
a939fe7a51
25 changed files with 981 additions and 540 deletions
  1. +4
    -1
      docker-compose.yml
  2. +49
    -0
      src/Services/Identity/eShopOnContainers.Identity/Configuration/Config.cs
  3. +16
    -0
      src/Services/Identity/eShopOnContainers.Identity/Extensions/PrincipalExtensions.cs
  4. +127
    -0
      src/Services/Identity/eShopOnContainers.Identity/Services/ProfileService.cs
  5. +5
    -1
      src/Services/Identity/eShopOnContainers.Identity/Startup.cs
  6. +2
    -2
      src/Services/Identity/eShopOnContainers.Identity/appsettings.json
  7. +2
    -1
      src/Services/Ordering/Ordering.API/settings.json
  8. +451
    -392
      src/Web/WebMVC/Controllers/AccountController.cs
  9. +8
    -9
      src/Web/WebMVC/Controllers/CartController.cs
  10. +20
    -13
      src/Web/WebMVC/Controllers/OrderController.cs
  11. +0
    -26
      src/Web/WebMVC/Data/ApplicationDbContext.cs
  12. +44
    -0
      src/Web/WebMVC/Extensions/HttpClientExtensions.cs
  13. +1
    -1
      src/Web/WebMVC/Models/ApplicationUser.cs
  14. +36
    -0
      src/Web/WebMVC/Models/OrderRequest.cs
  15. +13
    -0
      src/Web/WebMVC/Services/IIdentityParser.cs
  16. +3
    -3
      src/Web/WebMVC/Services/IOrderingService.cs
  17. +38
    -0
      src/Web/WebMVC/Services/IdentityParser.cs
  18. +87
    -53
      src/Web/WebMVC/Services/OrderingService.cs
  19. +50
    -10
      src/Web/WebMVC/Startup.cs
  20. +4
    -2
      src/Web/WebMVC/Views/Cart/Index.cshtml
  21. +3
    -2
      src/Web/WebMVC/Views/Order/Create.cshtml
  22. +3
    -0
      src/Web/WebMVC/Views/Shared/_Layout.cshtml
  23. +6
    -6
      src/Web/WebMVC/Views/Shared/_LoginPartial.cshtml
  24. +4
    -4
      src/Web/WebMVC/appsettings.json
  25. +5
    -14
      src/Web/WebMVC/project.json

+ 4
- 1
docker-compose.yml View File

@ -66,7 +66,10 @@ services:
- ordering.data - ordering.data
ordering.data: ordering.data:
image: eshop/ordering.data.sqlserver.linux
image: microsoft/mssql-server-linux
environment:
- SA_PASSWORD=Pass@word
- ACCEPT_EULA=Y
ports: ports:
- "5432:1433" - "5432:1433"


+ 49
- 0
src/Services/Identity/eShopOnContainers.Identity/Configuration/Config.cs View File

@ -61,6 +61,55 @@ namespace eShopOnContainers.Identity.Configuration
"orders", "orders",
"basket" "basket"
} }
},
new Client
{
ClientId = "xamarin",
ClientName = "eShop Xamarin OpenId Client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { "http://localhost:5003/callback.html" },
PostLogoutRedirectUris = { "http://localhost:5003/index.html" },
AllowedCorsOrigins = { "http://localhost:5003" },
AllowedScopes =
{
StandardScopes.OpenId.Name,
StandardScopes.Profile.Name,
"orders",
"basket"
}
},
new Client
{
ClientId = "mvc",
ClientName = "MVC Client",
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256())
},
ClientUri = "http://localhost:2114",
AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
RedirectUris = new List<string>
{
"http://localhost:2114/signin-oidc"
},
PostLogoutRedirectUris = new List<string>
{
"http://localhost:2114/"
},
LogoutUri = "http://localhost:2114/signout-oidc",
AllowedScopes = new List<string>
{
StandardScopes.OpenId.Name,
StandardScopes.Profile.Name,
StandardScopes.OfflineAccess.Name,
"orders",
"basket",
},
} }
}; };
} }


+ 16
- 0
src/Services/Identity/eShopOnContainers.Identity/Extensions/PrincipalExtensions.cs View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks;
namespace eShopOnContainers.Identity.Extensions
{
//public static class PrincipalExtensions
//{
// public static string GetSubjectId(this IPrincipal principal)
// {
// return principal.Identity.GetSubjectId();
// }
//}
}

+ 127
- 0
src/Services/Identity/eShopOnContainers.Identity/Services/ProfileService.cs View File

@ -0,0 +1,127 @@
using IdentityServer4.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using IdentityServer4.Models;
using Microsoft.AspNetCore.Identity;
using eShopOnContainers.Identity.Models;
using System.Security.Claims;
using IdentityModel;
namespace eShopOnContainers.Identity.Services
{
public class ProfileService : IProfileService
{
private readonly UserManager<ApplicationUser> _userManager;
public ProfileService(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
async public Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var subject = context.Subject;
if (subject == null) throw new ArgumentNullException(nameof(context.Subject));
var subjectId = subject.Claims.Where(x => x.Type == "sub").FirstOrDefault().Value;
var user = await _userManager.FindByIdAsync(subjectId);
if (user == null)
throw new ArgumentException("Invalid subject identifier");
var claims = GetClaimsFromUser(user);
context.IssuedClaims = claims.ToList();
}
async public Task IsActiveAsync(IsActiveContext context)
{
var subject = context.Subject;
if (subject == null) throw new ArgumentNullException(nameof(context.Subject));
var subjectId = subject.Claims.Where(x => x.Type == "sub").FirstOrDefault().Value;
var user = await _userManager.FindByIdAsync(subjectId);
context.IsActive = false;
if (user != null)
{
if (_userManager.SupportsUserSecurityStamp)
{
var security_stamp = subject.Claims.Where(c => c.Type == "security_stamp").Select(c => c.Value).SingleOrDefault();
if (security_stamp != null)
{
var db_security_stamp = await _userManager.GetSecurityStampAsync(user);
if (db_security_stamp != security_stamp)
return;
}
}
context.IsActive =
!user.LockoutEnabled ||
!user.LockoutEnd.HasValue ||
user.LockoutEnd <= DateTime.Now;
}
}
private IEnumerable<Claim> GetClaimsFromUser(ApplicationUser user)
{
var claims = new List<Claim>
{
new Claim(JwtClaimTypes.Subject, user.Id),
new Claim(JwtClaimTypes.PreferredUserName, user.UserName)
};
if (!string.IsNullOrWhiteSpace(user.Name))
claims.Add(new Claim("name", user.Name));
if (!string.IsNullOrWhiteSpace(user.Name))
claims.Add(new Claim("last_name", user.LastName));
if (!string.IsNullOrWhiteSpace(user.CardNumber))
claims.Add(new Claim("card_number", user.CardNumber));
if (!string.IsNullOrWhiteSpace(user.CardHolderName))
claims.Add(new Claim("card_holder", user.CardHolderName));
if (!string.IsNullOrWhiteSpace(user.SecurityNumber))
claims.Add(new Claim("card_security_number", user.SecurityNumber));
if (!string.IsNullOrWhiteSpace(user.City))
claims.Add(new Claim("address_city", user.City));
if (!string.IsNullOrWhiteSpace(user.Country))
claims.Add(new Claim("address_country", user.Country));
if (!string.IsNullOrWhiteSpace(user.State))
claims.Add(new Claim("address_state", user.State));
if (!string.IsNullOrWhiteSpace(user.Street))
claims.Add(new Claim("address_street", user.Street));
if (!string.IsNullOrWhiteSpace(user.ZipCode))
claims.Add(new Claim("address_zip_code", user.ZipCode));
if (_userManager.SupportsUserEmail)
{
claims.AddRange(new[]
{
new Claim(JwtClaimTypes.Email, user.Email),
new Claim(JwtClaimTypes.EmailVerified, user.EmailConfirmed ? "true" : "false", ClaimValueTypes.Boolean)
});
}
if (_userManager.SupportsUserPhoneNumber && !string.IsNullOrWhiteSpace(user.PhoneNumber))
{
claims.AddRange(new[]
{
new Claim(JwtClaimTypes.PhoneNumber, user.PhoneNumber),
new Claim(JwtClaimTypes.PhoneNumberVerified, user.PhoneNumberConfirmed ? "true" : "false", ClaimValueTypes.Boolean)
});
}
return claims;
}
}
}

+ 5
- 1
src/Services/Identity/eShopOnContainers.Identity/Startup.cs View File

@ -13,6 +13,7 @@ using eShopOnContainers.Identity.Data;
using eShopOnContainers.Identity.Models; using eShopOnContainers.Identity.Models;
using eShopOnContainers.Identity.Services; using eShopOnContainers.Identity.Services;
using eShopOnContainers.Identity.Configuration; using eShopOnContainers.Identity.Configuration;
using IdentityServer4.Services;
namespace eShopOnContainers.Identity namespace eShopOnContainers.Identity
{ {
@ -47,6 +48,7 @@ namespace eShopOnContainers.Identity
services.AddIdentity<ApplicationUser, IdentityRole>() services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>() .AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders(); .AddDefaultTokenProviders();
services.AddMvc(); services.AddMvc();
@ -59,7 +61,8 @@ namespace eShopOnContainers.Identity
.AddTemporarySigningCredential() .AddTemporarySigningCredential()
.AddInMemoryScopes(Config.GetScopes()) .AddInMemoryScopes(Config.GetScopes())
.AddInMemoryClients(Config.GetClients()) .AddInMemoryClients(Config.GetClients())
.AddAspNetIdentity<ApplicationUser>();
.AddAspNetIdentity<ApplicationUser>()
.Services.AddTransient<IProfileService, ProfileService>();
//Configuration Settings: //Configuration Settings:
services.AddOptions(); services.AddOptions();
@ -89,6 +92,7 @@ namespace eShopOnContainers.Identity
// Adds IdentityServer // Adds IdentityServer
app.UseIdentityServer(); app.UseIdentityServer();
app.UseMvc(routes => app.UseMvc(routes =>
{ {
routes.MapRoute( routes.MapRoute(


+ 2
- 2
src/Services/Identity/eShopOnContainers.Identity/appsettings.json View File

@ -1,7 +1,7 @@
{ {
"ConnectionStrings": { "ConnectionStrings": {
"DefaultConnection": "Server=identity.data;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word"
//"DefaultConnection": "Server=127.0.0.1,5433;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word"
//"DefaultConnection": "Server=identity.data;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word"
"DefaultConnection": "Server=127.0.0.1,5433;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word"
}, },
"ClientsCallBackUrls": { "ClientsCallBackUrls": {
"Spa": "http://localhost:5003" "Spa": "http://localhost:5003"


+ 2
- 1
src/Services/Ordering/Ordering.API/settings.json View File

@ -1,3 +1,4 @@
{ {
"ConnectionString": "Server=tcp:127.0.0.1,5433;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;"
//"ConnectionString": "Server=tcp:ordering.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;"
"ConnectionString": "Server=tcp:127.0.0.1,5432;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word;"
} }

+ 451
- 392
src/Web/WebMVC/Controllers/AccountController.cs View File

@ -4,438 +4,497 @@ using System.Linq;
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering; using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.eShopOnContainers.WebMVC.Models; using Microsoft.eShopOnContainers.WebMVC.Models;
using Microsoft.eShopOnContainers.WebMVC.Models.AccountViewModels; using Microsoft.eShopOnContainers.WebMVC.Models.AccountViewModels;
using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.Services;
using System.Net.Http;
using Newtonsoft.Json.Linq;
using Microsoft.eShopOnContainers.WebMVC.Extensions;
namespace Microsoft.eShopOnContainers.WebMVC.Controllers namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{ {
[Authorize] [Authorize]
public class AccountController : Controller public class AccountController : Controller
{ {
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly ILogger _logger;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
ILoggerFactory loggerFactory)
private readonly IIdentityParser<ApplicationUser> _identityParser;
public AccountController(IIdentityParser<ApplicationUser> identityParser)
{ {
_userManager = userManager;
_signInManager = signInManager;
_logger = loggerFactory.CreateLogger<AccountController>();
_identityParser = identityParser;
} }
//
// GET: /Account/Login
[HttpGet]
[AllowAnonymous]
public IActionResult Login(string returnUrl = null)
public ActionResult Index()
{ {
ViewData["ReturnUrl"] = returnUrl;
return View(); return View();
} }
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
[Authorize]
public IActionResult SignIn(string returnUrl)
{ {
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
var user = User as ClaimsPrincipal;
//TODO - Not retrieving AccessToken yet
var token = user.FindFirst("access_token");
if (token != null)
{ {
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, set lockoutOnFailure: true
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.Succeeded)
{
_logger.LogInformation(1, "User logged in.");
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
}
if (result.IsLockedOut)
{
_logger.LogWarning(2, "User account locked out.");
return View("Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
ViewData["access_token"] = token.Value;
} }
// If we got this far, something failed, redisplay form
return View(model);
return Redirect("/");
} }
//
// GET: /Account/Register
[HttpGet]
[AllowAnonymous]
public IActionResult Register(string returnUrl = null)
[Authorize]
public async Task<ActionResult> CallApi()
{ {
ViewData["ReturnUrl"] = returnUrl;
return View();
}
//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
ViewData["ReturnUrl"] = returnUrl;
if (ModelState.IsValid)
{
var user = new ApplicationUser
{
UserName = model.Email,
Email = model.Email,
CardHolderName = model.User.CardHolderName,
CardNumber = model.User.CardNumber,
CardType = model.User.CardType,
City = model.User.City,
Country = model.User.Country,
Expiration = model.User.Expiration,
LastName = model.User.LastName,
Name = model.User.Name,
Street = model.User.Street,
State = model.User.State,
ZipCode = model.User.ZipCode,
PhoneNumber = model.User.PhoneNumber,
SecurityNumber = model.User.SecurityNumber
};
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
// Send an email with this link
//var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
//var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
//await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
// $"Please confirm your account by clicking this link: <a href='{callbackUrl}'>link</a>");
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation(3, "User created a new account with password.");
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
//
// POST: /Account/LogOff
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> LogOff()
{
await _signInManager.SignOutAsync();
_logger.LogInformation(4, "User logged out.");
return RedirectToAction(nameof(CatalogController.Index), "Catalog");
}
//
// POST: /Account/ExternalLogin
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public IActionResult ExternalLogin(string provider, string returnUrl = null)
{
// Request a redirect to the external login provider.
var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
return Challenge(properties, provider);
}
//
// GET: /Account/ExternalLoginCallback
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
if (remoteError != null)
{
ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
return View(nameof(Login));
}
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
return RedirectToAction(nameof(Login));
}
// Sign in the user with this external login provider if the user already has a login.
var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
if (result.Succeeded)
{
_logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
return RedirectToLocal(returnUrl);
}
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
}
if (result.IsLockedOut)
{
return View("Lockout");
}
else
{
// If the user does not have an account, then ask the user to create an account.
ViewData["ReturnUrl"] = returnUrl;
ViewData["LoginProvider"] = info.LoginProvider;
var email = info.Principal.FindFirstValue(ClaimTypes.Email);
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });
}
}
//
// POST: /Account/ExternalLoginConfirmation
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl = null)
{
if (ModelState.IsValid)
{
// Get the information about the user from the external login provider
var info = await _signInManager.GetExternalLoginInfoAsync();
if (info == null)
{
return View("ExternalLoginFailure");
}
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(user);
if (result.Succeeded)
{
result = await _userManager.AddLoginAsync(user, info);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
_logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider);
return RedirectToLocal(returnUrl);
}
}
AddErrors(result);
}
ViewData["ReturnUrl"] = returnUrl;
return View(model);
}
// GET: /Account/ConfirmEmail
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
return View("Error");
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return View("Error");
}
var result = await _userManager.ConfirmEmailAsync(user, code);
return View(result.Succeeded ? "ConfirmEmail" : "Error");
}
//
// GET: /Account/ForgotPassword
[HttpGet]
[AllowAnonymous]
public IActionResult ForgotPassword()
{
return View();
}
//
// POST: /Account/ForgotPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindByNameAsync(model.Email);
if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
{
// Don't reveal that the user does not exist or is not confirmed
return View("ForgotPasswordConfirmation");
}
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
// Send an email with this link
//var code = await _userManager.GeneratePasswordResetTokenAsync(user);
//var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
//await _emailSender.SendEmailAsync(model.Email, "Reset Password",
// $"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
//return View("ForgotPasswordConfirmation");
}
var token = (User as ClaimsPrincipal).FindFirst("access_token").Value;
// If we got this far, something failed, redisplay form
return View(model);
}
var client = new HttpClient();
client.SetBearerToken(token);
//
// GET: /Account/ForgotPasswordConfirmation
[HttpGet]
[AllowAnonymous]
public IActionResult ForgotPasswordConfirmation()
{
return View();
}
var result = await client.GetStringAsync("apiuri");
ViewBag.Json = JArray.Parse(result.ToString());
//
// GET: /Account/ResetPassword
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPassword(string code = null)
{
return code == null ? View("Error") : View();
}
//
// POST: /Account/ResetPassword
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = await _userManager.FindByNameAsync(model.Email);
if (user == null)
{
// Don't reveal that the user does not exist
return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
}
var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
if (result.Succeeded)
{
return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
}
AddErrors(result);
return View(); return View();
} }
//
// GET: /Account/ResetPasswordConfirmation
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPasswordConfirmation()
{
return View();
}
//
// GET: /Account/SendCode
[HttpGet]
[AllowAnonymous]
public async Task<ActionResult> SendCode(string returnUrl = null, bool rememberMe = false)
public async Task<ActionResult> Signout()
{ {
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
return View("Error");
}
var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user);
var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList();
return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe });
await Request.HttpContext.Authentication.SignOutAsync("oidc");
return Redirect("/");
} }
//
// GET: /Account/VerifyCode
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> VerifyCode(string provider, bool rememberMe, string returnUrl = null)
public async Task SignoutCleanup(string sid)
{ {
// Require that the user has already logged in via username/password or external login
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
return View("Error");
}
return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe });
}
//
// POST: /Account/VerifyCode
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> VerifyCode(VerifyCodeViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// The following code protects for brute force attacks against the two factor codes.
// If a user enters incorrect codes for a specified amount of time then the user account
// will be locked out for a specified amount of time.
var result = await _signInManager.TwoFactorSignInAsync(model.Provider, model.Code, model.RememberMe, model.RememberBrowser);
if (result.Succeeded)
{
return RedirectToLocal(model.ReturnUrl);
}
if (result.IsLockedOut)
{
_logger.LogWarning(7, "User account locked out.");
return View("Lockout");
}
else
{
ModelState.AddModelError(string.Empty, "Invalid code.");
return View(model);
}
}
#region Helpers
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
private Task<ApplicationUser> GetCurrentUserAsync()
{
return _userManager.GetUserAsync(HttpContext.User);
}
private IActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
var cp = (ClaimsPrincipal)User;
var sidClaim = cp.FindFirst("sid");
if (sidClaim != null && sidClaim.Value == sid)
{ {
return RedirectToAction(nameof(CatalogController.Index), "Catalog");
await Request.HttpContext.Authentication.SignOutAsync("Cookies");
} }
} }
#endregion
//private readonly UserManager<ApplicationUser> _userManager;
//private readonly SignInManager<ApplicationUser> _signInManager;
//private readonly ILogger _logger;
//public AccountController(
// UserManager<ApplicationUser> userManager,
// SignInManager<ApplicationUser> signInManager,
// ILoggerFactory loggerFactory)
//{
// _userManager = userManager;
// _signInManager = signInManager;
// _logger = loggerFactory.CreateLogger<AccountController>();
//}
////
//// GET: /Account/Login
//[HttpGet]
//[AllowAnonymous]
//public IActionResult Login(string returnUrl = null)
//{
// ViewData["ReturnUrl"] = returnUrl;
// return View();
//}
////
//// POST: /Account/Login
//[HttpPost]
//[AllowAnonymous]
//[ValidateAntiForgeryToken]
//public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
//{
// ViewData["ReturnUrl"] = returnUrl;
// if (ModelState.IsValid)
// {
// // This doesn't count login failures towards account lockout
// // To enable password failures to trigger account lockout, set lockoutOnFailure: true
// var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
// if (result.Succeeded)
// {
// _logger.LogInformation(1, "User logged in.");
// return RedirectToLocal(returnUrl);
// }
// if (result.RequiresTwoFactor)
// {
// return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
// }
// if (result.IsLockedOut)
// {
// _logger.LogWarning(2, "User account locked out.");
// return View("Lockout");
// }
// else
// {
// ModelState.AddModelError(string.Empty, "Invalid login attempt.");
// return View(model);
// }
// }
// // If we got this far, something failed, redisplay form
// return View(model);
//}
////
//// GET: /Account/Register
//[HttpGet]
//[AllowAnonymous]
//public IActionResult Register(string returnUrl = null)
//{
// ViewData["ReturnUrl"] = returnUrl;
// return View();
//}
////
//// POST: /Account/Register
//[HttpPost]
//[AllowAnonymous]
//[ValidateAntiForgeryToken]
//public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
//{
// ViewData["ReturnUrl"] = returnUrl;
// if (ModelState.IsValid)
// {
// var user = new ApplicationUser
// {
// UserName = model.Email,
// Email = model.Email,
// CardHolderName = model.User.CardHolderName,
// CardNumber = model.User.CardNumber,
// CardType = model.User.CardType,
// City = model.User.City,
// Country = model.User.Country,
// Expiration = model.User.Expiration,
// LastName = model.User.LastName,
// Name = model.User.Name,
// Street = model.User.Street,
// State = model.User.State,
// ZipCode = model.User.ZipCode,
// PhoneNumber = model.User.PhoneNumber,
// SecurityNumber = model.User.SecurityNumber
// };
// var result = await _userManager.CreateAsync(user, model.Password);
// if (result.Succeeded)
// {
// // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
// // Send an email with this link
// //var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
// //var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
// //await _emailSender.SendEmailAsync(model.Email, "Confirm your account",
// // $"Please confirm your account by clicking this link: <a href='{callbackUrl}'>link</a>");
// await _signInManager.SignInAsync(user, isPersistent: false);
// _logger.LogInformation(3, "User created a new account with password.");
// return RedirectToLocal(returnUrl);
// }
// AddErrors(result);
// }
// // If we got this far, something failed, redisplay form
// return View(model);
//}
////
//// POST: /Account/LogOff
//[HttpPost]
//[ValidateAntiForgeryToken]
//public async Task<IActionResult> LogOff()
//{
// await _signInManager.SignOutAsync();
// _logger.LogInformation(4, "User logged out.");
// return RedirectToAction(nameof(CatalogController.Index), "Catalog");
//}
////
//// POST: /Account/ExternalLogin
//[HttpPost]
//[AllowAnonymous]
//[ValidateAntiForgeryToken]
//public IActionResult ExternalLogin(string provider, string returnUrl = null)
//{
// // Request a redirect to the external login provider.
// var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
// var properties = _signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);
// return Challenge(properties, provider);
//}
////
//// GET: /Account/ExternalLoginCallback
//[HttpGet]
//[AllowAnonymous]
//public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
//{
// if (remoteError != null)
// {
// ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
// return View(nameof(Login));
// }
// var info = await _signInManager.GetExternalLoginInfoAsync();
// if (info == null)
// {
// return RedirectToAction(nameof(Login));
// }
// // Sign in the user with this external login provider if the user already has a login.
// var result = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false);
// if (result.Succeeded)
// {
// _logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
// return RedirectToLocal(returnUrl);
// }
// if (result.RequiresTwoFactor)
// {
// return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
// }
// if (result.IsLockedOut)
// {
// return View("Lockout");
// }
// else
// {
// // If the user does not have an account, then ask the user to create an account.
// ViewData["ReturnUrl"] = returnUrl;
// ViewData["LoginProvider"] = info.LoginProvider;
// var email = info.Principal.FindFirstValue(ClaimTypes.Email);
// return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = email });
// }
//}
////
//// POST: /Account/ExternalLoginConfirmation
//[HttpPost]
//[AllowAnonymous]
//[ValidateAntiForgeryToken]
//public async Task<IActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl = null)
//{
// if (ModelState.IsValid)
// {
// // Get the information about the user from the external login provider
// var info = await _signInManager.GetExternalLoginInfoAsync();
// if (info == null)
// {
// return View("ExternalLoginFailure");
// }
// var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
// var result = await _userManager.CreateAsync(user);
// if (result.Succeeded)
// {
// result = await _userManager.AddLoginAsync(user, info);
// if (result.Succeeded)
// {
// await _signInManager.SignInAsync(user, isPersistent: false);
// _logger.LogInformation(6, "User created an account using {Name} provider.", info.LoginProvider);
// return RedirectToLocal(returnUrl);
// }
// }
// AddErrors(result);
// }
// ViewData["ReturnUrl"] = returnUrl;
// return View(model);
//}
//// GET: /Account/ConfirmEmail
//[HttpGet]
//[AllowAnonymous]
//public async Task<IActionResult> ConfirmEmail(string userId, string code)
//{
// if (userId == null || code == null)
// {
// return View("Error");
// }
// var user = await _userManager.FindByIdAsync(userId);
// if (user == null)
// {
// return View("Error");
// }
// var result = await _userManager.ConfirmEmailAsync(user, code);
// return View(result.Succeeded ? "ConfirmEmail" : "Error");
//}
////
//// GET: /Account/ForgotPassword
//[HttpGet]
//[AllowAnonymous]
//public IActionResult ForgotPassword()
//{
// return View();
//}
////
//// POST: /Account/ForgotPassword
//[HttpPost]
//[AllowAnonymous]
//[ValidateAntiForgeryToken]
//public async Task<IActionResult> ForgotPassword(ForgotPasswordViewModel model)
//{
// if (ModelState.IsValid)
// {
// var user = await _userManager.FindByNameAsync(model.Email);
// if (user == null || !(await _userManager.IsEmailConfirmedAsync(user)))
// {
// // Don't reveal that the user does not exist or is not confirmed
// return View("ForgotPasswordConfirmation");
// }
// // For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=532713
// // Send an email with this link
// //var code = await _userManager.GeneratePasswordResetTokenAsync(user);
// //var callbackUrl = Url.Action("ResetPassword", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
// //await _emailSender.SendEmailAsync(model.Email, "Reset Password",
// // $"Please reset your password by clicking here: <a href='{callbackUrl}'>link</a>");
// //return View("ForgotPasswordConfirmation");
// }
// // If we got this far, something failed, redisplay form
// return View(model);
//}
////
//// GET: /Account/ForgotPasswordConfirmation
//[HttpGet]
//[AllowAnonymous]
//public IActionResult ForgotPasswordConfirmation()
//{
// return View();
//}
////
//// GET: /Account/ResetPassword
//[HttpGet]
//[AllowAnonymous]
//public IActionResult ResetPassword(string code = null)
//{
// return code == null ? View("Error") : View();
//}
////
//// POST: /Account/ResetPassword
//[HttpPost]
//[AllowAnonymous]
//[ValidateAntiForgeryToken]
//public async Task<IActionResult> ResetPassword(ResetPasswordViewModel model)
//{
// if (!ModelState.IsValid)
// {
// return View(model);
// }
// var user = await _userManager.FindByNameAsync(model.Email);
// if (user == null)
// {
// // Don't reveal that the user does not exist
// return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
// }
// var result = await _userManager.ResetPasswordAsync(user, model.Code, model.Password);
// if (result.Succeeded)
// {
// return RedirectToAction(nameof(AccountController.ResetPasswordConfirmation), "Account");
// }
// AddErrors(result);
// return View();
//}
////
//// GET: /Account/ResetPasswordConfirmation
//[HttpGet]
//[AllowAnonymous]
//public IActionResult ResetPasswordConfirmation()
//{
// return View();
//}
////
//// GET: /Account/SendCode
//[HttpGet]
//[AllowAnonymous]
//public async Task<ActionResult> SendCode(string returnUrl = null, bool rememberMe = false)
//{
// var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
// if (user == null)
// {
// return View("Error");
// }
// var userFactors = await _userManager.GetValidTwoFactorProvidersAsync(user);
// var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList();
// return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe });
//}
////
//// GET: /Account/VerifyCode
//[HttpGet]
//[AllowAnonymous]
//public async Task<IActionResult> VerifyCode(string provider, bool rememberMe, string returnUrl = null)
//{
// // Require that the user has already logged in via username/password or external login
// var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
// if (user == null)
// {
// return View("Error");
// }
// return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe });
//}
////
//// POST: /Account/VerifyCode
//[HttpPost]
//[AllowAnonymous]
//[ValidateAntiForgeryToken]
//public async Task<IActionResult> VerifyCode(VerifyCodeViewModel model)
//{
// if (!ModelState.IsValid)
// {
// return View(model);
// }
// // The following code protects for brute force attacks against the two factor codes.
// // If a user enters incorrect codes for a specified amount of time then the user account
// // will be locked out for a specified amount of time.
// var result = await _signInManager.TwoFactorSignInAsync(model.Provider, model.Code, model.RememberMe, model.RememberBrowser);
// if (result.Succeeded)
// {
// return RedirectToLocal(model.ReturnUrl);
// }
// if (result.IsLockedOut)
// {
// _logger.LogWarning(7, "User account locked out.");
// return View("Lockout");
// }
// else
// {
// ModelState.AddModelError(string.Empty, "Invalid code.");
// return View(model);
// }
//}
//#region Helpers
//private void AddErrors(IdentityResult result)
//{
// foreach (var error in result.Errors)
// {
// ModelState.AddModelError(string.Empty, error.Description);
// }
//}
//private Task<ApplicationUser> GetCurrentUserAsync()
//{
// return _userManager.GetUserAsync(HttpContext.User);
//}
//private IActionResult RedirectToLocal(string returnUrl)
//{
// if (Url.IsLocalUrl(returnUrl))
// {
// return Redirect(returnUrl);
// }
// else
// {
// return RedirectToAction(nameof(CatalogController.Index), "Catalog");
// }
//}
//#endregion
} }
} }

+ 8
- 9
src/Web/WebMVC/Controllers/CartController.cs View File

@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Identity;
using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.eShopOnContainers.WebMVC.Models; using Microsoft.eShopOnContainers.WebMVC.Models;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
@ -13,21 +12,22 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
[Authorize] [Authorize]
public class CartController : Controller public class CartController : Controller
{ {
private readonly UserManager<ApplicationUser> _userManager;
private readonly IBasketService _basketSvc; private readonly IBasketService _basketSvc;
private readonly ICatalogService _catalogSvc; private readonly ICatalogService _catalogSvc;
private readonly IIdentityParser<ApplicationUser> _appUserParser;
public CartController(IBasketService basketSvc, ICatalogService catalogSvc, UserManager<ApplicationUser> userManager)
public CartController(IBasketService basketSvc, ICatalogService catalogSvc, IIdentityParser<ApplicationUser> appUserParser)
{ {
_userManager = userManager;
_basketSvc = basketSvc; _basketSvc = basketSvc;
_catalogSvc = catalogSvc; _catalogSvc = catalogSvc;
_appUserParser = appUserParser;
} }
public async Task<IActionResult> Index() public async Task<IActionResult> Index()
{ {
var user = await _userManager.GetUserAsync(HttpContext.User);
var user = _appUserParser.Parse(HttpContext.User);
var vm = await _basketSvc.GetBasket(user); var vm = await _basketSvc.GetBasket(user);
return View(vm); return View(vm);
} }
@ -36,7 +36,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
[HttpPost] [HttpPost]
public async Task<IActionResult> Index(Dictionary<string, int> quantities, string action) public async Task<IActionResult> Index(Dictionary<string, int> quantities, string action)
{ {
var user = await _userManager.GetUserAsync(HttpContext.User);
var user = _appUserParser.Parse(HttpContext.User);
var basket = await _basketSvc.SetQuantities(user, quantities); var basket = await _basketSvc.SetQuantities(user, quantities);
var vm = await _basketSvc.UpdateBasket(basket); var vm = await _basketSvc.UpdateBasket(basket);
@ -51,8 +51,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
public async Task<IActionResult> AddToCart(CatalogItem productDetails) public async Task<IActionResult> AddToCart(CatalogItem productDetails)
{ {
var user = await _userManager.GetUserAsync(HttpContext.User);
//var productDetails = _catalogSvc.GetCatalogItem(productId);
var user = _appUserParser.Parse(HttpContext.User);
var product = new BasketItem() var product = new BasketItem()
{ {
Id = Guid.NewGuid().ToString(), Id = Guid.NewGuid().ToString(),
@ -66,4 +65,4 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
return RedirectToAction("Index", "Catalog"); return RedirectToAction("Index", "Catalog");
} }
} }
}
}

+ 20
- 13
src/Web/WebMVC/Controllers/OrderController.cs View File

@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.eShopOnContainers.WebMVC.Models; using Microsoft.eShopOnContainers.WebMVC.Models;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.eShopOnContainers.WebMVC.Models.OrderViewModels; using Microsoft.eShopOnContainers.WebMVC.Models.OrderViewModels;
namespace Microsoft.eShopOnContainers.WebMVC.Controllers namespace Microsoft.eShopOnContainers.WebMVC.Controllers
@ -16,10 +15,10 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{ {
private IOrderingService _orderSvc; private IOrderingService _orderSvc;
private IBasketService _basketSvc; private IBasketService _basketSvc;
private readonly UserManager<ApplicationUser> _userManager;
public OrderController(IOrderingService orderSvc, IBasketService basketSvc, UserManager<ApplicationUser> userManager)
private readonly IIdentityParser<ApplicationUser> _appUserParser;
public OrderController(IOrderingService orderSvc, IBasketService basketSvc, IIdentityParser<ApplicationUser> appUserParser)
{ {
_userManager = userManager;
_appUserParser = appUserParser;
_orderSvc = orderSvc; _orderSvc = orderSvc;
_basketSvc = basketSvc; _basketSvc = basketSvc;
} }
@ -27,7 +26,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
public async Task<IActionResult> Create() public async Task<IActionResult> Create()
{ {
var vm = new CreateOrderViewModel(); var vm = new CreateOrderViewModel();
var user = await _userManager.GetUserAsync(HttpContext.User);
var user = _appUserParser.Parse(HttpContext.User);
var basket = await _basketSvc.GetBasket(user); var basket = await _basketSvc.GetBasket(user);
var order = _basketSvc.MapBasketToOrder(basket); var order = _basketSvc.MapBasketToOrder(basket);
vm.Order = _orderSvc.MapUserInfoIntoOrder(user, order); vm.Order = _orderSvc.MapUserInfoIntoOrder(user, order);
@ -38,7 +37,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
[HttpPost] [HttpPost]
public async Task<IActionResult> Create(CreateOrderViewModel model, Dictionary<string, int> quantities, string action) public async Task<IActionResult> Create(CreateOrderViewModel model, Dictionary<string, int> quantities, string action)
{ {
var user = await _userManager.GetUserAsync(HttpContext.User);
var user = _appUserParser.Parse(HttpContext.User);
var basket = await _basketSvc.SetQuantities(user, quantities); var basket = await _basketSvc.SetQuantities(user, quantities);
basket = await _basketSvc.UpdateBasket(basket); basket = await _basketSvc.UpdateBasket(basket);
var order = _basketSvc.MapBasketToOrder(basket); var order = _basketSvc.MapBasketToOrder(basket);
@ -48,10 +47,18 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
if (action == "[ Place Order ]") if (action == "[ Place Order ]")
{ {
_orderSvc.CreateOrder(user, order);
try
{
await _orderSvc.CreateOrder(user, order);
//Empty basket for current user.
await _basketSvc.CleanBasket(user);
//Empty basket for current user.
await _basketSvc.CleanBasket(user);
}
catch (Exception) {
//redirect to some error page if the operation fails.
return Redirect("http://www.google.com");
}
//Redirect to historic list. //Redirect to historic list.
return RedirectToAction("Index"); return RedirectToAction("Index");
@ -60,17 +67,17 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
return View(model); return View(model);
} }
public async Task<IActionResult> Detail(string orderId)
public IActionResult Detail(string orderId)
{ {
var user = await _userManager.GetUserAsync(HttpContext.User);
var user = _appUserParser.Parse(HttpContext.User);
var order = _orderSvc.GetOrder(user, orderId); var order = _orderSvc.GetOrder(user, orderId);
return View(order); return View(order);
} }
public async Task<IActionResult> Index(Order item)
public IActionResult Index(Order item)
{ {
var user = await _userManager.GetUserAsync(HttpContext.User);
var user = _appUserParser.Parse(HttpContext.User);
return View(_orderSvc.GetMyOrders(user)); return View(_orderSvc.GetMyOrders(user));
} }
} }

+ 0
- 26
src/Web/WebMVC/Data/ApplicationDbContext.cs View File

@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.eShopOnContainers.WebMVC.Models;
namespace Microsoft.eShopOnContainers.WebMVC.Data
{
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
}
}
}

+ 44
- 0
src/Web/WebMVC/Extensions/HttpClientExtensions.cs View File

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Extensions
{
public static class HttpClientExtensions
{
public static void SetBasicAuthentication(this HttpClient client, string userName, string password)
{
client.DefaultRequestHeaders.Authorization = new BasicAuthenticationHeaderValue(userName, password);
}
public static void SetToken(this HttpClient client, string scheme, string token)
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(scheme, token);
}
public static void SetBearerToken(this HttpClient client, string token)
{
client.SetToken(JwtConstants.TokenType, token);
}
}
public class BasicAuthenticationHeaderValue : AuthenticationHeaderValue
{
public BasicAuthenticationHeaderValue(string userName, string password)
: base("Basic", EncodeCredential(userName, password))
{ }
private static string EncodeCredential(string userName, string password)
{
Encoding encoding = Encoding.GetEncoding("iso-8859-1");
string credential = String.Format("{0}:{1}", userName, password);
return Convert.ToBase64String(encoding.GetBytes(credential));
}
}
}

+ 1
- 1
src/Web/WebMVC/Models/ApplicationUser.cs View File

@ -2,8 +2,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
namespace Microsoft.eShopOnContainers.WebMVC.Models namespace Microsoft.eShopOnContainers.WebMVC.Models
{ {


+ 36
- 0
src/Web/WebMVC/Models/OrderRequest.cs View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Models
{
public class OrderRequest
{
public OrderRequest() {
}
public string City { get; set; }
public string Street { get; set; }
public string State { get; set; }
public string Country { get; set; }
public string ZipCode { get; set; }
public string CardNumber { get; set; }
public string CardHolderName { get; set; }
public DateTime CardExpiration { get; set; }
public string CardSecurityNumber { get; set; }
public int CardTypeId { get; set; }
public string Buyer { get; set; }
}
}

+ 13
- 0
src/Web/WebMVC/Services/IIdentityParser.cs View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Principal;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Services
{
public interface IIdentityParser<T>
{
T Parse(IPrincipal principal);
}
}

+ 3
- 3
src/Web/WebMVC/Services/IOrderingService.cs View File

@ -8,9 +8,9 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
{ {
public interface IOrderingService public interface IOrderingService
{ {
List<Order> GetMyOrders(ApplicationUser user);
Order GetOrder(ApplicationUser user, string orderId);
void CreateOrder(ApplicationUser user, Order order);
Task<List<Order>> GetMyOrders(ApplicationUser user);
Task<Order> GetOrder(ApplicationUser user, string orderId);
Task CreateOrder(ApplicationUser user, Order order);
Order MapUserInfoIntoOrder(ApplicationUser user, Order order); Order MapUserInfoIntoOrder(ApplicationUser user, Order order);
void OverrideUserInfoIntoOrder(Order original, Order destination); void OverrideUserInfoIntoOrder(Order original, Order destination);
} }


+ 38
- 0
src/Web/WebMVC/Services/IdentityParser.cs View File

@ -0,0 +1,38 @@
using Microsoft.eShopOnContainers.WebMVC.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
namespace Microsoft.eShopOnContainers.WebMVC.Services
{
public class IdentityParser:IIdentityParser<ApplicationUser>
{
public ApplicationUser Parse(IPrincipal principal)
{
var user = new ApplicationUser();
var claims = (ClaimsPrincipal)principal;
user.CardHolderName = (claims.Claims.Where(x => x.Type == "card_holder").Count() > 0) ? claims.Claims.First(x => x.Type == "card_holder").Value : "";
user.CardNumber = (claims.Claims.Where(x => x.Type == "card_number").Count() > 0) ? claims.Claims.First(x => x.Type == "card_number").Value : "";
user.CardType = (claims.Claims.Where(x => x.Type == "missing").Count() > 0) ? int.Parse(claims.Claims.First(x => x.Type == "missing").Value) : 0;
user.City = (claims.Claims.Where(x => x.Type == "address_city").Count() > 0) ? claims.Claims.First(x => x.Type == "address_city").Value : "";
user.Country = (claims.Claims.Where(x => x.Type == "address_country").Count() > 0) ? claims.Claims.First(x => x.Type == "address_country").Value : "";
user.Email = (claims.Claims.Where(x => x.Type == "email").Count() > 0) ? claims.Claims.First(x => x.Type == "email").Value : "";
user.Id = (claims.Claims.Where(x => x.Type == "sub").Count() > 0) ? claims.Claims.First(x => x.Type == "sub").Value : "";
user.LastName = (claims.Claims.Where(x => x.Type == "last_name").Count() > 0) ? claims.Claims.First(x => x.Type == "last_name").Value : "";
user.Name = (claims.Claims.Where(x => x.Type == "name").Count() > 0) ? claims.Claims.First(x => x.Type == "name").Value : "";
user.PhoneNumber = (claims.Claims.Where(x => x.Type == "phone_number").Count() > 0) ? claims.Claims.First(x => x.Type == "phone_number").Value : "";
user.SecurityNumber = (claims.Claims.Where(x => x.Type == "card_security_number").Count() > 0) ? claims.Claims.First(x => x.Type == "card_security_number").Value : "";
user.State = (claims.Claims.Where(x => x.Type == "address_state").Count() > 0) ? claims.Claims.First(x => x.Type == "address_state").Value : "";
user.Street = (claims.Claims.Where(x => x.Type == "address_street").Count() > 0) ? claims.Claims.First(x => x.Type == "address_street").Value : "";
user.ZipCode = (claims.Claims.Where(x => x.Type == "address_zip_code").Count() > 0) ? claims.Claims.First(x => x.Type == "address_zip_code").Value : "";
return user;
}
}
}

+ 87
- 53
src/Web/WebMVC/Services/OrderingService.cs View File

@ -4,65 +4,80 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.eShopOnContainers.WebMVC.Models; using Microsoft.eShopOnContainers.WebMVC.Models;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using System.Net.Http;
using Newtonsoft.Json;
namespace Microsoft.eShopOnContainers.WebMVC.Services namespace Microsoft.eShopOnContainers.WebMVC.Services
{ {
public class OrderingService : IOrderingService public class OrderingService : IOrderingService
{ {
private List<Order> _orders;
//var ordersUrl = _settings.OrderingUrl + "/api/ordering/orders";
//var dataString = await _http.GetStringAsync(ordersUrl);
//var items = JsonConvert.DeserializeObject<List<Order>>(dataString);
private HttpClient _apiClient;
private readonly string _remoteServiceBaseUrl;
private readonly IOptions<AppSettings> _settings;
public OrderingService(IHttpContextAccessor httpContextAccessor)
public OrderingService(IOptions<AppSettings> settings)
{ {
_orders = new List<Order>()
{
new Order()
{
Id = Guid.NewGuid().ToString(),
BuyerId = new Guid("ebcbcb4c-b032-4baa-834b-7fd66d37bc95").ToString(),
OrderDate = DateTime.Now,
State = OrderState.InProcess,
OrderItems = new List<OrderItem>()
{
new OrderItem() { UnitPrice = 12.40m, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" }
}
},
new Order()
{
Id = Guid.NewGuid().ToString(),
BuyerId = new Guid("ebcbcb4c-b032-4baa-834b-7fd66d37bc95").ToString(),
OrderDate = DateTime.Now,
State = OrderState.InProcess,
OrderItems = new List<OrderItem>()
{
new OrderItem() { UnitPrice = 12.00m, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" }
}
},
new Order()
{
Id = Guid.NewGuid().ToString(),
BuyerId = new Guid("ebcbcb4c-b032-4baa-834b-7fd66d37bc95").ToString(),
OrderDate = DateTime.Now,
State = OrderState.Delivered,
OrderItems = new List<OrderItem>()
{
new OrderItem() { UnitPrice = 12.05m, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" }
}
}
};
_remoteServiceBaseUrl = $"{settings.Value.OrderingUrl}/api/v1/orders";
_settings = settings;
#region fake items
//_orders = new List<Order>()
//{
// new Order()
// {
// Id = Guid.NewGuid().ToString(),
// BuyerId = new Guid("ebcbcb4c-b032-4baa-834b-7fd66d37bc95").ToString(),
// OrderDate = DateTime.Now,
// State = OrderState.InProcess,
// OrderItems = new List<OrderItem>()
// {
// new OrderItem() { UnitPrice = 12.40m, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" }
// }
// },
// new Order()
// {
// Id = Guid.NewGuid().ToString(),
// BuyerId = new Guid("ebcbcb4c-b032-4baa-834b-7fd66d37bc95").ToString(),
// OrderDate = DateTime.Now,
// State = OrderState.InProcess,
// OrderItems = new List<OrderItem>()
// {
// new OrderItem() { UnitPrice = 12.00m, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" }
// }
// },
// new Order()
// {
// Id = Guid.NewGuid().ToString(),
// BuyerId = new Guid("ebcbcb4c-b032-4baa-834b-7fd66d37bc95").ToString(),
// OrderDate = DateTime.Now,
// State = OrderState.Delivered,
// OrderItems = new List<OrderItem>()
// {
// new OrderItem() { UnitPrice = 12.05m, PictureUrl = "https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt", Quantity = 1, ProductName="Roslyn Red T-Shirt" }
// }
// }
//};
#endregion
} }
public Order GetOrder(ApplicationUser user, string Id)
async public Task<Order> GetOrder(ApplicationUser user, string Id)
{ {
return _orders.Where(x => x.BuyerId.Equals(user.Id) && x.Id.Equals(Id)).FirstOrDefault();
_apiClient = new HttpClient();
var ordersUrl = $"{_remoteServiceBaseUrl}/{Id}";
var dataString = await _apiClient.GetStringAsync(ordersUrl);
var response = JsonConvert.DeserializeObject<Order>(dataString);
return response;
} }
public List<Order> GetMyOrders(ApplicationUser user)
async public Task<List<Order>> GetMyOrders(ApplicationUser user)
{ {
return _orders.Where(x => x.BuyerId.Equals(user.Id)).ToList();
_apiClient = new HttpClient();
var ordersUrl = _remoteServiceBaseUrl;
var dataString = await _apiClient.GetStringAsync(ordersUrl);
var response = JsonConvert.DeserializeObject<List<Order>>(dataString);
return response;
} }
public Order MapUserInfoIntoOrder(ApplicationUser user, Order order) public Order MapUserInfoIntoOrder(ApplicationUser user, Order order)
@ -80,15 +95,34 @@ namespace Microsoft.eShopOnContainers.WebMVC.Services
return order; return order;
} }
public void CreateOrder(ApplicationUser user, Order order)
public OrderRequest MapOrderIntoOrderRequest(Order order)
{
return new OrderRequest()
{
CardHolderName = order.PaymentInfo.CardHolderName,
CardNumber = order.PaymentInfo.CardNumber,
CardSecurityNumber = order.PaymentInfo.SecurityNumber,
CardTypeId = (int)order.PaymentInfo.CardType,
City = order.ShippingAddress.City,
Country = order.ShippingAddress.Country,
State = order.ShippingAddress.State,
Street = order.ShippingAddress.Street,
ZipCode = order.ShippingAddress.ZipCode
};
}
async public Task CreateOrder(ApplicationUser user, Order order)
{ {
order.OrderDate = DateTime.Now;
order.Id = Guid.NewGuid().ToString();
order.BuyerId = user.Id;
order.SequenceNumber = new Random(100).Next();
order.State = OrderState.InProcess;
_apiClient = new HttpClient();
var ordersUrl = $"{_remoteServiceBaseUrl}/new";
order.PaymentInfo.CardType = CardType.AMEX;
OrderRequest request = MapOrderIntoOrderRequest(order);
StringContent content = new StringContent(JsonConvert.SerializeObject(request), System.Text.Encoding.UTF8, "application/json");
var response = await _apiClient.PostAsync(ordersUrl, content);
_orders.Add(order);
if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
throw new Exception("Error creating order, try later");
} }
public void OverrideUserInfoIntoOrder(Order original, Order destination) public void OverrideUserInfoIntoOrder(Order original, Order destination)


+ 50
- 10
src/Web/WebMVC/Startup.cs View File

@ -4,14 +4,13 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.eShopOnContainers.WebMVC.Data;
using Microsoft.eShopOnContainers.WebMVC.Models; using Microsoft.eShopOnContainers.WebMVC.Models;
using Microsoft.eShopOnContainers.WebMVC.Services; using Microsoft.eShopOnContainers.WebMVC.Services;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.IdentityModel.Tokens;
namespace Microsoft.eShopOnContainers.WebMVC namespace Microsoft.eShopOnContainers.WebMVC
{ {
@ -40,12 +39,12 @@ namespace Microsoft.eShopOnContainers.WebMVC
public void ConfigureServices(IServiceCollection services) public void ConfigureServices(IServiceCollection services)
{ {
// Add framework services. // Add framework services.
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
//services.AddDbContext<ApplicationDbContext>(options =>
// options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
//services.AddIdentity<ApplicationUser, IdentityRole>()
// .AddEntityFrameworkStores<ApplicationDbContext>()
// .AddDefaultTokenProviders();
services.AddMvc(); services.AddMvc();
@ -53,6 +52,7 @@ namespace Microsoft.eShopOnContainers.WebMVC
services.AddTransient<ICatalogService, CatalogService>(); services.AddTransient<ICatalogService, CatalogService>();
services.AddSingleton<IOrderingService, OrderingService>(); //CCE: Once services are integrated, a singleton is not needed we can left transient. services.AddSingleton<IOrderingService, OrderingService>(); //CCE: Once services are integrated, a singleton is not needed we can left transient.
services.AddTransient<IBasketService, BasketService>(); services.AddTransient<IBasketService, BasketService>();
services.AddTransient<IIdentityParser<ApplicationUser>, IdentityParser>();
services.Configure<AppSettings>(Configuration); services.Configure<AppSettings>(Configuration);
} }
@ -60,13 +60,14 @@ namespace Microsoft.eShopOnContainers.WebMVC
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{ {
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug(); loggerFactory.AddDebug();
if (env.IsDevelopment()) if (env.IsDevelopment())
{ {
app.UseDeveloperExceptionPage(); app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseBrowserLink(); app.UseBrowserLink();
} }
else else
@ -76,7 +77,46 @@ namespace Microsoft.eShopOnContainers.WebMVC
app.UseStaticFiles(); app.UseStaticFiles();
app.UseIdentity();
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationScheme = "cookies",
AutomaticAuthenticate = true,
});
//app.UseIdentity();
var oidcOptions = new OpenIdConnectOptions
{
AuthenticationScheme = "oidc",
SignInScheme = "cookies",
Authority = "http://localhost:5000",
ClientId = "mvc",
ClientSecret = "secret",
ResponseType = "code id_token",
SaveTokens = true,
GetClaimsFromUserInfoEndpoint = true,
RequireHttpsMetadata = false,
//TokenValidationParameters = new TokenValidationParameters
//{
// NameClaimType = "name",
// RoleClaimType = "role"
//}
};
oidcOptions.Scope.Clear();
oidcOptions.Scope.Add("openid");
oidcOptions.Scope.Add("profile");
oidcOptions.Scope.Add("orders");
app.UseOpenIdConnectAuthentication(oidcOptions);
app.UseJwtBearerAuthentication(new JwtBearerOptions
{
Authority = "http://localhost:5000/", // base address of your OIDC server.
Audience = "http://localhost:5000/", // base address of your API.
RequireHttpsMetadata = false
});
app.UseMvc(routes => app.UseMvc(routes =>
{ {


+ 4
- 2
src/Web/WebMVC/Views/Cart/Index.cshtml View File

@ -1,5 +1,7 @@
@using Microsoft.eShopOnContainers.WebMVC.Services
@model Microsoft.eShopOnContainers.WebMVC.Models.Basket @model Microsoft.eShopOnContainers.WebMVC.Models.Basket
@inject UserManager<ApplicationUser> UserManager
@inject IIdentityParser<ApplicationUser> UserManager
@{ @{
ViewData["Title"] = "My Cart"; ViewData["Title"] = "My Cart";
@ -14,7 +16,7 @@
<form method="post" id="cartForm"> <form method="post" id="cartForm">
<div class="container cart-index-container"> <div class="container cart-index-container">
<div class="row"> <div class="row">
@await Component.InvokeAsync("CartList", new { user = await UserManager.GetUserAsync(User) })
@await Component.InvokeAsync("CartList", new { user = UserManager.Parse(User) })
<div class="col-md-offset-8 col-md-4"> <div class="col-md-offset-8 col-md-4">
<input type="submit" <input type="submit"
class="btn btn-default btn-brand btn-cart" class="btn btn-default btn-brand btn-cart"


+ 3
- 2
src/Web/WebMVC/Views/Order/Create.cshtml View File

@ -1,5 +1,6 @@
@using Microsoft.eShopOnContainers.WebMVC.Services
@model Microsoft.eShopOnContainers.WebMVC.Models.OrderViewModels.CreateOrderViewModel @model Microsoft.eShopOnContainers.WebMVC.Models.OrderViewModels.CreateOrderViewModel
@inject UserManager<ApplicationUser> UserManager
@inject IIdentityParser<ApplicationUser> UserManager
@{ @{
ViewData["Title"] = "New Order"; ViewData["Title"] = "New Order";
@ -65,7 +66,7 @@
<br /><br /> <br /><br />
<div class="col-md-12 order-create-section-items"> <div class="col-md-12 order-create-section-items">
<section> <section>
@await Component.InvokeAsync("CartList", new { user = await UserManager.GetUserAsync(User) })
@await Component.InvokeAsync("CartList", new { user = UserManager.Parse(User) })
</section> </section>
</div> </div>
<div class="form-group"> <div class="form-group">


+ 3
- 0
src/Web/WebMVC/Views/Shared/_Layout.cshtml View File

@ -27,6 +27,9 @@
</a> </a>
</div> </div>
<div class="navbar-header col-sm-6 col-xs-4 text-center"> <div class="navbar-header col-sm-6 col-xs-4 text-center">
@*@Html.ActionLink("Claims", "Claims", "Account")
@Html.ActionLink("Call Api", "Claims", "Account")
@Html.ActionLink("Log Out", "Signout", "Account")*@
@await Html.PartialAsync("_LoginPartial") @await Html.PartialAsync("_LoginPartial")
</div> </div>
</div> </div>


+ 6
- 6
src/Web/WebMVC/Views/Shared/_LoginPartial.cshtml View File

@ -1,16 +1,16 @@
@using Microsoft.AspNetCore.Identity @using Microsoft.AspNetCore.Identity
@using Microsoft.eShopOnContainers.WebMVC.Models @using Microsoft.eShopOnContainers.WebMVC.Models
@using Microsoft.eShopOnContainers.WebMVC.Services
@inject SignInManager<ApplicationUser> SignInManager
@inject UserManager<ApplicationUser> UserManager
@inject IIdentityParser<ApplicationUser> UserManager
@if (SignInManager.IsSignedIn(User))
@if(Context.User.Identity.IsAuthenticated)
{ {
<form asp-area="" asp-controller="Account" asp-action="LogOff" method="post" id="logoutForm" class="navbar-right"> <form asp-area="" asp-controller="Account" asp-action="LogOff" method="post" id="logoutForm" class="navbar-right">
<div class="nav navbar-nav navbar-right mt-15"> <div class="nav navbar-nav navbar-right mt-15">
@await Component.InvokeAsync("Cart", new { user = await UserManager.GetUserAsync(User) })
@await Component.InvokeAsync("Cart", new { user = UserManager.Parse(User) })
<div class="fr login-user"> <div class="fr login-user">
<span class="hidden-xs">@UserManager.GetUserName(User)</span>
<span class="hidden-xs">@User.FindFirst(x => x.Type == "preferred_username").Value</span>
<i class="down-arrow"></i> <i class="down-arrow"></i>
<div class="login-user-dropdown-content"> <div class="login-user-dropdown-content">
<a asp-controller="Order" asp-action="Index">MY ORDERS<i class="myorders-icon"></i></a> <a asp-controller="Order" asp-action="Index">MY ORDERS<i class="myorders-icon"></i></a>
@ -23,6 +23,6 @@
else else
{ {
<ul class="nav navbar-nav navbar-right"> <ul class="nav navbar-nav navbar-right">
<li><a asp-area="" asp-controller="Account" class="btn-login" asp-action="Login">&nbsp;Log In&nbsp;</a></li>
<li><a asp-area="" asp-controller="Account" class="btn-login" asp-action="SignIn">&nbsp;Log In&nbsp;</a></li>
</ul> </ul>
} }

+ 4
- 4
src/Web/WebMVC/appsettings.json View File

@ -1,12 +1,12 @@
{ {
"ConnectionStrings": { "ConnectionStrings": {
//"DefaultConnection": "Server=127.0.0.1,5433;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word"
"DefaultConnection": "Server=identity.data;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word"
"DefaultConnection": "Server=127.0.0.1,5433;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word"
//"DefaultConnection": "Server=identity.data;Database=aspnet-Microsoft.eShopOnContainers.WebMVC;User Id=sa;Password=Pass@word"
}, },
"CatalogUrl": "http://localhost:5101", "CatalogUrl": "http://localhost:5101",
"OrderingUrl": "http://localhost:5102/",
"OrderingUrl": "http://localhost:2446",
"BasketUrl": "http://localhost:5103", "BasketUrl": "http://localhost:5103",
"IdentityUrl": "http://localhost:5104",
"IdentityUrl": "http://localhost:5000",
"Logging": { "Logging": {
"IncludeScopes": false, "IncludeScopes": false,
"LogLevel": { "LogLevel": {


+ 5
- 14
src/Web/WebMVC/project.json View File

@ -7,10 +7,7 @@
}, },
"Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", "Microsoft.AspNetCore.Authentication.Cookies": "1.0.0",
"Microsoft.AspNetCore.Diagnostics": "1.0.0", "Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0",
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0", "Microsoft.AspNetCore.Mvc": "1.0.0",
"Microsoft.AspNetCore.Session": "1.0.0",
"Microsoft.AspNetCore.Razor.Tools": { "Microsoft.AspNetCore.Razor.Tools": {
"version": "1.0.0-preview2-final", "version": "1.0.0-preview2-final",
"type": "build" "type": "build"
@ -18,15 +15,6 @@
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0", "Microsoft.AspNetCore.Server.Kestrel": "1.0.0",
"Microsoft.AspNetCore.StaticFiles": "1.0.0", "Microsoft.AspNetCore.StaticFiles": "1.0.0",
"Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
"Microsoft.EntityFrameworkCore.SqlServer.Design": {
"version": "1.0.0",
"type": "build"
},
"Microsoft.EntityFrameworkCore.Tools": {
"version": "1.0.0-preview2-final",
"type": "build"
},
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0",
"Microsoft.Extensions.Configuration.Json": "1.0.0", "Microsoft.Extensions.Configuration.Json": "1.0.0",
"Microsoft.Extensions.Configuration.UserSecrets": "1.0.0", "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0",
@ -43,13 +31,16 @@
"version": "1.0.0-preview2-final", "version": "1.0.0-preview2-final",
"type": "build" "type": "build"
}, },
"Newtonsoft.Json": "9.0.1"
"Newtonsoft.Json": "9.0.1",
"System.IdentityModel.Tokens.Jwt": "5.0.0",
"Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.0.0",
"Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0",
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0"
}, },
"tools": { "tools": {
"BundlerMinifier.Core": "2.0.238", "BundlerMinifier.Core": "2.0.238",
"Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final", "Microsoft.AspNetCore.Razor.Tools": "1.0.0-preview2-final",
"Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final", "Microsoft.AspNetCore.Server.IISIntegration.Tools": "1.0.0-preview2-final",
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
"Microsoft.Extensions.SecretManager.Tools": "1.0.0-preview2-final", "Microsoft.Extensions.SecretManager.Tools": "1.0.0-preview2-final",
"Microsoft.VisualStudio.Web.CodeGeneration.Tools": { "Microsoft.VisualStudio.Web.CodeGeneration.Tools": {
"version": "1.0.0-preview2-final", "version": "1.0.0-preview2-final",


Loading…
Cancel
Save