Adding basic user form authentication

Great! You have registered the authentication middleware and prepared the database. In the next step, you are going to implement basic user authentication for the Tic-Tac-Toe application.

The following example demonstrates how to modify the user registration and add a simple login form with a user login and password textbox for authenticating users:

  1. Add a new model called LoginModel to the Models folder:
        public class LoginModel 
        { 
          [Required] 
          public string UserName { get; set; } 
          [Required] 
          public string Password { get; set; } 
          public string ReturnUrl { get; set; } 
        }
  1. Add a new folder called Account to the Views folder, and then add a new file called Login.cshtml within this new folder. It will contain the login view:
        @model TicTacToe.Models.LoginModel 
        <div class="container"> 
          <div id="loginbox" style="margin-top:50px;"
class="mainbox
col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2"> <div class="panel panel-info"> <div class="panel-heading"> <div class="panel-title">Sign In</div> </div> <div style="padding-top:30px" class="panel-body"> <div style="display:none" id="login-alert"
class="alert alert-danger col-sm-12"></div> <form id="loginform" class="form-horizontal"
role="form" asp-action="Login" asp-
controller="Account"> <input type="hidden" asp-for="ReturnUrl" /> <div asp-validation-summary="ModelOnly"
class="text-danger"></div> <div style="margin-bottom: 25px" class="input-
group"> <span class="input-group-addon"><i
class="glyphicon
glyphicon-user"></i></span> <input type="text" class="form-control"
asp-for="UserName" value=""
placeholder="username
or email"> </div> <div style="margin-bottom: 25px" class="input-
group"> <span class="input-group-addon"><i
class="glyphicon
glyphicon-lock"></i></span> <input type="password" class="form-control"
asp-for="Password" placeholder="password"> </div> <div style="margin-top:10px" class="form-group"> <div class="col-sm-12 controls"> <button type="submit" id="btn-login" href="#"
class="btn btn-success">Login</button> </div> </div> <div class="form-group"> <div class="col-md-12 control"> <div style="border-top: 1px solid#888;
padding-top:15px; font-size:85%"> Don't have an account? <a asp-action="Index"
asp-controller="UserRegistration">Sign Up
Here
</a> </div> </div> </div> </form> </div> </div> </div> </div>
  1. Update UserService, add a SignInManager private field, and then update the constructor:
        ... 
        private SignInManager<UserModel> _signInManager; 
        public UserService(ApplicationUserManager userManager,
ILogger<UserService> logger, SignInManager<UserModel>
signInManager) { ... _signInManager = signInManager; ... } ...
  1. Add a new method called SignInUser to UserService:
