Asp.net core 信号器核心不使用cookie身份验证

Asp.net core 信号器核心不使用cookie身份验证,asp.net-core,asp.net-identity,signalr.client,asp.net-core-signalr,Asp.net Core,Asp.net Identity,Signalr.client,Asp.net Core Signalr,我似乎无法让SignalR core使用cookie身份验证。我已经建立了一个测试项目,可以成功地进行身份验证,并对需要授权的控制器进行后续调用。因此,常规身份验证似乎起到了作用 但之后,当我尝试连接到集线器,然后在集线器上触发标有Authorize的方法时,调用将失败,并显示以下消息:Authorization failed for user:(null) 我插入了一个虚拟中间件来检查传入的请求。从我的客户端(xamarin移动应用程序)调用connection.StartAsync()时,我

我似乎无法让SignalR core使用cookie身份验证。我已经建立了一个测试项目,可以成功地进行身份验证,并对需要授权的控制器进行后续调用。因此,常规身份验证似乎起到了作用

但之后,当我尝试连接到集线器,然后在集线器上触发标有
Authorize
的方法时,调用将失败,并显示以下消息:
Authorization failed for user:(null)

我插入了一个虚拟中间件来检查传入的请求。从我的客户端(xamarin移动应用程序)调用
connection.StartAsync()
时,我收到一个
OPTIONS
请求,其中
context.User.Identity.IsAuthenticated
等于true。在我的集线器上的
OnConnectedAsync
被调用之后。此时,
\u contextAccessor.HttpContext.User.Identity.IsAuthenticated
为false。对我的请求进行反身份验证的责任是什么。从它离开我的中间件到调用OnConnectedAsync,都会有东西删除身份验证

有什么想法吗

示例代码:

public class MyMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task Invoke(HttpContext context)
    {

        await this._next(context);

        //At this point context.User.Identity.IsAuthenticated == true
    }
}

public class TestHub: Hub
{
    private readonly IHttpContextAccessor _contextAccessor;

    public TestHub(IHttpContextAccessor contextAccessor)
    {
        _contextAccessor = contextAccessor;
    }

    public override async Task OnConnectedAsync()
    {
        //At this point _contextAccessor.HttpContext.User.Identity.IsAuthenticated is false

        await Task.FromResult(1);
    }

    public Task Send(string message)
    {
        return Clients.All.InvokeAsync("Send", message);
    }

    [Authorize]
    public Task SendAuth(string message)
    {
        return Clients.All.InvokeAsync("SendAuth", message + " Authed");
    }
}


public class Startup
{
    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<MyContext>(options => options.UseInMemoryDatabase(databaseName: "MyDataBase1"));
        services.AddIdentity<Auth, MyRole>().AddEntityFrameworkStores<MyContext>().AddDefaultTokenProviders();
        services.Configure<IdentityOptions>(options => {

            options.Password.RequireDigit = false;
            options.Password.RequiredLength = 3;
            options.Password.RequireNonAlphanumeric = false;
            options.Password.RequireUppercase = false;
            options.Password.RequireLowercase = false;
            options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
            options.Lockout.MaxFailedAccessAttempts = 10;
            options.User.RequireUniqueEmail = true;

        });

        services.AddSignalR();
        services.AddTransient<TestHub>();
        services.AddTransient<MyMiddleware>();

        services.AddAuthentication();
        services.AddAuthorization();
        services.AddMvc();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseMiddleware<MyMiddleware>();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseAuthentication();

        app.UseSignalR(routes =>
        {
            routes.MapHub<TestHub>("TestHub");
        }); 

