|
9 | 9 | The following example demonstrates implementing a custom SqlAuthenticationProvider and providing the same to SqlClient for overriding Device Code Flow authentication mode: |
10 | 10 | <code language="c#"> |
11 | 11 | using System; |
| 12 | + using System.Collections.Generic; |
| 13 | + using System.Linq; |
12 | 14 | using System.Threading.Tasks; |
13 | | - using Microsoft.Identity.Client; |
14 | 15 | using Microsoft.Data.SqlClient; |
15 | | - |
| 16 | + using Microsoft.Identity.Client; |
| 17 | + |
16 | 18 | namespace CustomAuthenticationProviderExamples |
17 | 19 | { |
18 | 20 | /// <summary> |
|
21 | 23 | /// </summary> |
22 | 24 | public class CustomDeviceCodeFlowAzureAuthenticationProvider : SqlAuthenticationProvider |
23 | 25 | { |
| 26 | + private const string clientId = "my-client-id"; |
| 27 | + private const string clientName = "My Application Name"; |
| 28 | + private const string s_defaultScopeSuffix = "/.default"; |
| 29 | + |
| 30 | + // Maintain a copy of the PublicClientApplication object to cache the underlying access tokens it provides |
| 31 | + private static IPublicClientApplication pcApplication; |
| 32 | + |
24 | 33 | public override async Task<SqlAuthenticationToken> AcquireTokenAsync(SqlAuthenticationParameters parameters) |
25 | 34 | { |
26 | | - string clientId = "my-client-id"; |
27 | | - string clientName = "My Application Name"; |
28 | | - string s_defaultScopeSuffix = "/.default"; |
29 | | - |
30 | 35 | string[] scopes = new string[] { parameters.Resource.EndsWith(s_defaultScopeSuffix) ? parameters.Resource : parameters.Resource + s_defaultScopeSuffix }; |
31 | | - |
32 | | - IPublicClientApplication app = PublicClientApplicationBuilder.Create(clientId) |
33 | | - .WithAuthority(parameters.Authority) |
34 | | - .WithClientName(clientName) |
35 | | - .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient") |
| 36 | + |
| 37 | + IPublicClientApplication app = pcApplication; |
| 38 | + if (app == null) |
| 39 | + { |
| 40 | + pcApplication = app = PublicClientApplicationBuilder.Create(clientId) |
| 41 | + .WithAuthority(parameters.Authority) |
| 42 | + .WithClientName(clientName) |
| 43 | + .WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient") |
36 | 44 | .Build(); |
37 | | - |
38 | | - AuthenticationResult result = await app.AcquireTokenWithDeviceCode(scopes, |
39 | | - deviceCodeResult => CustomDeviceFlowCallback(deviceCodeResult)).ExecuteAsync(); |
| 45 | + } |
| 46 | + |
| 47 | + AuthenticationResult result; |
| 48 | + |
| 49 | + try |
| 50 | + { |
| 51 | + IEnumerable<IAccount> accounts = await app.GetAccountsAsync(); |
| 52 | + result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync(); |
| 53 | + } |
| 54 | + catch (MsalUiRequiredException) |
| 55 | + { |
| 56 | + result = await app.AcquireTokenWithDeviceCode(scopes, |
| 57 | + deviceCodeResult => CustomDeviceFlowCallback(deviceCodeResult)).ExecuteAsync(); |
| 58 | + } |
| 59 | + |
40 | 60 | return new SqlAuthenticationToken(result.AccessToken, result.ExpiresOn); |
41 | 61 | } |
42 | | - |
43 | | - public override bool IsSupported(SqlAuthenticationMethod authenticationMethod) => |
44 | | - authenticationMethod.Equals(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow); |
45 | | - |
46 | | - private Task CustomDeviceFlowCallback(DeviceCodeResult result) |
| 62 | + |
| 63 | + public override bool IsSupported(SqlAuthenticationMethod authenticationMethod) => authenticationMethod.Equals(SqlAuthenticationMethod.ActiveDirectoryDeviceCodeFlow); |
| 64 | + |
| 65 | + private static Task<int> CustomDeviceFlowCallback(DeviceCodeResult result) |
47 | 66 | { |
48 | 67 | Console.WriteLine(result.Message); |
49 | 68 | return Task.FromResult(0); |
50 | 69 | } |
51 | 70 | } |
52 | | - |
| 71 | + |
53 | 72 | public class Program |
54 | 73 | { |
55 | 74 | public static void Main() |
|
0 commit comments