重新加载页面影响注销 user/log

Reloading page affecting sign out of user/log out

我已经尝试修复这个问题很多次了,但到目前为止都没有成功。我正在登录我的页面,一切正常。然而,每次我重新加载我的页面时,我最终都会注销并重定向到“登录页面”并且必须重新登录。问题是什么?我的 Coockie 逻辑有问题吗?

我也试过实现login.RememberMe的逻辑,但是也不行。我检查过 login.RememberMe returns 是真的,但没有效果。

控制器中的登录方法:

[HttpPost]
public async Task<IActionResult> Login([FromBody] LoginModel login)
{
  ApplicationUser user = await this.SignInManager.UserManager.FindByEmailAsync(login.Email);

  Microsoft.AspNetCore.Identity.SignInResult result =
    await this.SignInManager.PasswordSignInAsync(login.Email, login.Password, login.RememberMe, false);

  if (!result.Succeeded)
  {
    List<string> errors = new List<string>();
    errors.Add("Email and password are invalid.");
    return BadRequest(new LoginResult
    {
      Successful = false,
      Errors = errors,
    });
  }

  IList<string> roles = await this.SignInManager.UserManager.GetRolesAsync(user);

  List<Claim> claims = new List<Claim>
  {
    new Claim(ClaimTypes.Name, login.Email)
  };

  ClaimsIdentity identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
  ClaimsPrincipal principal = new ClaimsPrincipal(identity);
  AuthenticationProperties props = new AuthenticationProperties
  {
    IsPersistent = true,
    ExpiresUtc = DateTime.UtcNow.AddMonths(1)
  };

  // to register the cookie to the browser
  this.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, props).Wait();

  foreach (string role in roles)
  {
    claims.Add(new Claim(ClaimTypes.Role, role));
  }

  SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(this.Configuration["JwtSecurityKey"]));
  SigningCredentials creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
  DateTime expiry = DateTime.Now.AddDays(Convert.ToInt32(this.Configuration["JwtExpiryInDays"]));

  JwtSecurityToken token = new JwtSecurityToken(
    this.Configuration["JwtIssuer"],
    this.Configuration["JwtAudience"],
    claims,
    expires: expiry,
    signingCredentials: creds
  );

  return Ok(new LoginResult
  {
    Successful = true,
    Token = new JwtSecurityTokenHandler().WriteToken(token),
  });
}

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
  services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
      options.TokenValidationParameters = new TokenValidationParameters
      {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = Configuration["JwtIssuer"],
        ValidAudience = Configuration["JwtAudience"],
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JwtSecurityKey"]))
      };
    })
    .AddCookie(options =>
     {
       options.Cookie.Name = "DashCoockie";
       options.LoginPath = "/login";
       options.ExpireTimeSpan = TimeSpan.FromDays(30);
       options.SlidingExpiration = true; 
       options.EventsType = typeof(CookieAuthEvent);
     });
  services.AddScoped<CookieAuthEvent>();

  services.AddAuthorization(config =>
  {
    config.AddPolicy(Policies.IsAdmin, Policies.IsAdminPolicy());
    config.AddPolicy(Policies.IsUser, Policies.IsUserPolicy());
  });

  services.ConfigureApplicationCookie(options =>
  {
    options.Cookie.HttpOnly = true;
    options.Events.OnRedirectToLogin = context =>
    {
      context.Response.StatusCode = 401;
      return Task.CompletedTask;
    };
  });

  services.AddControllers();

  // Instant update on runtime for development purposes
  services.AddControllersWithViews().AddRazorRuntimeCompilation();
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  app.UseAuthentication();
  app.UseAuthorization();

  app.UseCookiePolicy();
}

CookieAuthEvent.cs:

  public class CookieAuthEvent : CookieAuthenticationEvents
  {
      public override async Task ValidatePrincipal(CookieValidatePrincipalContext context)
      {
          context.Request.HttpContext.Items.Add("ExpiresUTC", context.Properties.ExpiresUtc);
      }
  }

登录后(Cookie 名称相同,只是隐藏了上面代码中的第一部分):

我的项目结构如下:Client、Server、Shared。我通过使用 LocalStorage 和 AuthService 找到了解决方案:客户端的 IAuthService。所以在我的设置中唯一的解决方案是使用 LocalStorage 吗?

public class AuthService : IAuthService
{
    private readonly HttpClient _httpClient;
    private readonly AuthenticationStateProvider _authenticationStateProvider;
    private readonly ILocalStorageService _localStorage;

    public AuthService(HttpClient httpClient,
                       AuthenticationStateProvider authenticationStateProvider,
                       ILocalStorageService localStorage)
    {
        _httpClient = httpClient;
        _authenticationStateProvider = authenticationStateProvider;
        _localStorage = localStorage;
    }

    public async Task<RegisterResult> Register(RegisterModel registerModel)
    {
        var result = await _httpClient.PostJsonAsync<RegisterResult>("api/accounts", registerModel);

        return result;
    }

    public async Task<LoginResult> Login(LoginModel loginModel)
    {
        var loginAsJson = JsonSerializer.Serialize(loginModel);
        var response = await _httpClient.PostAsync("api/Login", new StringContent(loginAsJson, Encoding.UTF8, "application/json"));
        var loginResult = JsonSerializer.Deserialize<LoginResult>(await response.Content.ReadAsStringAsync(), new JsonSerializerOptions { PropertyNameCaseInsensitive = true });

        if (!response.IsSuccessStatusCode)
        {
            return loginResult;
        }

        await _localStorage.SetItemAsync("authToken", loginResult.Token);
        ((ApiAuthenticationStateProvider)_authenticationStateProvider).MarkUserAsAuthenticated(loginModel.Email);
        _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("bearer", loginResult.Token);

        return loginResult;
    }

    public async Task Logout()
    {
        await _localStorage.RemoveItemAsync("authToken");
        ((ApiAuthenticationStateProvider)_authenticationStateProvider).MarkUserAsLoggedOut();
        _httpClient.DefaultRequestHeaders.Authorization = null;
    }
}

您似乎没有在请求中设置令牌header 尝试在您的启动程序中添加这些代码 class:

services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                    .AddJwtBearer(options =>
                    {
                        options.Events = new JwtBearerEvents()
                        {
                            OnMessageReceived = context =>
                              {
                                  context.Token = context.Request.Cookies["access_token"];
                                  return Task.CompletedTask;
                              }
                        };
                    });

在您的登录操作中:

Response.Cookies.Append("access_token",your JwtSecurityToken)