【问题标题】:ASP.NET Core 2.0 custom middleware using cookie authentication使用 cookie 身份验证的 ASP.NET Core 2.0 自定义中间件
【发布时间】:2017-10-25 17:23:47
【问题描述】:

我需要为我的公司实施自定义“身份验证”。 我之所以这么说是因为用户在访问应用程序之前在技术上已经过身份验证,如果是这样,userId 将存在于请求标头中。

我需要做的是找出一种方法来查询数据库并根据该 Id 获取其他用户信息,并设置 HttpContext.User 对象,以便可以在应用程序中轻松使用它。

我现在采取的路线涉及使用没有 ASP.NET Core 身份的 Cookie 身份验证。我将这个想法与自定义中间件相结合,该中间件将为用户查询数据库,从 db 字段填充声明,并使用 context.SignInAsync 创建 cookie。我将此中间件放在 app.UseAuthentication() 之前。问题是在第一次请求时未设置 .User 对象,因为似乎 SignIn 方法仅创建 cookie 但未设置 .User 对象。身份验证中间件还没有看到 cookie,因为它在第一次请求时不存在。

谁能提供任何想法?也许我做错了,或者这种技术很好,但我错过了让它发挥作用所需的东西。

在 Startup.cs 中:

public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();


        services.AddAuthentication("MyAuthenticationCookie")
           .AddCookie("MyAuthenticationCookie");
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseBrowserLink();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
        }

        app.UseStaticFiles();

        app.UseMyUserMiddleware();

        app.UseAuthentication();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }

自定义中间件:

    public class MyUserMiddleware
{
    private readonly RequestDelegate _next;

    public MyUserMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public Task Invoke(HttpContext context)
    {
        // Sign in user if this auth cookie doesn't exist
        if (context.Request.Cookies[".AspNetCore.MyAuthenticationCookie"] == null)
        {
            // Get user from db - not done

            // Set claims from user object - put in dummy test name for now
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, "TEST"),

            };

            var claimsIdentity = new ClaimsIdentity(claims, "MyAuthenticationCookie");

            context.SignInAsync("MyAuthenticationCookie", new ClaimsPrincipal(claimsIdentity));
        }

        return this._next(context);
    }
}

public static class MyUserMiddlewareExtensions
{
    public static IApplicationBuilder UseMyUserMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<MyUserMiddleware>();
    }
}

【问题讨论】:

  • “用户在访问应用程序之前在技术上得到了身份验证”?这听起来像是一个 Intranet 应用程序。您是否尝试过 Windows 身份验证? “用户 ID 将存在于请求标头中”?那么请求头中只会有一个自定义请求头属性“x-user-id”,2?哇,那是东西。
  • 我无法决定这部分是如何完成的。
  • 尝试在services.AddAuthentication()context.SignInAsync() 中将MyAuthenticationCookie 替换为CookieAuthenticationDefaults.AuthenticationScheme。然后在.AddCookie(options =&gt; { options.Cookie.Name = "xxxxxx"; })中设置cookie的名称。
  • 不会改变看起来的行为。

标签: c# asp.net-core authentication cookies asp.net-core-middleware


【解决方案1】:

简答:您应该使用自定义AuthorizationHandler 来验证和检索声明。

长答案:使用 ASP.NET CORE,您应该远离身份验证中间件。相反,您应该使用 AuthenticationHandler microsoft

要创建自定义身份验证处理程序,您需要创建一个继承自 AuthenticationHandler&lt;TOption&gt; 的新类。 TOption 是一个简单的类,用于将参数传递给您的处理程序。

public class TecMobileOptions : AuthenticationSchemeOptions
{ 
   // Add your options here
}

public class MyNewHandler : AuthenticationHandler<MyOptions>
{
    private readonly ILogger _logger;

    public TecMobileHandler(
        IOptionsMonitor<MyOptions> options,
        ILoggerFactory loggerFactory,
        UrlEncoder encoder,
        ISystemClock clock) : base(options, loggerFactory, encoder, clock)
    {
       // Inject here your DbContext
        _logger = loggerFactory.CreateLogger("name...");
    }
}

然后你需要实现 HandleAuthenticateAsync 方法。它会在必要时被 Auth 中间件调用:

    protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var authorization = Request.Headers["UserId"].ToString();
        (...)
        return AuthenticateResult.Success(
            new AuthenticationTicket(**your claims**, Scheme.Name));
    }

此方法返回的声明将通过 HttpContext.User 对象获得。

完成后,您需要将您的方案添加到身份验证构建器中。

services.AddAuthentication()
   .AddCookie("MyAuthenticationCookie");
   .AddScheme<MyOptions, MyHandler>("MyHandlerName");

不要忘记在 Startup.cs / Configure 方法中添加以下代码行

 app.UseAuthentication();

最后,您需要在要保护的所有类/方法上添加 Authorize 属性

[Authorize(AuthenticationSchemes = "MyHandlerName")]
public class MyControllerController : BaseController
{  }

OR

[Authorize(AuthenticationSchemes = "MyHandlerName")]
public IActionResult MyMethod()
{  }

编辑:这里的解决方案涵盖了完整的登录过程。 让我们考虑您定义两个身份验证方案 - 基于 Cookie 的称为 CookieScheme - AutoSignInScheme:按照上述步骤创建相应的处理程序

[Authorize(AuthenticationSchemes = "CookieScheme")]
public class SecuredController : Controller
{
     (...)
}

然后你需要添加AccountController

public class AccountController : Controller
{
    [HttpGet]
    [Authorize(AuthenticationSchemes = "AutoSignInScheme")]
    public async Task<IActionResult> AutoSignIn(string returnUrl)
    {
        await HttpContext.SignInAsync(
           "CookieScheme",
           new ClaimsPrincipal(new ClaimsIdentity(User.Claims, "CookieScheme")));
        return Redirect(returnUrl);
    }
 }

在您的 Startup.cs 中,添加以下行:

       services.AddAuthentication()
            .AddCookie("CookieScheme", opts =>
            {
                opts.LoginPath = new PathString("/account/AutoSignIn");
                opts.LogoutPath = ** TODO IF REQUIRED **
                opts.Cookie.Expiration = TimeSpan.FromHours(8);
            })
            .AddScheme<MyOptions, MyHandler>("AutoSignInScheme");

当用户尝试访问您的网站时,他会被重定向到自动登录控制器。然后从您的数据库中检索声明,存储在 cookie 中,最终将用户重定向到他的初始目的地!

Seb

【讨论】:

  • 感谢您的回答。在第一次请求后似乎没有创建 cookie,这是一个问题,因为无法保留用户信息,我每次都必须从自定义 AuthenticationHandler 调用数据库(在从标头获取 Id 之后)。
  • 对不起,我没有详尽无遗!这会创建声明,然后您可以将其保存到 cookie。通常,如果用户未登录,您会将他重定向到您获得声明的页面,创建 cookie 并将他重定向回您需要的地方!我的帖子向您展示了如何获得索赔!造成误会见谅
  • 有没有办法在中间件中设置cookie?无需登录操作。用户无需手动执行任何操作。
  • 您应该远离身份验证 cookie。我已经更新了我的答案以包含完整的流程。祝你好运
  • 对不起,我说的是中间件,但我的意思是处理程序。您认为将所有内容都包含在自定义处理程序中而不必合并 accountcontroller 和重定向是否可行?我们可以扩展 CookieAuthenticationHandler 吗?
猜你喜欢
  • 2018-07-19
  • 2017-02-15
  • 2018-02-24
  • 2018-01-30
  • 2018-03-30
  • 2018-10-21
  • 2016-07-05
相关资源
最近更新 更多