Search code examples
asp.net-core.net-corewebsocketchataspnetboilerplate

AbpSession always return null when start using Websocket


I'm using asp.net boilerplate framework, and I'm trying to set the WebSocket connection to become match the logged-in user id when the user establishes the WebSocket connection, but what I noticed is the AbpSession.UserId value is always null, so what is the reason, although in other classes it is working fine, and here is my code:


 public class WebSocketServerConnectionManager : ITransientDependency
    {

        private ConcurrentDictionary<string, WebSocket> _socket = new ConcurrentDictionary<string, WebSocket>();

        public IAbpSession AbpSession { get; set; }

        public WebSocketServerConnectionManager()
        {
            AbpSession = NullAbpSession.Instance;

        }

        public ConcurrentDictionary<string, WebSocket> GetAllSockets()
        {
        return _socket;
        
        }

        public string AddSocket(WebSocket socket) 
        {

            try
            {
                var ConnId = AbpSession.UserId.ToString(); //<==== Null

                    // Guid.NewGuid().ToString();


                //var test = AbpSession.UserId;


                _socket.TryAdd(ConnId/*dictionary item key*/, socket/*dictionary item value*/);
                Debug.WriteLine("Connection Added:" + ConnId);
                return ConnId;
            }
            catch(Exception ex)
            {
                throw new Exception(ex.Message);
            }
            
        }
}

Update 1:

And here is the client-side WebSocket initialization:


    async ngOnInit() {
this.connectWebSocket();

}

connectWebSocket(){
 
  this.socket=new WebSocket(this.webSocketUrl);

  this.socket.onopen=(event)=>{

  }

  this.socket.onclose=(event)=>{

  }


this.socket.onmessage=(event)=>{
this.isConnID(event.data);



  }

}

Update 2: Update3:

I have this in AuthConfigurer:

     /* This method is needed to authorize SignalR javascript client.
         * SignalR can not send authorization header. So, we are getting it from query string as an encrypted text. */
        private static Task QueryStringTokenResolver(MessageReceivedContext context)
        {

            var test = context.HttpContext.Request.Path.Value;//the value is null
            if (!context.HttpContext.Request.Path.HasValue ||
                (!context.HttpContext.Request.Path.Value.StartsWith("/signalr") && !context.HttpContext.Request.Path.Value.StartsWith("/ws")))
            {
                // We are just looking for signalr clients
                return Task.CompletedTask;
            }

            var qsAuthToken = context.HttpContext.Request.Query["enc_auth_token"].FirstOrDefault();
            if (qsAuthToken == null)
            {
                // Cookie value does not matches to querystring value
                return Task.CompletedTask;
            }

            // Set auth token from cookie
            context.Token = SimpleStringCipher.Instance.Decrypt(qsAuthToken, AppConsts.DefaultPassPhrase);
            return Task.CompletedTask;
        }

and in appsettings.json the Authentication section :


 "Authentication": {
    "JwtBearer": {
      "IsEnabled": "true",
      "SecurityKey": "Test_C421AAEE0D114E9C",
      "Issuer": "Test",
      "Audience": "Test"
    }
  },

Solution

  • You need to pass authentication information.

    1. If you're using the ASP.NET Boilerplate Angular template (with Module Zero), you may pass enc_auth_token in the query string, which will be resolved by QueryStringTokenResolver.
    // import { AppConsts } from '@shared/AppConsts';
    // import { UtilsService } from 'abp-ng2-module';
    
    connectWebSocket(){
        // this.socket=new WebSocket(this.webSocketUrl); // Change this to the following
        const encryptedAuthToken = new UtilsService().getCookieValue(AppConsts.authorization.encryptedAuthTokenName);
        const webSocketUrl = this.webSocketUrl + '?enc_auth_token=' + encodeURIComponent(encryptedAuthToken);
        this.socket = new WebSocket(webSocketUrl);
    
        ...
    }
    

    Reference: SignalRAspNetCoreHelper.ts

    1. If webSocketUrl doesn't start with /signalr, whitelist it in QueryStringTokenResolver:
    private static Task QueryStringTokenResolver(MessageReceivedContext context)
    {
        if (!context.HttpContext.Request.Path.HasValue ||
         // !context.HttpContext.Request.Path.Value.StartsWith("/signalr")) // Change this to the following
           (!context.HttpContext.Request.Path.Value.StartsWith("/signalr") && 
            !context.HttpContext.Request.Path.Value.StartsWith(webSocketUrl))
        {
            // ...
            return Task.CompletedTask;
        }
    
        ...
    }
    

    Remember to add the WebSockets middleware if you're using raw WebSockets.

    • Add app.UseWebSockets() before app.UseEndpoints(...) in Startup.cs:
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
    {
        ...
    
        app.UseWebSockets() // Add this
    
        app.UseEndpoints(...
        ...
    }
    

    References: