【问题标题】:JWT token stored in localstorage lost after window.location.href call调用 window.location.href 后存储在 localstorage 中的 JWT 令牌丢失
【发布时间】:2021-08-02 05:21:16
【问题描述】:

我正在使用 Javascript Fetch API 来调用 Dot net Web API。 使用适用于 HTML/Javascript 的 Visual Studio 代码和适用于 Dot Net Web API 的 Visual Studio 2019。 我正在尝试使用 Dot net C# Web API 实现登录功能,这将在响应中返回 JWT 令牌并稍后使用该令牌调用单独的 Web API/服务(例如 EmployeeInfo )。

  1. 登录页面: 它显示用户 ID 和密码字段以及“登录”按钮
  2. 一旦用户点击登录按钮,就会调用函数 fnlogin
    function fnlogin() {
        const uname = document.getElementById('uname').value;
        const pwd = document.getElementById('pwd').value;

        const logindata = {
            username: uname,
            password: pwd
        }
        const loginurl = 'http://localhost:13402/api/Auth/Login';
        authenticate(loginurl, logindata);        
    }
        
    async function authenticate(loginurl, logindata) {
        console.log(logindata)
        const response = await fetch(loginurl , {
            method: "POST",
            mode: "cors",
            body: JSON.stringify(logindata),
            headers: { "Content-type" : "application/json, charset=UTF-8"}
        });
        const rdata = await response.json();
        console.log(rdata);
        if (!rdata.success) {
            document.getElementById("loginMessage").innerHTML = rdata.message;
            return;
        }

        const inMemoryToken = rdata.data
        localStorage.setItem('user', JSON.stringify(rdata));
        window.location.href = "http://localhost:5500/Employeeinfo1.html";

    }
  1. Web API 正确返回 JWT 令牌。

控制器中的代码如下:

        [HttpPost("Login")]
        public async Task<ActionResult<ServiceResponse<string>>> Login(UserLoginDto request)
        {
            var response = await _authRepo.Login(
                request.Username, request.Password
            );

            if (!response.Success)
            {
                return BadRequest(response);
            }

            return Ok(response);
        }

``
The code in AuthRepository class is as follows :
public class AuthRepository : IAuthRepository
{
    private readonly AppDbContext _context;
    private readonly IConfiguration _configuration;
    public AuthRepository(AppDbContext context, IConfiguration configuration)
    {
        _configuration = configuration;
        _context = context;

    }

    public async Task<ServiceResponse<string>> Login(string username, string password)
    {
        var response = new ServiceResponse<string>();
        var user = await _context.Users.FirstOrDefaultAsync(x => x.Username.ToLower().Equals(username.ToLower()));
        if (user == null)
        {
            response.Success = false;
            response.Message = "User not found.";
        }
        else if (!VerifyPasswordHash(password, user.PasswordHash, user.PasswordSalt))
        {
            response.Success = false;
            response.Message = "Wrong password.";
        }
        else
        {
            response.Data = CreateToken(user);
        }

        return response;
    }

    public async Task<ServiceResponse<User>> Register(User user, string password)
    {
        ServiceResponse<User> response = new ServiceResponse<User>();
        if (await UserExists(user.Username))
        {
            response.Success = false;
            response.Message = "User already exists.";
            return response;
        }

        CreatePasswordHash(password, out byte[] passwordHash, out byte[] passwordSalt);

        user.PasswordHash = passwordHash;
        user.PasswordSalt = passwordSalt;

        _context.Users.Add(user);
        await _context.SaveChangesAsync();
        response.Data = user;
        return response;
    }

    public async Task<bool> UserExists(string username)
    {
        if (await _context.Users.AnyAsync(x => x.Username.ToLower().Equals(username.ToLower())))
        {
            return true;
        }
        return false;
    }

    private void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
    {
        using (var hmac = new System.Security.Cryptography.HMACSHA512())
        {
            passwordSalt = hmac.Key;
            passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
        }
    }

    private bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
    {
        using (var hmac = new System.Security.Cryptography.HMACSHA512(passwordSalt))
        {
            var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
            for (int i = 0; i < computedHash.Length; i++)
            {
                if (computedHash[i] != passwordHash[i])
                {
                    return false;
                }
            }
            return true;
        }
    }

    private string CreateToken(User user)
    {
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Name, user.Username)
        };

        var key = new SymmetricSecurityKey(System.Text.Encoding.UTF8.GetBytes(_configuration.GetSection("AppSettings:Token").Value));

        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);

        var tokendDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(claims),
            Expires = System.DateTime.Now.AddDays(1),
            SigningCredentials = creds
        };

        var tokenHandler = new JwtSecurityTokenHandler();
        var token = tokenHandler.CreateToken(tokendDescriptor);

        return tokenHandler.WriteToken(token);
    }

4. Once the JWT token is returned , it is stored in LocalStorage. I verified in Chrome Dev Tools

But after the next screen is displayed, when I check in Chrome dev tools, the object/token is no longer present in the Local Storage.
Is this because of window.location.href will remove all local data in localStorage in the browser ?

I want to be able to use the token to pass to remaining html screens and web api 


【问题讨论】:

  • 运行将项目存储在本地存储中的代码的页面的 URL 是什么?您可能将其存储在一个来源并尝试从另一个来源 (http://localhost:5500) 读取。
  • 登录页面的url是127.0.0.1:5500/login.html

标签: javascript .net-core jwt local-storage


【解决方案1】:

您正在将一个项目存储在 http://127.0.0.1:5500 的本地存储中并尝试从 http://localhost:5500 读取它。

来自 MDN 网络文档中的 Window.localStorage

window界面的localStorage只读属性允许你访问Document的源的Storage对象;

关于Origin:

Web 内容的来源由用于访问它的 URL 的方案(协议)、主机(域)和端口定义。只有当方案、主机和端口都匹配时,两个对象才具有相同的来源。

如您所见,对于浏览器,来源不同,因为主机不匹配:127.0.0.1localhost 不是同一个字符串。

在任何地方都使用localhost127.0.0.1,但不要同时使用。

【讨论】:

  • 我的理解是 localhost 和 127.0.0.1 是一样的。。我想有一些不同,我改变了,它工作了。谢谢
  • @SudhirJangam, localhost 是一个主机名,通常指的是127.0.0.1,在这个意义上你可以认为它是一样的。浏览器会进行严格的字符串比较来确定来源,并且由于"localhost" 不等于"127.0.0.1",它会确定来源不同。
猜你喜欢
  • 2018-11-24
  • 2020-11-19
  • 2020-09-08
  • 2019-07-04
  • 2019-03-24
  • 2019-02-01
  • 2018-12-07
  • 2019-05-06
  • 1970-01-01
相关资源
最近更新 更多