public async Task<SignInResult> SignInUser( LoginModel loginModel, HttpContext httpContext)
{
_logger.LogTrace($"signin user {loginModel.UserName}");

var stopwatch = new Stopwatch(); stopwatch.Start();
try
{
var user = await _userManager.FindByNameAsync
(loginModel.UserName);
var isValid = await _signInManager.CheckPasswordSignInAsync
(user, loginModel.Password, true);
if (!isValid.Succeeded) return SignInResult.Failed;

if (!await _userManager.IsEmailConfirmedAsync(user))
return SignInResult.NotAllowed;

var identity = new ClaimsIdentity
(CookieAuthenticationDefaults.AuthenticationScheme);
identity.AddClaim(new Claim(ClaimTypes.Name,
loginModel.UserName));
identity.AddClaim(new Claim(ClaimTypes.GivenName,
user.FirstName));
identity.AddClaim(new Claim(ClaimTypes.Surname,
user.LastName));
identity.AddClaim(new Claim("displayName", $"
{user.FirstName} {user.LastName}"));

if (!string.IsNullOrEmpty(user.PhoneNumber))
identity.AddClaim(new Claim(ClaimTypes.HomePhone,
user.PhoneNumber));

identity.AddClaim(new Claim("Score", user.Score.
ToString()));

await httpContext.SignInAsync(CookieAuthenticationDefaults.
AuthenticationScheme,
new ClaimsPrincipal(identity), new AuthenticationProperties {
IsPersistent = false });

return isValid;
}
catch (Exception ex)
{
_logger.LogError($"cannot sign in user{ loginModel.UserName} - {
ex} ");
throw ex;
}
finally
{
stopwatch.Stop();
_logger.LogTrace($"sign in user {loginModel.UserName} finished
in
{ stopwatch.Elapsed} ");
}
}

Add another method, SignOutUser, to UserService and update the user service interface: 

public async Task SignOutUser(HttpContext httpContext) 
        { 
          await _signInManager.SignOutAsync(); 
          await httpContext.SignOutAsync(new 
AuthenticationProperties {
IsPersistent = false }); return; }
  1. Add a new controller called AccountController to the Controllers folder: 
public class AccountController : Controller 
        { 
          private IUserService _userService; 
          public AccountController(IUserService userService) 
          { 
            _userService = userService; 
          } 
         }

Let's perform the steps as follows:  

    1. Implement a new Login method in AccountController as follows:
 
         public async Task<IActionResult> Login(string returnUrl) 
          { 
            return await Task.Run(() => 
            { 
              var loginModel = new LoginModel { ReturnUrl = 
returnUrl }; return View(loginModel); }); } ...
    1. Add another implementation of the Login method that takes in a login model as a parameter:
[HttpPost] 
public async Task<IActionResult> Login(LoginModel loginModel) 
{ 
  if (ModelState.IsValid) 
   { 
    var result = await _userService.SignInUser(loginModel, 
HttpContext); if (result.Succeeded) { if (!string.IsNullOrEmpty(loginModel.ReturnUrl)) return Redirect(loginModel.ReturnUrl); else return RedirectToAction("Index", "Home"); } else ModelState.AddModelError("", result.IsLockedOut ?"User
is locked" : "User is not allowed"); } return View(); }
    1. Add a new Logout method as follows: 
          public IActionResult Logout() 
          { 
            _userService.SignOutUser(HttpContext).Wait(); 
            HttpContext.Session.Clear(); 
            return RedirectToAction("Index", "Home"); 
          } 
  1. Update the Views/Shared/_Menu.cshtml file, and replace the existing code block at the top of the method:
        @using Microsoft.AspNetCore.Http; 
        @{ 
          var email = User?.Identity?.Name ??  
Context.Session.GetString("email"); var displayName = User.Claims.FirstOrDefault(
x => x.Type == "displayName")?.Value ??
Context.Session.GetString("displayName"); }
  1. Update the Views/Shared/_Menu.cshtml file to display either a display name element for already authenticated users or a login element for an authenticated user; for that, replace the final <li> element:
        <li> 
          @if (!string.IsNullOrEmpty(email)) 
          { 
            Html.RenderPartial("_Account",
new TicTacToe.Models.AccountModel { Email = email,
DisplayName = displayName }); } else { <a asp-area="" asp-controller="Account"
asp-action="Login">Login</a> } </li>
  1. Update the Views/Shared/_Account.cshtml file, and replace the Log Off and View Details links:
        <a class="btn btn-danger btn-block" asp-controller="Account"
asp-action="Logout" asp-area="">Log Off</a> <a class="btn btn-default btn-block" asp-action="Index"
asp-controller="Home" asp-area="Account">View Details</a>
  1. Go to the ViewsSharedComponentsGameSession folder, and update the default.cshtml file to improve the visual representation by having our table as follows:
... 
<table> @for (int rows = 0; rows < 3; rows++) { <tr style="height:150px;"> @for (int columns = 0; columns < 3; columns++) { <td style="width:150px; border:1px solid #808080;text-
align:center; vertical-align:middle"
id="@($"c_{rows}_{columns}")"> @{ var position = Model.Turns?.FirstOrDefault(turn =>
turn.X == columns && turn.Y == rows); if (position != null) { if (position.User == Model.User1) <i class="glyphicon glyphicon-unchecked"></i> else <i class="glyphicon glyphicon-remove-circle"></i> } else { <a class="btn btn-default btn-SetPosition"style=
"width:150px; min-height:150px;"
data-X="@columns" data-Y="@rows"> &nbsp; </a> } } </td> } </tr> } </table> ...
  1. Start the application, click on the Login element in the top menu, and sign in as an existing user (or register as a user if you have not done so previously):

  1. Click the Log Off button. You should be logged off and get redirected back to the Home page:

That essentially makes up our forms authentication, where we have been able to sign a user in and out with a login form. In the next section, we will look at how we can add an external provider as a means of authentication to our application.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.150.123