简体   繁体   中英

Html page loading causing Javascript to not function properly in redirected page

I am having this issue with my home button not adding headers in a get request. I have stored a token inside of the localStorage and I send it in the headers when I make a get request to Controller: Home Action: Index. From what I see, it doesn't use my jquery and goes straight to the Account/Index.

Initially, I though it was a problem with the javascript not binding to a button click. After further investigation, I found that the Console.log() I have in _Layout.cshtml do not work and neither does the button. This leads me to believe there is a problem with $("html").html(response); in the Login.js file.

The correct flow is LoginPage -> Login.js (grabs data and uses Ajax for a post request.) -> Returns a html page composing of _Layout.cshtml and /Views/Home/Index.cshtml

Below is my code for the file "Views/Shared/_Layout.cshtml":

 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Chat </title> <environment include="Development"> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" /> <link rel="stylesheet" href="~/css/site.css" /> </environment> <environment exclude="Development"> <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css" asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css" asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" /> <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" /> </environment> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li id="li_btnHome"><a asp-area="" asp-controller="" asp-action="">Home</a></li> </ul> </div> </div> </nav> <div class="container body-content"> @RenderBody() <hr /> <footer> <p>&copy; 2018 - Chat</p> </footer> </div> <environment include="Development"> <script src="~/lib/jquery/dist/jquery.js"></script> <script src="~/lib/bootstrap/dist/js/bootstrap.js"></script> <script src="~/js/site.js" asp-append-version="true"></script> <script type="text/javascript"> console.log("Development"); </script> </environment> <environment exclude="Development"> <script src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-3.3.1.min.js" asp-fallback-src="~/lib/jquery/dist/jquery.min.js" asp-fallback-test="window.jQuery" crossorigin="anonymous" integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT"> </script> <script src="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/bootstrap.min.js" asp-fallback-src="~/lib/bootstrap/dist/js/bootstrap.min.js" asp-fallback-test="window.jQuery && window.jQuery.fn && window.jQuery.fn.modal" crossorigin="anonymous" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa"> </script> <script src="~/js/site.min.js" asp-append-version="true"></script> <script type="text/javascript"> console.log("Not Development"); </script> </environment> <script type="text/javascript"> console.log("Hello World"); </script> <!--<script src="~/js/NavBarFunction.js"></script>--> @RenderSection("Scripts", required: false) </body> </html> 

Here's the javascript file "wwwroot/js/NavBarFunctions.js":

  $("#li_btnHome a")[0].onclick = function (event) { event.preventDefault(); alert("called click"); var tokenObj = localStorage.getItem("token"); var tokenStr = tokenObj == null ? "what_about_tokenObj_is_null?" : tokenObj.toString(); $.ajax({ type: 'GET', contentType: 'application/json; charset=utf-8;', url: '@Url.Action("Index", "Home")', beforeSend: function (xhr) { xhr.setRequestHeader("Authorization", tokenStr); }, success: function (response) { alert(1); $("html").html(response); } }); return false; }; 

Here's the HomeController, located in "Controllers/HomeController":

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Chat.Enums;
using Chat.Identity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;

namespace _Chat.Controllers
{
    public class HomeController : Controller
    {
        private AuthenticateUser authenticateUser = new AuthenticateUser();

        public async Task<IActionResult> Index()
        {
            var request = Request;
            var headers = request.Headers;

            StringValues token;
            if (headers.TryGetValue("Authorization", out token))
            {
                var result = await this.authenticateUser.ValidateToken(token);
                if (result.Result == AuthenticateResult.Success)
                {
                    return View();
                }
                else
                {
                    return RedirectToAction("Index", "Account");
                }
            }

            return RedirectToAction("Index", "Account");
        }
    }
}

For some odd reason, it looks like after my page is redirected from log in to home, all scripts/javascript stop working.

Here's the code authenticating login. Located in "Controllers/AccountController":

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Chat.Models;
using Chat.DatabaseAccessObject;
using Chat.Identity;
using Chat.DatabaseAccessObject.CommandObjects;
using System.Linq.Expressions;
using System.Net.Mime;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.Authentication;
using Microsoft.IdentityModel.Tokens;

