【问题标题】:ASP.NET Core 2.2 Authentication not workingASP.NET Core 2.2 身份验证不起作用
【发布时间】:2020-03-21 00:51:29
【问题描述】:

我正在尝试创建自己的登录身份验证,但它不起作用,所以我创建了这个快速测试...

[HttpGet]
public IActionResult Index()
{
    try
    {
        var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme);
        identity.AddClaim(new Claim(ClaimTypes.Name, "Test Name"));
        var principal = new ClaimsPrincipal(identity);

        SignIn(principal, CookieAuthenticationDefaults.AuthenticationScheme);

        var isAuthenticated = User.Identity.IsAuthenticated;    //-- THIS IS ALWAY FALSE... BUI JUST LOGGED IN?!?!?!?

        return View();
    }
    catch(Exception ex)
    {
        _logger.LogError(ex, "Error:");
        return StatusCode(500);
    }
}

所以你可以看到我调用SignIn 然后在下一行我检查用户现在是否已通过身份验证,但它总是返回 false,User.Identity 也看起来是空的。有谁知道我在这里做错了什么?

在我的 Startup / ConfigureServices 我有:

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(
    CookieAuthenticationDefaults.AuthenticationScheme,
    options =>
    {
        options.LoginPath = "/Admin/Index";
    });

在启动/配置中

app.UseAuthentication();
app.UseCookiePolicy(new CookiePolicyOptions
{
    MinimumSameSitePolicy = SameSiteMode.Strict,
});

【问题讨论】:

    标签: c# authentication asp.net-core asp.net-core-2.2


    【解决方案1】:
    SignIn(principal, CookieAuthenticationDefaults.AuthenticationScheme);
    

    这是一个无操作。 SignIn 是创建SignInResult 实例的便捷方法,通常会从操作中返回。这遵循命令模式,但您的示例只是创建命令并且从不执​​行它。

    你真正想要的是:

    await HttpContext.SignInAsync(principal);
    

    如果您愿意,您可以提供方案,但您已将CookieAuthenticationDefaults.AuthenticationScheme 设置为ConfigureServices 中的默认值,因此将假定此方案。

    但是,即使进行了此更改,User.Identity.IsAuthenticated 仍将是 false,直到发出另一个请求。通常,您会这样做:

    await HttpContext.SignInAsync(principal);
    
    return RedirectToAction(...);
    

    通过您的设置,调用SignInAsync 最终会创建一个存储身份验证信息的cookie。它不会更新当前的User。在由重定向引起的下一个请求中,您的 ASP.NET Core 应用程序会读取 cookie,并正确填充 User

    【讨论】:

      【解决方案2】:

      我发现您的 Index 方法缺少 Authorize 属性。请添加Authorize属性如下:

      [Authorize]
      [HttpGet]
      public IActionResult Index()
      {
          ....
      }
      

      那么在Startup类的Configure方法中,中间件顺序应该如下:

      public void Configure(IApplicationBuilder app, IHostingEnvironment env)
      {
              ......
      
              app.UseStaticFiles();
              app.UseCookiePolicy(new CookiePolicyOptions
              {
                  MinimumSameSitePolicy = SameSiteMode.Strict,
              });
      
              app.UseAuthentication();
              app.UseMvc(routes =>
              {
                  routes.MapRoute(
                      name: "default",
                      template: "{controller=Home}/{action=Index}/{id?}");
              });
      }
      

      现在它应该适合你了。

      【讨论】:

      • 不,这不起作用,如果我将 [Authorize] 添加到操作中,您将无法访问它,因为我没有登录。通常我会在我的所有控制器和操作上使用 [Authorize],而不是用于授权的操作。
      • 哦!你搞错了!没有授权属性并登录User.Identity.IsAuthenticated; 将始终为假。这是预期的行为。
      • 事情是这样的,我没有登录。在我登录之前需要运行操作中的代码,但它不起作用。注意:使用 [Authorize] 属性将阻止非登录用户访问该操作:请参阅:docs.microsoft.com/en-us/dotnet/api/…
      【解决方案3】:

      这是SignIn的源代码

      public virtual SignInResult SignIn(
        ClaimsPrincipal principal,
        string authenticationScheme)
      => new SignInResult(authenticationScheme, principal);
      

      上面的代码只是返回一个对象SignInResult,此时它什么都不做。

      这里是SignInResult的源代码: https://github.com/aspnet/Mvc/blob/master/src/Microsoft.AspNetCore.Mvc.Core/SignInResult.cs

      这里是核心代码:

      public class SignInResult : ActionResult
      {
      
          /// <inheritdoc />
          public override async Task ExecuteResultAsync(ActionContext context)
          {
              ...
              await context.HttpContext.SignInAsync(AuthenticationScheme, Principal, Properties);
          }
      }
      

      它是一个返回类型ActionResult,它只是调用context.HttpContext.SignInAsync,所以ControllerBase.SignInHttpContext.SignInAsync() 的一种快捷方式。

      但是!看看下面ActionResult

      public abstract class ActionResult : IActionResult
      {
        public virtual Task ExecuteResultAsync(ActionContext context)
        {
         this.ExecuteResult(context);
         return Task.CompletedTask;
        }
      
        public virtual void ExecuteResult(ActionContext context)
        {
        }
      }
      

      所以SignInResultSync 方法没有任何作用,而只是Async

      我可以建议的是:

      1. 在您的测试方法中,您只能return SignIn(...),然后该操作将自动执行,然后您可以在下一个请求中检查其是否授权。
      2. 如果您想在一个操作中登录并执行其他操作,请直接使用HttpContext.SignInAsync(),它适用于您当前的代码。
      3. [这个选项只是为了好玩]关于SignInResult只实现了async函数,但在sync方法中什么都不做,所以你可以尝试将你的测试动作更改为async Task&lt;IActionResult&gt;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-09-06
        • 1970-01-01
        • 1970-01-01
        • 2019-10-18
        • 2019-12-13
        • 2023-04-11
        • 1970-01-01
        • 2021-08-22
        相关资源
        最近更新 更多