-
Notifications
You must be signed in to change notification settings - Fork 14
/
AzureAuthToken.cs
129 lines (116 loc) · 5.38 KB
/
AzureAuthToken.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
namespace Microsoft.Translator.API
{
/// <summary>
/// Client to call Cognitive Services Azure Auth Token service in order to get an access token.
/// Exposes asynchronous as well as synchronous methods.
/// </summary>
public class AzureAuthToken
{
/// URL of the token service
private static readonly Uri ServiceUrl = new Uri("https://api.cognitive.microsoft.com/sts/v1.0/issueToken");
/// Name of header used to pass the subscription key to the token service
private const string OcpApimSubscriptionKeyHeader = "Ocp-Apim-Subscription-Key";
/// After obtaining a valid token, this class will cache it for this duration.
/// Use a duration of 5 minutes, which is less than the actual token lifetime of 10 minutes.
private static readonly TimeSpan TokenCacheDuration = new TimeSpan(0, 5, 0);
/// Cache the value of the last valid token obtained from the token service.
private string storedTokenValue = string.Empty;
/// When the last valid token was obtained.
private DateTime storedTokenTime = DateTime.MinValue;
/// Gets the subscription key.
public string SubscriptionKey { get; private set; } = string.Empty;
/// Gets the HTTP status code for the most recent request to the token service.
public HttpStatusCode RequestStatusCode { get; private set; }
/// <summary>
/// Creates a client to obtain an access token.
/// </summary>
/// <param name="key">Subscription key to use to get an authentication token.</param>
public AzureAuthToken(string key)
{
if (string.IsNullOrEmpty(key))
{
throw new ArgumentNullException("key", "A subscription key is required");
}
this.SubscriptionKey = key;
this.RequestStatusCode = HttpStatusCode.InternalServerError;
}
/// <summary>
/// Gets a token for the specified subscription.
/// </summary>
/// <returns>The encoded JWT token prefixed with the string "Bearer ".</returns>
/// <remarks>
/// This method uses a cache to limit the number of request to the token service.
/// A fresh token can be re-used during its lifetime of 10 minutes. After a successful
/// request to the token service, this method caches the access token. Subsequent
/// invocations of the method return the cached token for the next 5 minutes. After
/// 5 minutes, a new token is fetched from the token service and the cache is updated.
/// </remarks>
public async Task<string> GetAccessTokenAsync()
{
if (SubscriptionKey == string.Empty) return string.Empty;
// Re-use the cached token if there is one.
if ((DateTime.Now - storedTokenTime) < TokenCacheDuration)
{
return storedTokenValue;
}
using (var client = new HttpClient())
using (var request = new HttpRequestMessage())
{
request.Method = HttpMethod.Post;
request.RequestUri = ServiceUrl;
request.Content = new StringContent(string.Empty);
request.Headers.TryAddWithoutValidation(OcpApimSubscriptionKeyHeader, this.SubscriptionKey);
client.Timeout = TimeSpan.FromSeconds(2);
var response = await client.SendAsync(request);
this.RequestStatusCode = response.StatusCode;
response.EnsureSuccessStatusCode();
var token = await response.Content.ReadAsStringAsync();
storedTokenTime = DateTime.Now;
storedTokenValue = "Bearer " + token;
return storedTokenValue;
}
}
/// <summary>
/// Gets a token for the specified subscription. Synchronous version.
/// Use of async version preferred
/// </summary>
/// <returns>The encoded JWT token prefixed with the string "Bearer ".</returns>
/// <remarks>
/// This method uses a cache to limit the number of request to the token service.
/// A fresh token can be re-used during its lifetime of 10 minutes. After a successful
/// request to the token service, this method caches the access token. Subsequent
/// invocations of the method return the cached token for the next 5 minutes. After
/// 5 minutes, a new token is fetched from the token service and the cache is updated.
/// </remarks>
public string GetAccessToken()
{
// Re-use the cached token if there is one.
if ((DateTime.Now - storedTokenTime) < TokenCacheDuration)
{
return storedTokenValue;
}
string accessToken = null;
var task = Task.Run(async () =>
{
accessToken = await GetAccessTokenAsync();
});
while (!task.IsCompleted)
{
System.Threading.Thread.Yield();
}
if (task.IsFaulted)
{
throw task.Exception;
}
else if (task.IsCanceled)
{
throw new Exception("Timeout obtaining access token.");
}
return accessToken;
}
}
}