namespace Chat.Controllers
{
    public class AccountController : Controller
    {
        private const string SECRET_KEY = "CHATSECRETKEY";
        public static SymmetricSecurityKey SIGNING_KEY = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SECRET_KEY));
        private ServerToStorageFacade serverToStorageFacade = new ServerToStorageFacade();
        private AuthenticateUser authenticateUser = new AuthenticateUser();

        public IActionResult Index()
        {
            return View();
        }

        // Post: /login/
        [HttpPost]
        public async Task<IActionResult> Login([FromBody]LoginModel loginModel)
        {
            if (ModelState.IsValid)
            {
                var mapLoginModelToUser = new MapLoginModelToUser();
                var user = await mapLoginModelToUser.MapObject(loginModel);

                // If login user with those credentials does not exist
                if(user == null)
                {
                    return BadRequest();
                }

                else
                {
                    var result = await this.authenticateUser.Authenticate(user);

                    if(result.Result == Chat.Enums.AuthenticateResult.Success)
                    {
                        // SUCCESSFUL LOGIN
                        // Creating and storing cookies

                        var token = Json(new
                        {
                            data = this.GenerateToken(user.Email, user.PantherID),
                            redirectUrl = Url.Action("Index","Home"),
                            success = true
                        });
                        return Ok(token);
                    }
                    else
                    {
                        // Unsuccessful login
                        return Unauthorized();
                    }
                }
            }

            return BadRequest();
        }

        private string GenerateToken(string email, string pantherId)
        {
            var claimsData = new[] { new Claim(ClaimTypes.Email, email), new Claim(ClaimTypes.Actor, pantherId) };

            var signInCredentials = new SigningCredentials(SIGNING_KEY, SecurityAlgorithms.HmacSha256);
            var token = new JwtSecurityToken(
                issuer: "localhost",
                audience: "localhost",
                expires: DateTime.Now.AddDays(7),
                claims: claimsData,
                signingCredentials: signInCredentials
            );

            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public async Task<IActionResult> Error() => View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
    }

    public class MapLoginModelToUser
    {
        private ServerToStorageFacade serverToStorageFacade;

        public MapLoginModelToUser()
        {
            serverToStorageFacade = new ServerToStorageFacade();
        }


        public async Task<User> MapObject(LoginModel loginModel)
        {
            Expression<Func<User, bool>> expression = x => x.Email == loginModel.inputEmail;

            var user = await this.serverToStorageFacade.ReadObjectByExpression(new User(Guid.NewGuid()), expression);

            if(user == default(Command))
            {
                return null;
            }

            return new User(user.ID)
            {
                Email = loginModel.inputEmail,
                Password = loginModel.inputPassword,
                FirstName = user.FirstName,
                LastName = user.LastName,
                PantherID = user.PantherID,
                ClassDictionary = user.ClassDictionary,
                UserEntitlement = user.UserEntitlement
            };
        }
    }
}

Also the code that renders the page. Located in "wwwroot/js/Login.js":

$(document).ready(function () {
    $("#formSubmit").submit(function (event) {
        event.preventDefault();
        var email = $("#inputEmail").val();
        var password = $("#inputPassword").val();
        var remember = $("#rememberMe").val();
        var loginModel = {
            inputEmail: email,
            inputPassword: password,
            rememberMe: remember
        };

        $.ajax({
            type: 'POST',
            url: 'Account/Login',
            data: JSON.stringify(loginModel),
            contentType: 'application/json; charset=utf-8;',
            success: function (response) {
                var token = response.value.data;
                localStorage.setItem("token", token);
                alert("You have successfully logged in.");
                setHeader();
                redirect(response.value.redirectUrl);
            }
        });
    });

    function setHeader() {
        $.ajaxSetup({
            beforeSend: function (xhr) {
                xhr.setRequestHeader('Authorization', localStorage.getItem("token"));
            }
        });
    }

    function redirect(redirectUrl) {
        $.ajax({
            type: 'GET',
            contentType: 'application/json; charset=utf-8;',
            url: redirectUrl,
            success: function (response) {
                $("html").html(response);
            }
        });    
    }
});

This is the error received after loading the new html page: 控制台重定向错误

EDIT: This is what's sent in the response after the Home button is clicked.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Login - Chat FIU</title>


            <link rel="stylesheet" href="/lib/bootstrap/dist/css/bootstrap.css" />
            <link rel="stylesheet" href="/css/site.css" />


    </head>
    <body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li><a id="btnHome" href="/">Home</a></li>
                </ul>
            </div>
        </div>
    </nav>


        <div class="container body-content">


