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.

172 lines
6.2 KiB

2 years ago
  1. using EasyBL;
  2. using Microsoft.Identity.Client;
  3. using Microsoft.Office365.OutlookServices;
  4. using System;
  5. using System.Linq;
  6. using System.Security.Claims;
  7. using System.Threading.Tasks;
  8. using System.Web;
  9. using WebApp.Outlook.TokenStorage;
  10. namespace WebApp.Outlook.AuthProvider
  11. {
  12. public sealed class AuthProvider : IAuthProvider
  13. {
  14. // Properties used to get and manage an access token.
  15. private readonly string redirectUri = ServiceHelper.RedirectUri;
  16. private readonly string appId = ServiceHelper.AppId;
  17. private readonly string appPassword = ServiceHelper.AppSecret;
  18. private readonly string graphScopes = ServiceHelper.Scopes;
  19. private readonly string graphScopes_Outlook = ServiceHelper.Scopes_Outlook;
  20. private static readonly AuthProvider instance = new AuthProvider();
  21. private AuthProvider()
  22. {
  23. }
  24. public static AuthProvider Instance
  25. {
  26. get
  27. {
  28. return instance;
  29. }
  30. }
  31. public string AppPassword => appPassword;
  32. /// <summary>
  33. /// </summary>
  34. /// <returns></returns>
  35. public async Task<string> GetAccessTokenAsync()
  36. {
  37. try
  38. {
  39. string accessToken = null;
  40. // Load the app config from web.config
  41. // Get the current user's ID
  42. var signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
  43. if (!string.IsNullOrEmpty(signedInUserID))
  44. {
  45. // Get the user's token cache
  46. var httpContextWrapper = new HttpContextWrapper(HttpContext.Current);
  47. var tokenCache = new SessionTokenCache(signedInUserID, httpContextWrapper).GetMsalCacheInstance();
  48. var cca = new ConfidentialClientApplication(appId, redirectUri, new ClientCredential(AppPassword), tokenCache, null);
  49. // Call AcquireTokenSilentAsync, which will return the cached access token if it
  50. // has not expired. If it has expired, it will handle using the refresh token to
  51. // get a new one.
  52. var scopes = graphScopes.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
  53. var result = await cca.AcquireTokenSilentAsync(scopes, cca.Users.First());
  54. accessToken = result.AccessToken;
  55. }
  56. return accessToken;
  57. }
  58. catch (Exception)
  59. {
  60. return null;
  61. }
  62. }
  63. /// <summary>
  64. /// </summary>
  65. /// <returns></returns>
  66. public async Task<string> GetOutlookAccessTokenAsync()
  67. {
  68. try
  69. {
  70. string accessToken = null;
  71. // Get the current user's ID
  72. var signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
  73. if (!string.IsNullOrEmpty(signedInUserID))
  74. {
  75. var httpContextWrapper = new HttpContextWrapper(HttpContext.Current);
  76. var tokenCache = new SessionTokenCache(signedInUserID, httpContextWrapper).GetMsalCacheInstance();
  77. var cca = new ConfidentialClientApplication(appId, redirectUri, new ClientCredential(AppPassword), tokenCache, null);
  78. var scopes = graphScopes_Outlook.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
  79. var result = await cca.AcquireTokenSilentAsync(scopes, cca.Users.First());
  80. accessToken = result.AccessToken;
  81. }
  82. return accessToken;
  83. }
  84. catch (Exception ex)
  85. {
  86. return null;
  87. }
  88. }
  89. /// <summary>
  90. /// </summary>
  91. /// <returns></returns>
  92. public async Task<string> GetCacheOutlookAccessTokenAsync()
  93. {
  94. try
  95. {
  96. var accessToken = (string)HttpRuntimeCache.Get("outlookaccesstoken");
  97. return accessToken;
  98. }
  99. catch (Exception ex)
  100. {
  101. return null;
  102. }
  103. }
  104. /// <summary>
  105. /// </summary>
  106. /// <returns></returns>
  107. public async Task<string> GetUserEmailAsync()
  108. {
  109. var client = new OutlookServicesClient(new Uri("https://outlook.office.com/api/v2.0"), AuthProvider.Instance.GetOutlookAccessTokenAsync);
  110. try
  111. {
  112. var userDetail = (User)await client.Me.ExecuteAsync();
  113. return userDetail.EmailAddress;
  114. }
  115. catch (MsalException ex)
  116. {
  117. return $"#ERROR#: Could not get user's email address. {ex.Message}";
  118. }
  119. }
  120. /// <summary>
  121. /// 請求初始化
  122. /// </summary>
  123. /// <param name="email">todo: describe email parameter on GetRequestAsync</param>
  124. /// <returns></returns>
  125. public async Task<OutlookServicesClient> GetRequestAsync(string email = null)
  126. {
  127. var userEmail = email;
  128. if (email == null)
  129. {
  130. userEmail = await GetUserEmailAsync();
  131. }
  132. Func<Task<string>> Getter = AuthProvider.Instance.GetOutlookAccessTokenAsync;
  133. if (email != null)
  134. {
  135. Getter = AuthProvider.Instance.GetCacheOutlookAccessTokenAsync;
  136. }
  137. var client = new OutlookServicesClient(new Uri("https://outlook.office.com/api/v2.0"), Getter);
  138. client.Context.SendingRequest2 += new EventHandler<Microsoft.OData.Client.SendingRequest2EventArgs>(
  139. (sender, e) => InsertXAnchorMailboxHeader(e, userEmail));
  140. return client;
  141. }
  142. /// <summary>
  143. /// 添加Header郵件地址
  144. /// </summary>
  145. /// <param name="sender"></param>
  146. /// <param name="e"></param>
  147. /// <param name="email"></param>
  148. public void InsertXAnchorMailboxHeader(Microsoft.OData.Client.SendingRequest2EventArgs e, string email)
  149. {
  150. e.RequestMessage.SetHeader("X-AnchorMailbox", email);
  151. }
  152. }
  153. }