You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

85 lines
2.7 KiB

2 years ago
  1. using Microsoft.Identity.Client;
  2. using System.Threading;
  3. using System.Web;
  4. namespace WebApp.Outlook.TokenStorage
  5. {
  6. public class SessionTokenCache
  7. {
  8. private static ReaderWriterLockSlim SessionLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
  9. private string UserId = string.Empty;
  10. private string CacheId = string.Empty;
  11. private HttpContextBase httpContext = null;
  12. private TokenCache cache = new TokenCache();
  13. public SessionTokenCache(string userId, HttpContextBase httpcontext)
  14. {
  15. // not object, we want the SUB
  16. UserId = userId;
  17. CacheId = UserId + "_TokenCache";
  18. httpContext = httpcontext;
  19. Load();
  20. }
  21. public TokenCache GetMsalCacheInstance()
  22. {
  23. cache.SetBeforeAccess(BeforeAccessNotification);
  24. cache.SetAfterAccess(AfterAccessNotification);
  25. Load();
  26. return cache;
  27. }
  28. public void SaveUserStateValue(string state)
  29. {
  30. SessionLock.EnterWriteLock();
  31. httpContext.Session[CacheId + "_state"] = state;
  32. SessionLock.ExitWriteLock();
  33. }
  34. public string ReadUserStateValue()
  35. {
  36. var state = string.Empty;
  37. SessionLock.EnterReadLock();
  38. state = (string)httpContext.Session[CacheId + "_state"];
  39. SessionLock.ExitReadLock();
  40. return state;
  41. }
  42. public void Load()
  43. {
  44. SessionLock.EnterReadLock();
  45. cache.Deserialize((byte[])httpContext.Session[CacheId]);
  46. SessionLock.ExitReadLock();
  47. }
  48. public void Persist()
  49. {
  50. SessionLock.EnterWriteLock();
  51. // Optimistically set HasStateChanged to false. We need to do it early to avoid losing
  52. // changes made by a concurrent thread.
  53. cache.HasStateChanged = false;
  54. // Reflect changes in the persistent store
  55. httpContext.Session[CacheId] = cache.Serialize();
  56. SessionLock.ExitWriteLock();
  57. }
  58. // Triggered right before MSAL needs to access the cache. Reload the cache from the
  59. // persistent store in case it changed since the last access.
  60. private void BeforeAccessNotification(TokenCacheNotificationArgs args)
  61. {
  62. Load();
  63. }
  64. // Triggered right after MSAL accessed the cache.
  65. private void AfterAccessNotification(TokenCacheNotificationArgs args)
  66. {
  67. // if the access operation resulted in a cache update
  68. if (cache.HasStateChanged)
  69. {
  70. Persist();
  71. }
  72. }
  73. }
  74. }