Add basic caching for authentication tokens
This commit is contained in:
parent
5f97bcfa71
commit
ccff9a40b5
13
ChaosBot/Services/ICache.cs
Normal file
13
ChaosBot/Services/ICache.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
|
||||
namespace ChaosBot.Services
|
||||
{
|
||||
public interface ICache<T, TU>
|
||||
{
|
||||
void Invalidate();
|
||||
void Add(T key, TU value, DateTime expires);
|
||||
void Remove(T key);
|
||||
TU Get(T key);
|
||||
bool HasKey(T key);
|
||||
}
|
||||
}
|
||||
49
ChaosBot/WebServer/AccessTokenCache.cs
Normal file
49
ChaosBot/WebServer/AccessTokenCache.cs
Normal file
@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ChaosBot.Services;
|
||||
|
||||
namespace ChaosBot.WebServer
|
||||
{
|
||||
public class AccessTokenCache : ICache<string, string>
|
||||
{
|
||||
private Dictionary<string, Tuple<string, DateTime>> _cache = new Dictionary<string, Tuple<string, DateTime>>();
|
||||
|
||||
public void Invalidate()
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
_cache = _cache
|
||||
.Where(v => v.Value.Item2 > now)
|
||||
.ToDictionary(x => x.Key, x => x.Value);
|
||||
}
|
||||
|
||||
public void Add(string key, string value, DateTime expires)
|
||||
{
|
||||
_cache.Add(key, new Tuple<string, DateTime>(value, expires));
|
||||
}
|
||||
|
||||
public void Remove(string key)
|
||||
{
|
||||
_cache.Remove(key);
|
||||
}
|
||||
|
||||
public string Get(string key)
|
||||
{
|
||||
if (!_cache.TryGetValue(key, out Tuple<string, DateTime> data))
|
||||
throw new KeyNotFoundException();
|
||||
|
||||
return data.Item1;
|
||||
}
|
||||
|
||||
public bool HasKey(string key)
|
||||
{
|
||||
return _cache.ContainsKey(key);
|
||||
}
|
||||
|
||||
public List<string> GetKeys()
|
||||
{
|
||||
return _cache.Keys.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
@ -15,6 +16,7 @@ namespace ChaosBot.WebServer.App
|
||||
[Route("/api/discord")]
|
||||
public class DiscordController : Controller
|
||||
{
|
||||
private static readonly AccessTokenCache Cache = WebServer.Cache;
|
||||
private static readonly HttpClient client = new HttpClient();
|
||||
private static readonly ILogger Logger = Program.Logger;
|
||||
|
||||
@ -43,6 +45,9 @@ namespace ChaosBot.WebServer.App
|
||||
string responseString = await response.Content.ReadAsStringAsync();
|
||||
DiscordOauthResponse responseObject = JsonConvert.DeserializeObject<DiscordOauthResponse>(responseString);
|
||||
|
||||
DiscordUserResponse userResponse = GetDiscordUser(responseObject.access_token);
|
||||
Cache.Add(responseObject.access_token, userResponse.id, DateTime.Now.AddSeconds(responseObject.expires_in));
|
||||
|
||||
return LocalRedirect($"/#/?access_token={responseObject.access_token}");
|
||||
}
|
||||
|
||||
@ -52,16 +57,7 @@ namespace ChaosBot.WebServer.App
|
||||
if (!Request.Cookies.TryGetValue("access_token", out string accessToken))
|
||||
accessToken = null;
|
||||
|
||||
HttpResponseMessage response;
|
||||
using (HttpRequestMessage requestMessage =
|
||||
new HttpRequestMessage(HttpMethod.Get, "https://discord.com/api/v7/users/@me"))
|
||||
{
|
||||
requestMessage.Headers.Authorization =
|
||||
new AuthenticationHeaderValue("Bearer", accessToken);
|
||||
response = client.SendAsync(requestMessage).GetAwaiter().GetResult();
|
||||
}
|
||||
string responseString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
|
||||
DiscordUserResponse userResponse = JsonConvert.DeserializeObject<DiscordUserResponse>(responseString);
|
||||
DiscordUserResponse userResponse = GetDiscordUser(accessToken);
|
||||
|
||||
return Json(userResponse);
|
||||
}
|
||||
@ -85,6 +81,22 @@ namespace ChaosBot.WebServer.App
|
||||
|
||||
return Json(userResponse);
|
||||
}
|
||||
|
||||
private static DiscordUserResponse GetDiscordUser(string accessToken)
|
||||
{
|
||||
HttpResponseMessage response;
|
||||
using (HttpRequestMessage requestMessage =
|
||||
new HttpRequestMessage(HttpMethod.Get, "https://discord.com/api/v7/users/@me"))
|
||||
{
|
||||
requestMessage.Headers.Authorization =
|
||||
new AuthenticationHeaderValue("Bearer", accessToken);
|
||||
response = client.SendAsync(requestMessage).GetAwaiter().GetResult();
|
||||
}
|
||||
|
||||
string responseString = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
|
||||
DiscordUserResponse userResponse = JsonConvert.DeserializeObject<DiscordUserResponse>(responseString);
|
||||
return userResponse;
|
||||
}
|
||||
}
|
||||
|
||||
internal class DiscordOauthResponse
|
||||
|
||||
@ -30,6 +30,9 @@ namespace ChaosBot.WebServer
|
||||
options.ForwardedHeaders =
|
||||
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||
});
|
||||
|
||||
services
|
||||
.AddSingleton(sp => new AccessTokenCache());
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline
|
||||
|
||||
@ -11,6 +11,8 @@ namespace ChaosBot.WebServer
|
||||
{
|
||||
public static class WebServer
|
||||
{
|
||||
public static readonly AccessTokenCache Cache = new AccessTokenCache();
|
||||
|
||||
public static void Start(string[] args)
|
||||
{
|
||||
CreateHostBuilder(args).Build().Run();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user