Azure AD, Endpoint Manger(Intune), SharePoint access token 的获取
云霄宇霁 人气:0本章全是干货,干货,干货,重要的事情说三遍。
最近在研究Azure, Cloud相关的东西,项目中用的是Graph API(这个在下一章会相信介绍),可能是Graph API推出的时间比较晚,部分API还在开发中,所以难免出现部分功能支持不完善,issue之类的,当然Microsoft也在不断更新完善中,期待Graph API时代的到来。
针对以上的问题,有时在项目中不得不采取一些非常规的手段,调用Microsoft backend API,什么是backend API呢,就是我们用Fiddle监控或者页面F12 Network 看到Microsoft调用的底层Rest API。
例如:Azure AD的Company Branding功能,Graph V 1.0版本没有API支持,但项目需要,怎么办?
1)、是查找是否有Beta版本,如果有,项目组决定是否可以使用Beta API ,因为Microsoft 官网是不建议Beta API应用于生产环境的。
https://docs.microsoft.com/en-us/graph/api/resources/organizationalbrandingproperties?view=graph-rest-beta
2)、就是我们今天说的重点,调用Microsoft backend API
首先说明一下啊,所有获取token的token endpoint都是统一地址:
private string _tokenEndpoint = "https://login.microsoftonline.com/common/oauth2/token";
1、 Backend API Access Token
调用backend api,重点是获取access token,这里是impersonate user login(模拟用户登录的方式)。
private async Task<string> GetAADAccessToken(string username, string password) { var resource = $"resource=74658136-14ec-4630-ad9b-26e160ff0fc6&client_id=1950a258-227b-4e31-a9cf-717495945fc2&grant_type=password&username={username}&password={password}"; return await GetAccessToken(resource); } private async Task<string> GetAccessToken(string resource) { var httpClient = new HttpClient(); using (var stringContent = new StringContent(resource, Encoding.UTF8, "application/x-www-form-urlencoded")) { try { var result = await httpClient.PostAsync(_tokenEndpoint, stringContent).ContinueWith((response) => { return response.Result.Content.ReadAsStringAsync().Result; }).ConfigureAwait(false); var tokenResult = JsonSerializer.Deserialize<JsonElement>(result); var token = tokenResult.GetProperty("access_token").GetString(); return token; } catch (Exception ex) { throw new TokenException(ErrorCode.BadRequest, ex.Message); } } }
解释一下哈:
“1950a258-227b-4e31-a9cf-717495945fc2” 是Microsoft build-in的application Id,
“74658136-14ec-4630-ad9b-26e160ff0fc6” 是token的颁发地址
以上两个ID是固定值,直接使用就可以。
获取到了access token,接下需要构建HTTP Client:
private HttpClient BuildHttpClient(string accessToken) { var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); httpClient.DefaultRequestHeaders.Add("X-Requested-With", "XMLHttpRequest"); httpClient.DefaultRequestHeaders.Add("x-ms-client-request-id", $"{new Guid()}"); httpClient.DefaultRequestHeaders.Add("x-ms-correlation-id", $"{new Guid()}"); return httpClient; }
最后发送HTTP请求,获取数据信息:
private static IEnumerable<CompanyBrandingModel> GetCompanyBrandings() { var services = new ServiceCollection(); var provider = services.ConfigureServices().BuildServiceProvider(); var httpClientService = provider.GetService<IHttpClientService>(); var httpClient = httpClientService?.GetHttpClient(_username, _password, TokenType.AzureAD, _clientId).GetAwaiter().GetResult(); var requestUrl = "https://main.iam.ad.ext.azure.com/api/LoginTenantBrandings"; var response = httpClient?.GetAsync(requestUrl).GetAwaiter().GetResult(); var content = response?.Content.ReadAsStringAsync().Result; var brandings = JsonConvert.DeserializeObject<List<CompanyBrandingModel>>(content) .Where(b => b.isConfigured.HasValue && b.isConfigured.Value); return brandings; }
获取的结果和页面一致,证明backend API还是可行的,哈哈。
2、Graph Token
Graph API官网为我们提供了多种方式使用Graph API:
1、通过Nuget 安装Graph SDK,调用Graph SDK
构建GraphServiceClient对象,这里提供了2种方式,Delegated 和 Application,Application又分Secret 和 Certification,我们这里只介绍Application Secret。
public GraphServiceClient GetGraphServiceClientByApp(string tenantId, string clientId, string clientSecret) { var confidentialClientApplication = ConfidentialClientApplicationBuilder .Create(clientId) .WithTenantId(tenantId) .WithClientSecret(clientSecret) .Build(); var credentialProvider = new ClientCredentialProvider(confidentialClientApplication); var graphClient = new GraphServiceClient(credentialProvider); return graphClient; }
2、调用Graph Rest API,首先需要获取Graph access token,示例代码如下:
public async Task<string> GetAppAccessToken(string clientId, string clientSecret)
{
if (string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(clientSecret))
{
throw new TokenException(ErrorCode.InvalidArguments, ExceptionConstants.NullOrEmpty);
}
var resource = $"scope=https://graph.microsoft.com/.default&grant_type=client_credentials&client_id={clientId}&client_secret={clientSecret}";
return await GetAccessToken(resource);
}
有了access token之后,就可以构建http client,发送http请求了,同上,这里就不在累述了,说多了都是废话,标题就是干货,干货,干货。
3、SharePoint access token
操作SharePoint的API有好多种,这里咱们只说Asp.NET Core CSOM, .NET Framework比较简单,这里就不多说了,想了解的下方留言吧。
首先获取SharePoint access token,直接干代码:
private async Task<string> GetSPAccessToken(string username, string password, string clientId) { var spAdminUrl = $"https://{username.Substring(username.IndexOf("@") + 1, username.IndexOf(".") - username.IndexOf("@") - 1)}-admin.sharepoint.com/"; try { var uri = new Uri(spAdminUrl); string _resource = $"{uri.Scheme}://{uri.DnsSafeHost}"; var resource = $"resource={_resource}&client_id={clientId}&grant_type=password&username={HttpUtility.UrlEncode(username)}&password={HttpUtility.UrlEncode(password)}"; return await GetAccessToken(resource); } catch (System.UriFormatException e) { throw new UriFormatException(e.Message, e); } }
拿到token之后,通过Nuget安装package,构建ClientContext对象:
public class SPClientContextService { private readonly ITokenCacheService _tokenCacheService; public SPClientContextService(ITokenCacheService tokenCacheService) { this._tokenCacheService = tokenCacheService; } public async Task<ClientContext> GetSPClientContextInstance(string username, string password, string clientId) { var accessToken = await _tokenCacheService.TryGetValue(username, password, TokenType.SharePoint, clientId); var spAdminUrl = $"https://{username.Substring(username.IndexOf("@") + 1, username.IndexOf(".") - username.IndexOf("@") - 1)}-admin.sharepoint.com/"; var context = new ClientContext(new Uri(spAdminUrl)); context.ExecutingWebRequest += (sender, e) => { e.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + accessToken; }; return context; } }
OK,篇幅已经比较长了,如需了解更多,请在下方留言,源码请参见Github。
加载全部内容