fishnet installed
This commit is contained in:
@ -0,0 +1,21 @@
|
||||
|
||||
using FishNet.Broadcast;
|
||||
|
||||
namespace FishNet.Example.Authenticating
|
||||
{
|
||||
public struct HostPasswordBroadcast : IBroadcast
|
||||
{
|
||||
public string Password;
|
||||
}
|
||||
|
||||
public struct PasswordBroadcast : IBroadcast
|
||||
{
|
||||
public string Password;
|
||||
}
|
||||
|
||||
public struct ResponseBroadcast : IBroadcast
|
||||
{
|
||||
public bool Passed;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d26bb0c99070e9b49bc8632dc0b68214
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,152 @@
|
||||
using FishNet.Connection;
|
||||
using FishNet.Example.Authenticating;
|
||||
using FishNet.Managing;
|
||||
using FishNet.Transporting;
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Authenticating
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This authenticator is an example of how to let host bypass the authentication process.
|
||||
/// When checking to authenticate on the client side call AuthenticateAsHost, and if returned true skip normal authentication.
|
||||
/// </summary>
|
||||
public abstract class HostAuthenticator : Authenticator
|
||||
{
|
||||
#region Serialized.
|
||||
/// <summary>
|
||||
/// True to enable use of AuthenticateAsHost.
|
||||
/// </summary>
|
||||
[Tooltip("True to enable use of AuthenticateAsHost.")]
|
||||
[SerializeField]
|
||||
private bool _allowHostAuthentication;
|
||||
/// <summary>
|
||||
/// Sets if to allow host authentication.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void SetAllowHostAuthentication(bool value) => _allowHostAuthentication = value;
|
||||
/// <summary>
|
||||
/// Returns if AllowHostAuthentication is enabled.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool GetAllowHostAuthentication() => _allowHostAuthentication;
|
||||
#endregion
|
||||
|
||||
#region Private.
|
||||
/// <summary>
|
||||
/// A random hash which only exist if the server is started.
|
||||
/// </summary>
|
||||
private static string _hostHash = string.Empty;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Initializes this script for use.
|
||||
/// </summary>
|
||||
/// <param name="networkManager"></param>
|
||||
public override void InitializeOnce(NetworkManager networkManager)
|
||||
{
|
||||
base.InitializeOnce(networkManager);
|
||||
//Listen for connection state of local server to set hash.
|
||||
base.NetworkManager.ServerManager.OnServerConnectionState += ServerManager_OnServerConnectionState;
|
||||
//Listen for broadcast from client. Be sure to set requireAuthentication to false.
|
||||
base.NetworkManager.ServerManager.RegisterBroadcast<HostPasswordBroadcast>(OnHostPasswordBroadcast, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after the local server connection state changes.
|
||||
/// </summary>
|
||||
private void ServerManager_OnServerConnectionState(ServerConnectionStateArgs obj)
|
||||
{
|
||||
int length = (obj.ConnectionState == LocalConnectionState.Started) ? 25 : 0;
|
||||
SetHostHash(length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Received on server when a client sends the password broadcast message.
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection sending broadcast.</param>
|
||||
/// <param name="hpb"></param>
|
||||
private void OnHostPasswordBroadcast(NetworkConnection conn, HostPasswordBroadcast hpb)
|
||||
{
|
||||
//Not accepting host authentications. This could be an attack.
|
||||
if (!_allowHostAuthentication)
|
||||
{
|
||||
conn.Disconnect(true);
|
||||
return;
|
||||
}
|
||||
/* 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.Authenticated)
|
||||
{
|
||||
conn.Disconnect(true);
|
||||
return;
|
||||
}
|
||||
|
||||
bool correctPassword = (hpb.Password == _hostHash);
|
||||
OnHostAuthenticationResult(conn, correctPassword);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after handling a host authentication result.
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection authenticating.</param>
|
||||
/// <param name="authenticated">True if authentication passed.</param>
|
||||
protected abstract void OnHostAuthenticationResult(NetworkConnection conn, bool authenticated);
|
||||
|
||||
/// <summary>
|
||||
/// Sets a host hash of length.
|
||||
/// </summary>
|
||||
/// https://stackoverflow.com/questions/32932679/using-rngcryptoserviceprovider-to-generate-random-string
|
||||
private void SetHostHash(int length)
|
||||
{
|
||||
if (length <= 0)
|
||||
{
|
||||
_hostHash = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
const string charPool = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()";
|
||||
StringBuilder result = new StringBuilder();
|
||||
using (RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider())
|
||||
{
|
||||
byte[] uintBuffer = new byte[sizeof(uint)];
|
||||
while (length-- > 0)
|
||||
{
|
||||
rng.GetBytes(uintBuffer);
|
||||
uint num = BitConverter.ToUInt32(uintBuffer, 0);
|
||||
result.Append(charPool[(int)(num % (uint)charPool.Length)]);
|
||||
}
|
||||
}
|
||||
|
||||
_hostHash = result.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if authentication was sent as host.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected bool AuthenticateAsHost()
|
||||
{
|
||||
if (!_allowHostAuthentication)
|
||||
return false;
|
||||
if (_hostHash == string.Empty)
|
||||
return false;
|
||||
|
||||
HostPasswordBroadcast hpb = new HostPasswordBroadcast()
|
||||
{
|
||||
Password = _hostHash,
|
||||
};
|
||||
|
||||
base.NetworkManager.ClientManager.Broadcast(hpb);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7497d751bb68f444b4343e3edc28e39
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,132 @@
|
||||
using FishNet.Authenticating;
|
||||
using FishNet.Connection;
|
||||
using FishNet.Managing;
|
||||
using FishNet.Managing.Logging;
|
||||
using FishNet.Transporting;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace FishNet.Example.Authenticating
|
||||
{
|
||||
/// <summary>
|
||||
/// This is an example of a password authenticator.
|
||||
/// Never send passwords without encryption.
|
||||
/// </summary>
|
||||
public class PasswordAuthenticator : HostAuthenticator
|
||||
{
|
||||
#region Public.
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public override event Action<NetworkConnection, bool> OnAuthenticationResult;
|
||||
#endregion
|
||||
|
||||
#region Serialized.
|
||||
/// <summary>
|
||||
/// Password to authenticate.
|
||||
/// </summary>
|
||||
[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.
|
||||
base.NetworkManager.ClientManager.OnClientConnectionState += ClientManager_OnClientConnectionState;
|
||||
//Listen for broadcast from client. Be sure to set requireAuthentication to false.
|
||||
base.NetworkManager.ServerManager.RegisterBroadcast<PasswordBroadcast>(OnPasswordBroadcast, false);
|
||||
//Listen to response from server.
|
||||
base.NetworkManager.ClientManager.RegisterBroadcast<ResponseBroadcast>(OnResponseBroadcast);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a connection state changes for the local client.
|
||||
/// </summary>
|
||||
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;
|
||||
//Authentication was sent as host, no need to authenticate normally.
|
||||
if (AuthenticateAsHost())
|
||||
return;
|
||||
|
||||
PasswordBroadcast pb = new PasswordBroadcast()
|
||||
{
|
||||
Password = _password
|
||||
};
|
||||
|
||||
base.NetworkManager.ClientManager.Broadcast(pb);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Received on server when a client sends the password broadcast message.
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection sending broadcast.</param>
|
||||
/// <param name="pb"></param>
|
||||
private void OnPasswordBroadcast(NetworkConnection conn, PasswordBroadcast pb)
|
||||
{
|
||||
/* 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.Authenticated)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Received on client after server sends an authentication response.
|
||||
/// </summary>
|
||||
/// <param name="rb"></param>
|
||||
private void OnResponseBroadcast(ResponseBroadcast rb)
|
||||
{
|
||||
string result = (rb.Passed) ? "Authentication complete." : "Authenitcation failed.";
|
||||
NetworkManager.Log(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends an authentication result to a connection.
|
||||
/// </summary>
|
||||
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 ResponseBroadcast()
|
||||
{
|
||||
Passed = authenticated
|
||||
};
|
||||
base.NetworkManager.ServerManager.Broadcast(conn, rb, false);
|
||||
}
|
||||
/// <summary>
|
||||
/// Called after handling a host authentication result.
|
||||
/// </summary>
|
||||
/// <param name="conn">Connection authenticating.</param>
|
||||
/// <param name="authenticated">True if authentication passed.</param>
|
||||
protected override void OnHostAuthenticationResult(NetworkConnection conn, bool authenticated)
|
||||
{
|
||||
SendAuthenticationResponse(conn, authenticated);
|
||||
OnAuthenticationResult?.Invoke(conn, authenticated);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 226e4eaf2fa685f48bdc3dfaa87c1453
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user