        app.UseMvc(routes =>
        {
            routes.MapRoute(name: "default", template: "{controller=App}/{action=Index}/{id?}");
        });
    }
}
公共类中间件
{
private readonly RequestDelegate\u next;
公共MyMiddleware(RequestDelegate下一步)
{
_下一个=下一个;
}
公共异步任务调用(HttpContext上下文)
{
等待此消息。_下一步(上下文);
//此时context.User.Identity.IsAuthenticated==true
}
}
公共类TestHub:Hub
{
专用只读IHttpContextAccessor\u contextAccessor;
公共测试中心(IHttpContextAccessor contextAccessor)
{
_contextAccessor=contextAccessor;
}
公共覆盖异步任务OnConnectedAsync()
{
//此时_contextAccessor.HttpContext.User.Identity.IsAuthenticated为false
等待任务。来自结果(1);
}
公共任务发送(字符串消息)
{
返回Clients.All.InvokeAsync(“发送”,消息);
}
[授权]
公共任务SendAuth(字符串消息)
{
返回Clients.All.InvokeAsync(“SendAuth”,message+“Authed”);
}
}
公营创业
{
//此方法由运行时调用。请使用此方法将服务添加到容器中。
//有关如何配置应用程序的更多信息,请访问https://go.microsoft.com/fwlink/?LinkID=398940
public void配置服务(IServiceCollection服务)
{
services.AddDbContext(options=>options.UseInMemoryDatabase(databaseName:“MyDataBase1”);
services.AddIdentity().AddEntityFrameworkStores().AddDefaultTokenProviders();
配置(选项=>{
options.Password.RequireDigit=false;
options.Password.RequiredLength=3;
options.Password.RequireNonAlphanumeric=false;
options.Password.RequireUppercase=false;
options.Password.RequireLowercase=false;
options.Lockout.DefaultLockoutTimeSpan=TimeSpan.FromMinutes(30);
options.locket.MaxFailedAccessAttempts=10;
options.User.RequireUniqueEmail=true;
});
services.AddSignalR();
services.AddTransient();
services.AddTransient();
services.AddAuthentication();
services.AddAuthorization();
services.AddMvc();
}
//此方法由运行时调用。请使用此方法配置HTTP请求管道。
公共无效配置(IApplicationBuilder应用程序,IHostingEnvironment环境)
{
app.UseMiddleware();
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseAuthentication();
app.usesigner(路由=>
{
routes.MapHub(“TestHub”);
}); 
app.UseMvc(路由=>
{
MapRoute(名称:“默认”,模板:“{controller=App}/{action=Index}/{id?}”);
});
}
}
这是客户端代码:

public async Task Test()
{
    var cookieJar = new CookieContainer();

    var handler = new HttpClientHandler
    {
        CookieContainer = cookieJar,
        UseCookies = true,
        UseDefaultCredentials = false
    };


    var client = new HttpClient(handler);

    var json = JsonConvert.SerializeObject((new Auth { Name = "craig", Password = "12345" }));

    var content = new StringContent(json, Encoding.UTF8, "application/json");

    var result1 = await client.PostAsync("http://localhost:5000/api/My", content); //cookie created

    var result2 = await client.PostAsync("http://localhost:5000/api/My/authtest", content); //cookie tested and works


    var connection = new HubConnectionBuilder()
        .WithUrl("http://localhost:5000/TestHub")
        .WithConsoleLogger()
        .WithMessageHandler(handler)
        .Build();



    connection.On<string>("Send", data =>
    {
        Console.WriteLine($"Received: {data}");
    });

    connection.On<string>("SendAuth", data =>
    {
        Console.WriteLine($"Received: {data}");
    });

    await connection.StartAsync();

    await connection.InvokeAsync("Send", "Hello"); //Succeeds, no auth required

    await connection.InvokeAsync("SendAuth", "Hello NEEDSAUTH"); //Fails, auth required

}
公共异步任务测试()
{
var cookieJar=new CookieContainer();
var handler=新的HttpClientHandler
{
CookieContainer=cookieJar,
UseCookies=true,
UseDefaultCredentials=false
};
var client=新的HttpClient(处理程序);
var json=JsonConvert.SerializeObject((new Auth{Name=“craig”,Password=“12345”});
var content=newstringcontent(json,Encoding.UTF8,“application/json”);
var result1=wait client.PostAsync(“http://localhost:5000/api/My“,内容);//已创建cookie
var result2=wait client.PostAsync(“http://localhost:5000/api/My/authtest“,content);//cookie经过测试并有效
var connection=new HubConnectionBuilder()
.WithUrl(“http://localhost:5000/TestHub")
.WithConsoleLogger()
.WithMessageHandler(处理程序)
.Build();
connection.On(“发送”,数据=>
{
WriteLine($“已接收:{data}”);
});
connection.On(“SendAuth”,data=>
{
WriteLine($“已接收:{data}”);
});
等待连接。StartAsync();
等待连接。InvokeAsync(“发送”,“你好”);//成功,无需身份验证
等待连接。InvokeAsync(“SendAuth”,“Hello NEEDSAUTH”);//失败,需要身份验证
}

这似乎是WebSocketsTransport中的一个问题,我们不会将cookie复制到websocket选项中。我们目前只复制标题。我将提交一个问题以查看它。

如果您正在使用Core 2,请尝试更改UseAuthentication的顺序,将其放在UseSignalR方法之前

 app.UseAuthentication();
 app.UseSignalR...
那么在中心内部,Identity属性不应该为null

Context.User.Identity.Name

嘿,Brennan,我想这是在客户端?我尝试在HttpClientHandler上重写SendAsync,并向每个请求添加cookie。但这似乎也不起作用。你对我如何设置要复制的标题有什么建议吗?我只需要能够验证。还有其他想法吗?是的,这是关于客户的。如果您使用的是alpha2 rel