using FishNet.Authenticating; using FishNet.Connection; using FishNet.Managing; using FishNet.Managing.Logging; using FishNet.Transporting; using System; using FishNet.Managing.Transporting; using UnityEngine; namespace FishNet.Example.Authenticating { /// /// This is an example of a password authenticator. /// Never send passwords without encryption. /// public class PasswordAuthenticator : HostAuthenticator { #region Public. /// /// Called when authenticator has concluded a result for a connection. Boolean is true if authentication passed, false if failed. /// Server listens for this event automatically. /// public override event Action OnAuthenticationResult; #endregion #region Serialized. /// /// Password to authenticate. /// [Tooltip("Password to authenticate.")] [SerializeField] private string _password = "HelloWorld"; #endregion public override void InitializeOnce(NetworkManager networkManager) { base.InitializeOnce(networkManager); // Listen for connection state change as client. NetworkManager.ClientManager.OnClientConnectionState += ClientManager_OnClientConnectionState; // Listen for broadcast from client. Be sure to set requireAuthentication to false. NetworkManager.ServerManager.RegisterBroadcast(OnPasswordBroadcast, false); // Listen to response from server. NetworkManager.ClientManager.RegisterBroadcast(OnResponseBroadcast); } /// /// Called when a connection state changes for the local client. /// private void ClientManager_OnClientConnectionState(ClientConnectionStateArgs args) { /* If anything but the started state then exit early. * Only try to authenticate on started state. The server * doesn't have to send an authentication request before client * can authenticate, that is entirely optional and up to you. In this * example the client tries to authenticate soon as they connect. */ if (args.ConnectionState != LocalConnectionState.Started) return; /* If was able to authenticate as clientHost * there is no need to send the password authentication. * Host authentication uses its own authentication approach. */ if (TryAuthenticateAsClientHost()) return; /* If not sending host authentication, then * authenticate normally. */ PasswordBroadcast pb = new() { Password = _password }; NetworkManager.ClientManager.Broadcast(pb); } /// /// Received on server when a client sends the password broadcast message. /// /// Connection sending broadcast. /// private void OnPasswordBroadcast(NetworkConnection conn, PasswordBroadcast pb, Channel channel) { /* If client is already authenticated this could be an attack. Connections * are removed when a client disconnects so there is no reason they should * already be considered authenticated. */ if (conn.IsAuthenticated) { conn.Disconnect(true); return; } bool correctPassword = pb.Password == _password; SendAuthenticationResponse(conn, correctPassword); /* Invoke result. This is handled internally to complete the connection or kick client. * It's important to call this after sending the broadcast so that the broadcast * makes it out to the client before the kick. */ OnAuthenticationResult?.Invoke(conn, correctPassword); } /// /// Received on client after server sends an authentication response. /// /// private void OnResponseBroadcast(ResponseBroadcast rb, Channel channel) { string result = rb.Passed ? "Authentication complete." : "Authentication failed."; NetworkManager.Log(result); } /// /// Sends an authentication result to a connection. /// private void SendAuthenticationResponse(NetworkConnection conn, bool authenticated) { /* Tell client if they authenticated or not. This is * entirely optional but does demonstrate that you can send * broadcasts to client on pass or fail. */ ResponseBroadcast rb = new() { Passed = authenticated }; NetworkManager.ServerManager.Broadcast(conn, rb, false); } /// /// Called after handling a host authentication result. /// /// Connection authenticating. /// True if authentication passed. protected override void OnHostAuthenticationResult(NetworkConnection conn, bool authenticated) { SendAuthenticationResponse(conn, authenticated); OnAuthenticationResult?.Invoke(conn, authenticated); } } }