Получить фотографию профиля пользователя из Azure
У меня есть приложение для нескольких арендаторов на лазурном. Я могу войти в систему и получить базовую информацию о пользователе, например имя и адрес электронной почты.
Теперь мне нужно получить фотографию профиля пользователя из лазурного. Я попробовал некоторые решения, представленные в Интернете, но ни одно из них не работает для меня.
Вот мой Startup.Auth.cs
код
public partial class Startup
{
private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private string appKey = ConfigurationManager.AppSettings["ida:ClientSecret"];
private string graphResourceID = "https://graph.windows.net";
private static string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
private string authority = aadInstance + "common";
private ApplicationDbContext db = new ApplicationDbContext();
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions { });
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
{
// instead of using the default validation (validating against a single issuer value, as we do in line of business apps),
// we inject our own multitenant validation logic
ValidateIssuer = false,
},
Notifications = new OpenIdConnectAuthenticationNotifications()
{
SecurityTokenValidated = (context) =>
{
return Task.FromResult(0);
},
AuthorizationCodeReceived = (context) =>
{
var code = context.Code;
ClientCredential credential = new ClientCredential(clientId, appKey);
string tenantID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
AuthenticationContext authContext = new AuthenticationContext(aadInstance + tenantID, new ADALTokenCache(signedInUserID));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceID);
return Task.FromResult(0);
},
AuthenticationFailed = (context) =>
{
context.OwinContext.Response.Redirect("/Home/Error");
context.HandleResponse(); // Suppress the exception
return Task.FromResult(0);
}
}
});
}
}
Вот код для получения основной информации пользователя
private ApplicationDbContext db = new ApplicationDbContext();
private string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private string appKey = ConfigurationManager.AppSettings["ida:ClientSecret"];
private string aadInstance = ConfigurationManager.AppSettings["ida:AADInstance"];
private string graphResourceID = "https://graph.windows.net";
// GET: UserProfile
public async Task<ActionResult> Index()
{
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
try
{
Uri servicePointUri = new Uri(graphResourceID);
Uri serviceRoot = new Uri(servicePointUri, tenantID);
ActiveDirectoryClient activeDirectoryClient = new ActiveDirectoryClient(serviceRoot,
async () => await GetTokenForApplication());
// use the token for querying the graph to get the user details
var result = await activeDirectoryClient.Users
.Where(u => u.ObjectId.Equals(userObjectID))
.ExecuteAsync();
IUser user = result.CurrentPage.ToList().First();
return View(user);
}
catch (AdalException)
{
// Return to error page.
return View("Error");
}
// if the above failed, the user needs to explicitly re-authenticate for the app to obtain the required token
catch (Exception)
{
return View("Relogin");
}
}
public void RefreshSession()
{
HttpContext.GetOwinContext().Authentication.Challenge(
new AuthenticationProperties { RedirectUri = "/UserProfile" },
OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
public async Task<string> GetTokenForApplication()
{
string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
// get a token for the Graph without triggering any user interaction (from the cache, via multi-resource refresh token, etc)
ClientCredential clientcred = new ClientCredential(clientId, appKey);
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's database
AuthenticationContext authenticationContext = new AuthenticationContext(aadInstance + tenantID, new ADALTokenCache(signedInUserID));
AuthenticationResult authenticationResult = await authenticationContext.AcquireTokenSilentAsync(graphResourceID, clientcred, new UserIdentifier(userObjectID, UserIdentifierType.UniqueId));
return authenticationResult.AccessToken;
}
Я тоже попробовал это и получаю ошибку
Insufficient privileges to complete the operation.
Мое приложение имеет следующие разрешения
- Войдите и прочитайте профиль пользователя
- Читать данные каталога
Код для получения фото пользователя
var servicePoint = new Uri("https://graph.windows.net");
var serviceRoot = new Uri(servicePoint, "<your tenant>"); //e.g. xxx.onmicrosoft.com
const string clientId = "<clientId>";
const string secretKey = "<secretKey>";// ClientID and SecretKey are defined when you register application with Azure AD
var authContext = new AuthenticationContext("https://login.windows.net/<tenant>/oauth2/token");
var credential = new ClientCredential(clientId, secretKey);
ActiveDirectoryClient directoryClient = new ActiveDirectoryClient(serviceRoot, async () =>
{
var result = await authContext.AcquireTokenAsync("https://graph.windows.net/", credential);
return result.AccessToken;
});
var user = await directoryClient.Users.Where(x => x.UserPrincipalName == "<username>").ExecuteSingleAsync();
DataServiceStreamResponse photo = await user.ThumbnailPhoto.DownloadAsync();
using (MemoryStream s = new MemoryStream())
{
photo.Stream.CopyTo(s);
var encodedImage = Convert.ToBase64String(s.ToArray());
}
2 ответа
Недостаточные права могут означать, что вам нужно добавить некоторые дополнительные разрешения.
Попробуйте предоставить: User.Read разрешений. Подробности смотрите в документах: https://msdn.microsoft.com/en-us/library/azure/ad/graph/howto/azure-ad-graph-api-permission-scopes
Кроме того, попробуйте следовать следующей теме SO о том, как предоставлять разрешения: Graph API - Недостаточно прав для завершения операции.
AFAIK, разрешение " Чтение данных каталога" позволит вашему приложению читать все данные в каталоге организации, такие как пользователи, группы, приложения и т. Д. Я предположил, что это может использовать jwt.io для декодирования вашего access_token
и проверить scp
и убедитесь, что область действия Directory.Read.All (чтение данных каталога) и User.Read (включение входа и чтение профиля пользователя) существуют следующим образом:
Примечание. Разрешение " Чтение данных каталога" является разрешением делегирования и должно быть разрешено администратором. Если вы являетесь администратором AAD, вы можете предоставить разрешение, нажав кнопку " Предоставить разрешения", показанную на следующем снимке экрана:
Получив разрешение, вы можете подождать некоторое время, проверить свое приложение и убедиться, что область Directory.Read.All была добавлена в ваш декодированный файл. access_token
,
ОБНОВИТЬ:
Исходя из вашего кода, вы используете поток учетных данных клиента для получения токена, на данный момент вам необходимо установить РАЗРЕШЕНИЯ НА ПРИЛОЖЕНИЕ для API Windows Azure Active Directory следующим образом:
Подождите немного и расшифруйте access_token
и проверьте предоставленные разрешения по roles
следующее:
UPDATE2:
Поскольку вы сказали, что вы не являетесь администратором в каталоге Microsoft, я проверил это на своем собственном AAD, я мог бы предоставить разрешения, и это могло бы работать на моей стороне. Более того, я заметил, что вы используете поток кода и получаете делегированные разрешения для успешного получения базовой информации пользователя. Вы используете поток учетных данных клиента для получения базовой информации пользователя, но у вас нет разрешения на предоставление разрешений. Я предположил, что вы могли бы использовать ADALTokenCache
и использовать GetTokenForApplication
для получения access_token
, а затем получить пользовательское фото.