<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
    <link href="/css/signin.css" rel="stylesheet">
    <script src="/lib/jquery/dist/jquery.js"></script>
    <script src="/lib/bootstrap/dist/js/bootstrap.js"></script>
    <script src="/js/Login.js"></script>
</head>
<body class="text-center">
    <form id="formSubmit" method="post" class="form-signin">
        <img class="mb-4" src="/images/FIU-Chat-Curved.png" alt="" width="150" height="150">
        <h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
        <label for="inputEmail" class="sr-only">Email address</label>
        <input autofocus="" class="form-control" data-val="true" data-val-required="The Email field is required." id="inputEmail" name="inputEmail" placeholder="Email address" required="required" type="email" value="" />
        <label for="inputPassword" class="sr-only">Password</label>
        <input class="form-control" data-val="true" data-val-required="The Password field is required." id="inputPassword" name="inputPassword" placeholder="Password" required="required" type="password" />
        <div class="checkbox mb-3">
            <label>
                <input data-val="true" data-val-required="The Remember field is required." id="rememberMe" name="rememberMe" type="checkbox" value="true" />  Remember me
            </label>
        </div>
        <button id="btnLogin" class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
        <p class="mt-5 mb-3 text-muted">&copy; 2017-2018</p>
    <input name="__RequestVerificationToken" type="hidden" value="CfDJ8Ah5tOyN_3lPrH0DgSEU8vD7Q7JItdizW-mYDc5uamCO3oRTBN-pdo9ZyPgRaHRyovwEGfT5Qhw0UD-rfbIHUJPt4FgUOhM1OkAWC9AtAfPEKkxz7TBfwKfz0EpfxF4DX2DAczujogr__xnIr3vDq3o" /><input name="rememberMe" type="hidden" value="false" /></form>

</body>
</html>
            <hr />
            <footer>
                <p>&copy; 2018 - Chat FIU</p>
            </footer>
        </div>


            <script src="/lib/jquery/dist/jquery.js"></script>
            <script src="/lib/bootstrap/dist/js/bootstrap.js"></script>
            <script src="/js/site.js?v=BxFAw9RUJ1E4NycpKEjCNDeoSvr4RPHixdBq5wDnkeY"></script>
            <script type="text/javascript">
            </script>


        <script type="text/javascript">
        </script>
        <script src="/js/NavBarFunction.js"></script>

    </body>

The key to solve the problem is in your flow described here:

The correct flow is LoginPage -> Login.js (grabs data and uses Ajax for a post request.) -> Returns a html page composing of _Layout.cshtml and /Views/Home/Index.cshtml

This kind of flow implies that you want to redirect into index page (proved by usage of return RedirectToAction("Index", "Account"); in controller action), which AJAX usage in redirection with GET method makes no sense (because AJAX call intended to stay in the same page ).

Instead of replacing entire HTML page content using $("html").html(response); , use window.location.href to redirect with specified URL like this:

NavBarFunctions.js

$("#li_btnHome a")[0].click(function (event) {
    event.preventDefault();
    alert("called click");
    var tokenObj = localStorage.getItem("token");
    var tokenStr = tokenObj == null ? "what_about_tokenObj_is_null?" : tokenObj.toString();

    $.ajax({
        type: 'GET',
        url: '@Url.Action("Index", "Home")',
        beforeSend: function (xhr) {
            xhr.setRequestHeader("Authorization", tokenStr);
        },
        success: function (response) {
            // this is just an example, replace action & controller name as you wish
            window.location.href = '@Url.Action("ActionName", "ControllerName")';
        }
    });
});

Login.js

function redirect(redirectUrl) {
    $.ajax({
        type: 'GET',
        contentType: 'application/json; charset=utf-8;',
        url: redirectUrl,
        success: function (response) {
            window.location.href = redirectUrl;
        }
    });    
}

However if you want to render certain portion of the page using partial view, you may use jQuery.html() targeting a placeholder, eg <div> tag:

<!-- partial view placeholder -->
<div id="content">...</div>
// ajax callback
$.ajax({
    // other settings
    .....
    success: function (response) {
        $('#content').html(response);
    },
    .....
});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM