unity使用BestHTTP插件连接到SignalR做身份验证
最近研究了下.net core webapi,搞到SignalR时,想使用SignalR代替WebSockt(SignalR内部也是WebSockt)做一些事情。 然后通过使用BestHTTP插件连接到SignalR,并使用Token验证身份,也简单提到Cookie验证身份的方法。
public class HubManager : MonoBehaviour
{
public string url = $" https://localhost:5001";
private string _token;
private HubConnection _hub;
private async Task Start()
{
//StartCoroutine(GetToken1());//使用UnityWebRequest获取Token
_token = await GetToken();//获取token
await ConnectHubAsync(url, _token);//连接SignalR
}
// BestHTTP请求获取Token
// 也可以放在IAuthenticationProvider接口中的StartAuthentication方法获取
private Task<string> GetToken()
{
Uri uri = new Uri(this.url + "/Token/CreateToken");
LoginRequest loginRequest = new LoginRequest("admin", "123456");
string json = JsonMapper.ToJson(loginRequest);
byte[] bytes = Encoding.UTF8.GetBytes(json);
HTTPRequest request = new HTTPRequest(uri, HTTPMethods.Post);
request.AddHeader("Content-Type", "application/json;charset=utf-8");
request.RawData = bytes;
return request.GetAsStringAsync();
}
//连接SignalR
public async Task ConnectHubAsync(string urlStr, string token)
{
JsonProtocol protocol = new JsonProtocol(new LitJsonEncoder());
_hub = new HubConnection(new Uri(urlStr + "/hub"), protocol);
//添加token,作为身份认证(这就需要再连接前拿到token)
//如果不使用token,就再OnConnected中添加认证(前期不成熟的方案)
//如果使用cookie验证,可以参考SampleCookieAuthentication类改一下
//对IAuthenticationProvider接口理解在下面
_hub.AuthenticationProvider = new HeaderAuthenticator(token);
_hub.OnConnected += OnConnected;
_hub.OnError += OnError;
_hub.OnClosed += OnClosed;
_hub.On<string>("ReceiveMsg", ReceiveMsg);//接收信息
await _hub.ConnectAsync();//需要连接
await PublicChat("Hi");
//_hub.NegotiationResult.AccessToken = _token;
}
//使用UnityWebRequest获取Token
private IEnumerator GetToken1()
{
//https://localhost:7296/Token/CreateToken
string urlStr = this.url + "/Token/CreateToken";
LoginRequest loginRequest = new LoginRequest("admin", "123456");
string json = JsonMapper.ToJson(loginRequest);
byte[] bytes = Encoding.UTF8.GetBytes(json);
UnityWebRequest request = new UnityWebRequest()
{
url = urlStr,
method = UnityWebRequest.kHttpVerbPOST,
uploadHandler = new UploadHandlerRaw(bytes),
downloadHandler = new DownloadHandlerBuffer()
};
request.SetRequestHeader("Content-Type", "application/json;charset=utf-8");
yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success)
{
Debug.Log(request.error);
}
else
{
_token = request.downloadHandler.text;
Debug.Log(_token);
}
}
// 群聊
public async Task PublicChat(string msg)
{
//ReceiveMsg 为SignalR为接收信息的方法名
await _hub.SendAsync("ReceiveMsg", msg);
}
// 私聊
public async Task PrivateChat(int id, string msg)
{
await _hub.SendAsync("PrivateChat", id, msg);
}
// 接收消息
private void ReceiveMsg(string msg)
{
Debug.Log($"Hub -> {msg}");
}
// hub关闭时调用
private void OnClosed(HubConnection connection)
{
Debug.Log("Hub -> 与服务端断开连接...");
}
// hub异常
private void OnError(HubConnection connection, string error)
{
Debug.LogError($"Hub -> {error}");
}
// Hub连接成功
private void OnConnected(HubConnection connection)
{
Debug.Log("Hub -> 与服务端建立连接...");
// 身份认证,不使用token或cookie时用的
// connection.SendAsync("AddConnected", 1, "gzhen");
}
}
public record LoginRequest
{
public string Username { private set; get; }
public string Password { private set; get; }
public LoginRequest(string username, string password)
{
Username = username;
Password = password;
}
}
.net core webapi 发布Token代码
[HttpPost]
public ActionResult<string> CreateToken(LoginRequest request)
{
if (request.Username.Equals("admin") && request.Password.Equals("123456"))
{
//添加token
List<Claim> claims = new();
claims.Add(new Claim(ClaimTypes.NameIdentifier, "1"));//id
claims.Add(new Claim(ClaimTypes.Name, "admin"));//名字
claims.Add(new Claim(ClaimTypes.Role, "admin"));//角色
byte[] keyBytes = Encoding.UTF8.GetBytes(_tokenSetting.Value.SecKey);
DateTime expire = DateTime.Now.AddSeconds(_tokenSetting.Value.ExpireSeconds);//超时时间
SymmetricSecurityKey key = new(keyBytes);
SigningCredentials credentials = new(key, SecurityAlgorithms.HmacSha256Signature);
JwtSecurityToken token = new(claims: claims, expires: expire, signingCredentials: credentials);
string tokenStr = new JwtSecurityTokenHandler().WriteToken(token);
return Ok(tokenStr);
}
else
{
return BadRequest();
}
}
SignalR 验证身份代码
public class NotificationHub : Hub
{
private static readonly List<User> users = new List<User>();
private readonly ILogger<NotificationHub> _logger;
public NotificationHub(ILogger<NotificationHub> logger)
{
_logger = logger;
}
public override Task OnConnectedAsync()
{
//_logger.LogInformation($"与[{Context.ConnectionId}]建立连接...");
//使用token作为身份认证
string id = Context.User.FindFirstValue(ClaimTypes.NameIdentifier);
string name = Context.User.FindFirstValue(ClaimTypes.Name);
_logger.LogInformation($"与[id:{id} username:{name}]建立连接...");
User user = new User(int.Parse(id), name, Context.ConnectionId);
users.Add(user);
return base.OnConnectedAsync();
}
}
IAuthenticationProvider接口理解
此接口使用来做身份认证的接口,HeaderAuthenticator和SampleCookieAuthentication都继承此接口,也可以根据这两个类理解的此接口。
public interface IAuthenticationProvider
{
/// <summary>
/// 是否对开启身份认证
/// </summary>
bool IsPreAuthRequired { get; }
/// <summary>
/// 身份认证的成功的回调,如果IsPreAuthRequired为fasle则不验证。
/// </summary>
event OnAuthenticationSuccededDelegate OnAuthenticationSucceded;
/// <summary>
/// 身份认证的失败的回调
/// </summary>
event OnAuthenticationFailedDelegate OnAuthenticationFailed;
/// <summary>
/// 开始验证,如果IsPreAuthRequired则不调用。
/// 可以获取token,cookie等信息的操作可以搬到在此处
/// </summary>
void StartAuthentication();
/// <summary>
/// 准备请求,将得到的token,cookie等数据在此处做整理。
/// </summary>
void PrepareRequest(HTTPRequest request, RequestTypes type);
}
完结散花。欢迎来讨论,提出意见。