【问题标题】:SignalR dotnet core authenticationSignalR dotnet 核心身份验证
【发布时间】:2018-05-18 14:39:28
【问题描述】:

我正在使用带有Bazinga.AspNetCore.Authentication.BasicMicrosoft.AspNetCore.SignalR nuget 包,它为dotnet 核心添加了基本身份验证。我的 C# SignalR 客户端在没有身份验证时连接,但是当我添加 AuthorizeAttribute 时,它通过 http 连接,并且 http 请求标头成功通过身份验证,但 Socket 未通过身份验证,可能是因为套接字消息中没有标头。

所以我想知道我应该如何将令牌或其他东西传递给经过身份验证的套接字连接,或者是否有我可以遵循的示例代码。我认为我应该将随机令牌传递给经过身份验证的用户,并且用户需要在消息中不断传递令牌。

Client project, Server project

服务器:

using System.Threading.Tasks;
using Bazinga.AspNetCore.Authentication.Basic;
using Domainlogic;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Cors.Infrastructure;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace API
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options => options.AddPolicy("CorsPolicy", builder =>
            {
                builder
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowAnyOrigin();
            }));

            services.AddSignalR();

            services.AddAuthentication(BasicAuthenticationDefaults.AuthenticationScheme)
                .AddBasicAuthentication(credentials => Task.FromResult(
                    credentials.username == "SomeUserName"
                    && credentials.password == "SomePassword"));
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseCors("CorsPolicy");

            app.UseCors(CorsConstants.AnyOrigin);

            app.UseFileServer();

            app.UseSignalR(route => { route.MapHub<MessageHub>("/chat"); });

            app.UseAuthentication();
        }
    }
}

服务器集线器:

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.SignalR;

namespace Domainlogic
{
    public class MessagePayload
    {
        public string Name { get; set; }

        public string Message { get; set; }

        public DateTime Date { get; set; }        
    }

    [Authorize]
    public class MessageHub : Hub
    {   
        // connected IDs
        private static readonly HashSet<string> ConnectedIds = new HashSet<string>();

        public override async Task OnConnectedAsync()
        {
            ConnectedIds.Add(Context.ConnectionId);

            await Clients.All.SendAsync("SendAction", "joined", ConnectedIds.Count);
        }

        public override async Task OnDisconnectedAsync(Exception ex)
        {
            ConnectedIds.Remove(Context.ConnectionId);

            await Clients.All.SendAsync("SendAction", "left", ConnectedIds.Count);
        }

        public async Task Send(MessagePayload message)
        {
            await Clients.All.SendAsync("SendMessage", message);
        }
    }
}

客户:

using System;
using System.Net;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Connections.Client;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Logging;

namespace SignalRClient
{
    public class MessagePayload
    {
        public string Name { get; set; }

        public string Message { get; set; }

        public DateTime Date { get; set; }        
    }

    class Program
    {
        public static string Base64Encode(string plainText) {
            var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
            return System.Convert.ToBase64String(plainTextBytes);
        }

        static void Main(string[] args)
        {
            var credential = Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes("SomeUserName" + ":" + "SomePassword"));

            //Set connection
            var connection = new HubConnectionBuilder()
                .WithUrl("http://localhost:5000/chat", options =>
                {
                    options.Headers.Add("Authorization", $"Basic {credential}");
                })
                .AddJsonProtocol()
                .Build();

            connection.On<MessagePayload>("SendMessage", param =>
            {
                Console.WriteLine(param.Message);
            });

            connection.StartAsync().Wait();

            var startTimeSpan = TimeSpan.Zero;
            var periodTimeSpan = TimeSpan.FromSeconds(3);
            int i = 0;

            var timer = new System.Threading.Timer((e) =>
            {
                connection.InvokeAsync<MessagePayload>("Send", new MessagePayload()
                {
                    Message = "Some message: " + i++
                });
            }, null, startTimeSpan, periodTimeSpan);


            Console.Read();
            connection.StopAsync();
        }
    }
}

【问题讨论】:

    标签: c# asp.net-core asp.net-core-signalr


    【解决方案1】:

    感谢 GitHub 上的“davidfowl”,解决方案将 UseAuthentication 移至 UseSignalR 上方。

    来源https://github.com/aspnet/SignalR/issues/2316

    代替:

    app.UseSignalR(route => { route.MapHub<MessageHub>("/chat"); });
    
    app.UseAuthentication();
    

    使用这个:

    app.UseAuthentication();
    
    app.UseSignalR(route => { route.MapHub<MessageHub>("/chat"); });
    

    【讨论】:

    • 为什么文档中没有这个!?!?
    • 我还必须添加 app.UseAuthorization(); app.UseAuthentication() 之间;和 app.UseSignalR(在我的例子中是 app.UseEndpoints),在配置部分中,以便它工作,否则它会给出关于中间件的错误。
    【解决方案2】:

    为了解决这个问题,我必须使用 Dictionary 将用户的令牌和 connectionId 存储在服务器缓存中。那是因为在集线器中我无法控制会话。

    因此,每次用户连接到我公开的集线器和接收用户的 connectionId 和令牌的端点时。当请求由集线器处理时,我通过用户身份验证的连接知道。

    控制器

    [HttpPost]
    [Authorize]
    [Route("{connectionId}")]
    public IActionResult Post(string connectionId)
    {
        this.hubConnectionService.AddConnection(connectionId, this.workContext.CurrentUserId);
        return this.Ok();
    }
    

    集线器

    public override Task OnDisconnectedAsync(Exception exception)
    {
        this.hubConnectionService.RemoveConnection(this.Context.ConnectionId);
        return base.OnDisconnectedAsync(exception);
    }
    

    【讨论】:

      猜你喜欢
      • 2021-11-07
      • 1970-01-01
      • 2020-08-17
      • 2019-11-03
      • 2019-02-23
      • 2017-01-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多