9 changed files with 215 additions and 2 deletions
@ -0,0 +1,21 @@ |
|||||
|
using System; |
||||
|
using Microsoft.AspNetCore.Hosting; |
||||
|
using Microsoft.AspNetCore.Identity; |
||||
|
using Microsoft.AspNetCore.Identity.UI; |
||||
|
using Microsoft.EntityFrameworkCore; |
||||
|
using Microsoft.eShopWeb.Infrastructure.Identity; |
||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
|
||||
|
[assembly: HostingStartup(typeof(Microsoft.eShopWeb.Web.Areas.Identity.IdentityHostingStartup))] |
||||
|
namespace Microsoft.eShopWeb.Web.Areas.Identity |
||||
|
{ |
||||
|
public class IdentityHostingStartup : IHostingStartup |
||||
|
{ |
||||
|
public void Configure(IWebHostBuilder builder) |
||||
|
{ |
||||
|
builder.ConfigureServices((context, services) => { |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,63 @@ |
|||||
|
@page |
||||
|
@model LoginModel |
||||
|
|
||||
|
@{ |
||||
|
ViewData["Title"] = "Log in"; |
||||
|
} |
||||
|
|
||||
|
<h2>@ViewData["Title"]</h2> |
||||
|
<div class="container" account-login-container> |
||||
|
<div class="row"> |
||||
|
<div class="col-md-12"> |
||||
|
<section> |
||||
|
<form method="post"> |
||||
|
<h4>Use a local account to log in.</h4> |
||||
|
<hr /> |
||||
|
<div asp-validation-summary="All" class="text-danger"></div> |
||||
|
<div class="form-group"> |
||||
|
<label asp-for="Input.Email"></label> |
||||
|
<input asp-for="Input.Email" class="form-control" /> |
||||
|
<span asp-validation-for="Input.Email" class="text-danger"></span> |
||||
|
</div> |
||||
|
<div class="form-group"> |
||||
|
<label asp-for="Input.Password"></label> |
||||
|
<input asp-for="Input.Password" class="form-control" /> |
||||
|
<span asp-validation-for="Input.Password" class="text-danger"></span> |
||||
|
</div> |
||||
|
<div class="form-group"> |
||||
|
<div class="checkbox"> |
||||
|
<label asp-for="Input.RememberMe"> |
||||
|
<input asp-for="Input.RememberMe" /> |
||||
|
@Html.DisplayNameFor(m => m.Input.RememberMe) |
||||
|
</label> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="form-group"> |
||||
|
<button type="submit" class="btn btn-default">Log in</button> |
||||
|
</div> |
||||
|
<div class="form-group"> |
||||
|
<p> |
||||
|
<a asp-page="./ForgotPassword">Forgot your password?</a> |
||||
|
</p> |
||||
|
<p> |
||||
|
<a asp-page="./Register" asp-route-returnUrl="@Model.ReturnUrl">Register as a new user</a> |
||||
|
</p> |
||||
|
</div> |
||||
|
<p> |
||||
|
Note that for demo purposes you don't need to register and can login with these credentials: |
||||
|
</p> |
||||
|
<p> |
||||
|
User: <b>demouser@microsoft.com</b> |
||||
|
</p> |
||||
|
<p> |
||||
|
Password: <b>Pass@word1</b> |
||||
|
</p> |
||||
|
</form> |
||||
|
</section> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
@section Scripts { |
||||
|
<partial name="_ValidationScriptsPartial" /> |
||||
|
} |
||||
@ -0,0 +1,103 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.ComponentModel.DataAnnotations; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Authorization; |
||||
|
using Microsoft.AspNetCore.Authentication; |
||||
|
using Microsoft.AspNetCore.Identity; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.AspNetCore.Mvc.RazorPages; |
||||
|
using Microsoft.eShopWeb.Infrastructure.Identity; |
||||
|
using Microsoft.Extensions.Logging; |
||||
|
|
||||
|
namespace Microsoft.eShopWeb.Web.Areas.Identity.Pages.Account |
||||
|
{ |
||||
|
[AllowAnonymous] |
||||
|
public class LoginModel : PageModel |
||||
|
{ |
||||
|
private readonly SignInManager<ApplicationUser> _signInManager; |
||||
|
private readonly ILogger<LoginModel> _logger; |
||||
|
|
||||
|
public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger) |
||||
|
{ |
||||
|
_signInManager = signInManager; |
||||
|
_logger = logger; |
||||
|
} |
||||
|
|
||||
|
[BindProperty] |
||||
|
public InputModel Input { get; set; } |
||||
|
|
||||
|
public IList<AuthenticationScheme> ExternalLogins { get; set; } |
||||
|
|
||||
|
public string ReturnUrl { get; set; } |
||||
|
|
||||
|
[TempData] |
||||
|
public string ErrorMessage { get; set; } |
||||
|
|
||||
|
public class InputModel |
||||
|
{ |
||||
|
[Required] |
||||
|
[EmailAddress] |
||||
|
public string Email { get; set; } |
||||
|
|
||||
|
[Required] |
||||
|
[DataType(DataType.Password)] |
||||
|
public string Password { get; set; } |
||||
|
|
||||
|
[Display(Name = "Remember me?")] |
||||
|
public bool RememberMe { get; set; } |
||||
|
} |
||||
|
|
||||
|
public async Task OnGetAsync(string returnUrl = null) |
||||
|
{ |
||||
|
if (!string.IsNullOrEmpty(ErrorMessage)) |
||||
|
{ |
||||
|
ModelState.AddModelError(string.Empty, ErrorMessage); |
||||
|
} |
||||
|
|
||||
|
returnUrl = returnUrl ?? Url.Content("~/"); |
||||
|
|
||||
|
// Clear the existing external cookie to ensure a clean login process
|
||||
|
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); |
||||
|
|
||||
|
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); |
||||
|
|
||||
|
ReturnUrl = returnUrl; |
||||
|
} |
||||
|
|
||||
|
public async Task<IActionResult> OnPostAsync(string returnUrl = null) |
||||
|
{ |
||||
|
returnUrl = returnUrl ?? Url.Content("~/"); |
||||
|
|
||||
|
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(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true); |
||||
|
if (result.Succeeded) |
||||
|
{ |
||||
|
_logger.LogInformation("User logged in."); |
||||
|
return LocalRedirect(returnUrl); |
||||
|
} |
||||
|
if (result.RequiresTwoFactor) |
||||
|
{ |
||||
|
return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe }); |
||||
|
} |
||||
|
if (result.IsLockedOut) |
||||
|
{ |
||||
|
_logger.LogWarning("User account locked out."); |
||||
|
return RedirectToPage("./Lockout"); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
ModelState.AddModelError(string.Empty, "Invalid login attempt."); |
||||
|
return Page(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// If we got this far, something failed, redisplay form
|
||||
|
return Page(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1 @@ |
|||||
|
@using Microsoft.eShopWeb.Web.Areas.Identity.Pages.Account |
||||
@ -0,0 +1,18 @@ |
|||||
|
<environment include="Development"> |
||||
|
<script src="~/Identity/lib/jquery-validation/dist/jquery.validate.js"></script> |
||||
|
<script src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script> |
||||
|
</environment> |
||||
|
<environment exclude="Development"> |
||||
|
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.17.0/jquery.validate.min.js" |
||||
|
asp-fallback-src="~/Identity/lib/jquery-validation/dist/jquery.validate.min.js" |
||||
|
asp-fallback-test="window.jQuery && window.jQuery.validator" |
||||
|
crossorigin="anonymous" |
||||
|
integrity="sha384-rZfj/ogBloos6wzLGpPkkOr/gpkBNLZ6b6yLy4o+ok+t/SAKlL5mvXLr0OXNi1Hp"> |
||||
|
</script> |
||||
|
<script src="https://ajax.aspnetcdn.com/ajax/jquery.validation.unobtrusive/3.2.9/jquery.validate.unobtrusive.min.js" |
||||
|
asp-fallback-src="~/Identity/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js" |
||||
|
asp-fallback-test="window.jQuery && window.jQuery.validator && window.jQuery.validator.unobtrusive" |
||||
|
crossorigin="anonymous" |
||||
|
integrity="sha384-ifv0TYDWxBHzvAk2Z0n8R434FL1Rlv/Av18DXE43N/1rvHyOG4izKst0f2iSLdds"> |
||||
|
</script> |
||||
|
</environment> |
||||
@ -0,0 +1,5 @@ |
|||||
|
@using Microsoft.AspNetCore.Identity |
||||
|
@using Microsoft.eShopWeb.Web.Areas.Identity |
||||
|
@using Microsoft.eShopWeb.Infrastructure.Identity |
||||
|
@namespace Microsoft.eShopWeb.Web.Areas.Identity.Pages |
||||
|
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers |
||||
Loading…
Reference in new issue