Aracılığıyla paylaş


Erişim belirteçlerinde bir grup fazla kullanım talebi görüntülendiğinde oturum açmış kullanıcı grubu listesini alma

Talebi uygulamanız için bir erişim belirtecinde yapılandırdığınızda groups , Microsoft Entra Id'nin erişim belirtecinde döndürülebilecek en fazla grup sayısı vardır. Sınır aşıldığında Azure, şu anda oturum açmış olan kullanıcının tam grup listesini almak için kullanılabilecek bir URL olan bir grup fazla kullanım talebi sağlar. Bu URL, Microsoft Graph uç noktasını kullanır. Talep hakkında groups daha fazla bilgi için bkz. Microsoft kimlik platformu erişim belirteçleri.

JSON web belirteçleri (JWT) için Azure, belirteçte bulunabilecek grup sayısını 200 ile sınırlar. Talebin yapılandırılmış olduğu groups bir kaynak için erişim belirteci istediğinizde, 200'den fazla grubun üyesiyseniz gerçek grupları almak yerine bir grup fazla kullanım talebi alırsınız.

Bu makalede, örnek bir proje kullanarak bir grup fazla kullanım talebinden gerçek kullanıcı grubu listesinin nasıl alındığı tanıtıcıdır.

Uygulamanız için grup talebi yapılandırma

İsteğe groups bağlı talepleri kullanarak uygulamanız için talebi yapılandırabilirsiniz. Daha fazla bilgi için bkz . Kimlik belirteçlerinde, erişim belirteçlerinde ve SAML belirteçlerinde isteğe bağlı talepleri yapılandırma ve yönetme.

Uygulama birinci taraf bir uygulamaysa (Microsoft uygulaması), talebi yapılandıramazsınız groups . Bunu yalnızca kendi uygulama kaydınızla yapılandırabilirsiniz. Bir istemci uygulaması için talebi yapılandırmak groups istiyorsanız, bir kimlik belirtecinde yapılandırmanız gerekir.

Örnek projeyi indirme

Örnek proje MSAL.Net_GroupOveragesClaim indirin. Grup listesinin bir grup fazla kullanım talebinden nasıl alınıp alınamaya ilişkin olduğunu gösterir.

Örnek projeyi çalıştırmadan önce

  • Örnek proje için bir uygulama kaydı yapılandırın.

    Örnek proje hem genel istemci akışını hem de gizli istemci akışını gerçekleştirir, bu nedenle bir web yeniden yönlendirmesi (genel istemci akışı için) ve bir istemci gizli dizisi (gizli istemci akışı için) yapılandırmanız gerekir. Gizli istemcinin users uç noktaya gitmesi ve ilk oturum açma belirtecinden alınabilen kullanıcı kimliğine göre grupları araması gerektiğinden, gizli istemci sürümü için Microsoft Graph uygulama izni gerekir Group.Read.All. Genel istemci, bir kullanıcı bağlamı me olduğundan uç noktaya gider.

  • appsettings.json dosyasını uygun değerlerle güncelleştirerek örnek projeyi kiracınızla çalışacak şekilde yapılandırın:

    {
    "Azure": {
        "ClientId": "{client_id}",
        "TenantId": "{tenant_id}",
        "CallbackPath": "http://localhost",
        "ClientSecret": "{client_secret}",
        "AppScopes": [ "https://database.windows.net/.default" ],
        "GraphScopes": [ "User.Read" ]
    }
    }
    

    appsettings.json dosyasındaki ayarların açıklamaları şunlardır:

    • AppScopes

      Talebin groups yapılandırıldığı bir kapsamınız olmalıdır.

      Bu genellikle kiracınızdaki bir API'dir. Ancak bu durumda, user_impersonation izniyle Azure SQL Veritabanı eklemek bu senaryo için işe yarar. Eklediğiniz kapsam bu API için çalışır. Bunun nedeni, talebin groups söz konusu API'de yapılandırılmış olmasıdır.

      Azure SQL Veritabanı API'sini gösteren ekran görüntüsü.

    • GraphScopes

      Group.Read.All (grup görünen adını almak için gereklidir) ve User.Read.All (istemci kimlik bilgileri akışını kullanarak grup listesini almak için gereklidir) uygulama izinlerini ekleyin. Bu izinler için yönetici onayı sağlamanız gerekir. User.Read temsilci izni zaten orada olmalıdır. Eklenmiyorsa ekleyin.

      Eklenen uygulama izinlerini gösteren ekran görüntüsü.

    • Bu örnek projenin uygulama kaydı yapılandırıldıktan sonra, appsettings.json dosyasına istemci kimliğini (uygulama kimliği), istemci gizli dizisini ve kiracı kimliğini ekleyin.

  • Test grupları oluşturmak için (gerekirse) Create_TestGroup.ps1.txt dosyasında PowerShell betiklerini çalıştırın.

    Örnek projede Create_TestGroup.ps1.txt adlı bir metin dosyası vardır. PowerShell betiklerini bu dosyada çalıştırmak için .txt uzantısını kaldırın. Çalıştırmadan önce, test gruplarına eklemek için kullanıcının nesne kimliğine ihtiyacınız vardır. Grup oluşturabilen ve gruplara kullanıcı ekleyebilen bir dizin rolünde olmanız gerekir. Örnek proje, , TEST_0002vb. biçiminde TEST_0001255 grup oluşturur. Her grup için sağladığınız nesne kimliği eklenir. Betiğin sonunda Azure'da oturum açar, test gruplarını oluşturmak için komutunu çalıştırır ve ardından oturumu kapatabilirsiniz.

    Not

    53. satıra açıklama ekleyen örnek bir temizleme yöntemi vardır:

    Connect-AzureAD
    Create-TestGroups -deleteIfExists $false
    #Delete-TestGroups
    Disconnect-AzureAD
    

Grup fazla kullanım talebi kullanarak tam kullanıcı grupları listesini alma

  1. Örnek uygulamayı çalıştırın.

  2. Uygulamada oturum açın.

    Örnek uygulama bir .NET konsol uygulaması olduğundan kimlik doğrulaması tarayıcıda gerçekleşir.

  3. Oturum açtıktan sonra tarayıcıyı kapatın; konsol uygulamasına geri dönersiniz.

  4. Erişim belirteci konsol penceresinde sunulduktan sonra, erişim belirtecini panoya kopyalayın ve kodlanmış belirteci görüntülemek için içine yapıştırın https://jwt.ms . Bu yalnızca bir kullanıcı belirtecidir.

    Kullanıcı çok fazla grubun üyesiyse, konsol penceresinde özgün grup fazla kullanım talebi ve bu belirteç için yeni grup fazla kullanım talebi görüntülenir. Yeni grup fazla kullanım talebi Graph .NET SDK isteği yerine .NET HTTP istemci isteğinde kullanılır.

    Kullanıcı gruplarının tam listesini almak için kullanılan yöntemlerin ekran görüntüsü.

  5. Microsoft Graph için almak istediğiniz erişim belirteci türünü seçin. Şu anda oturum açmış olan kullanıcı için kullanıcı belirteci (yenileme belirteci akışı) veya istemci kimlik bilgileri verme akışını kullanarak bir uygulama belirteci kullanarak erişim belirteci alabilirsiniz.

  6. Kullanıcı gruplarının .NET HTTP Request tam listesini almak için veya Graph .NET SDK öğesini seçin.

    Kullanıcı gruplarının tam listesini almak için kullanılan yöntemlerin ekran görüntüsü.

    Gruplar konsol penceresinde görünür:

    Kullanıcı gruplarının tam listesinin ekran görüntüsü.

Kod hakkında

Get_GroupsOverageClaimURL yöntemi

Örnek proje, kullanıcıların kimliğini doğrulamak ve erişim belirteçleri almak için MSAL.NET (Microsoft.Identity.Client) kullanır. System.Net.Http HTTP istemcisi için, Microsoft.Graph SDK ise grafik istemcisi için kullanılır. JSON dosyasını System.Text.Json ayrıştırmak için kullanılır. Belirteçten System.IdentityModel.Tokens.Jwt talepleri almak için kullanılır. Sağlayıcı JwtSecurityToken , belirteçteki grup fazla kullanım talebi almak için kullanılır.

Belirteç talepleri ve claim_sourcesiçeriyorsaclaim_names, belirteç içinde bir grup fazla kullanım talebi olduğunu gösterir. Bu durumda, grup listesinin URL'sini oluşturmak ve konsol penceresinde özgün değeri çıkarmak için kullanıcı kimliğini (oid) ve iki talebi kullanın. İki talep değerinden biri yoksa, try/catch blok hatayı işler ve bir string.empty değer döndürür. Bu, belirteçte grup fazla kullanım talebi olmadığını gösterir.

/// <summary>
		/// Looks for a group overage claim in an access token and returns the value if found.
		/// </summary>
		/// <param name="accessToken"></param>
		/// <returns></returns>
		private static string Get_GroupsOverageClaimURL(string accessToken)
        {
			JwtSecurityToken token = new JwtSecurityTokenHandler().ReadJwtToken(accessToken);
			string claim = string.Empty;
			string sources = string.Empty;
			string originalUrl = string.Empty;
			string newUrl = string.Empty;

            try
            {
				// use the user id in the new graph URL since the old overage link is for Azure AD Graph which is being deprecated.
				userId = token.Claims.First(c => c.Type == "oid").Value;

				// getting the claim name to properly parse from the claim sources but the next 3 lines of code are not needed,
				// just for demonstration purposes only so you can see the original value that was used in the token.
				claim = token.Claims.First(c => c.Type == "_claim_names").Value;
				sources = token.Claims.First(c => c.Type == "_claim_sources").Value;
				originalUrl = sources.Split("{\"" + claim.Split("{\"groups\":\"")[1].Replace("}","").Replace("\"","") + "\":{\"endpoint\":\"")[1].Replace("}","").Replace("\"", "");
				
				// make sure the endpoint is specific for your tenant -- .gov for example for gov tenants, etc.
				newUrl = $"https://graph.microsoft.com/v1.0/users/{userId}/memberOf?$orderby=displayName&$count=true";

				Console.WriteLine($"Original Overage URL: {originalUrl}");
				//Console.WriteLine($"New URL: {newUrl}");


			} catch {
				// no need to do anything because the claim does not exist
			} 

			return newUrl;
        }

Program.cs dosyası

Bu dosyada, kullanıcı oturum açma ve erişim belirteçleri alma için bir genel istemci uygulaması yapılandırması ve uygulama oturum açma ve erişim belirteçleri alma (istemci kimlik bilgileri verme akışı) için gizli bir istemci uygulaması vardır. ManualTokenProvider , Graph hizmet istemcisinin Graph'ın hizmete erişmesini sağlamak yerine hizmete erişim belirteci geçirmesi için kullanılır.

Ayrıca çalışma zamanında bu ayarları depolamak için bir appsettings.json dosyası ve bir sınıf (AzureConfig.cs) vardır. Genel statik özellik AzureSettings , ASP.NET Core uygulamalarına benzer bir yapılandırma oluşturucu kullanarak yapılandırma dosyasından ayarları alır. Bu özellik bir konsol uygulamasına yerel olmadığından eklenmelidir.

static AzureConfig _config = null;
		public static AzureConfig AzureSettings
		{
			get
			{
				// Only load this when the app starts.
				// To reload, you will have to set the variable _config to null again before calling this property.
				if (_config == null)
				{
					_config = new AzureConfig();
					IConfiguration builder = new ConfigurationBuilder()
						.SetBasePath(System.IO.Directory.GetCurrentDirectory())
						.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
						.Build();

					ConfigurationBinder.Bind(builder.GetSection("Azure"), _config);
				}

				return _config;
			}
		}

Kimlik doğrulama sağlayıcısı

Authentication Graph hizmeti istemcisinin sağlayıcısı için örnek proje, MSAL kullanarak erişim belirteçlerini zaten almış olan istemci için erişim belirtecini ayarlamak üzere özel bir el ile belirteç sağlayıcısı kullanır.

using Microsoft.Graph;

using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;

namespace MSAL.Net_GroupOveragesClaim.Authentication
{
    class ManualTokenProvider : IAuthenticationProvider
    {
        string _accessToken;

        public ManualTokenProvider ( string accessToken)
        {
            _accessToken = accessToken;
        }

        async Task IAuthenticationProvider.AuthenticateRequestAsync(HttpRequestMessage request)
        {
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _accessToken);
            request.Headers.Add("ConsistencyLevel", "eventual");
        }
    }
}

Get_Groups_HTTP_Method

Bu yöntem, grupların Graph_Request_viaHTTP listesini almak için yöntemini çağırır ve ardından bu listeyi konsol penceresinde görüntüler.

/// <summary>
		/// Entry point to make the request to Microsoft graph using the .Net HTTP Client
		/// </summary>
		/// <param name="graphToken"></param>
		/// <returns></returns>
		private static async Task Get_Groups_HTTP_Method(string graphToken, string url)
        {
			List<Group> groupList = new List<Group>();
						
			groupList = await Graph_Request_viaHTTP(graphToken, url);
			foreach (Group g in groupList)
			{
				Console.WriteLine($"Group Id: {g.Id} : Display Name: {g.DisplayName}");
			}
		}
/// <summary>
		/// Calls Microsoft Graph via a HTTP request.  Handles paging in the request
		/// </summary>
		/// <param name="user_access_token"></param>
		/// <returns>List of Microsoft Graph Groups</returns>
		private static async Task<List<Group>> Graph_Request_viaHTTP(string user_access_token, string url)
        {
			string json = string.Empty;
			//string url = "https://graph.microsoft.com/v1.0/me/memberOf?$orderby=displayName&$count=true";
			List<Group> groups = new List<Group>();

			// todo: check for the count parameter in the request and add if missing

			/*
			 * refer to this documentation for usage of the http client in .net
			 * https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-5.0
			 * 
			 */

			// add the bearer token to the authorization header for this request
			_httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue( "Bearer", user_access_token);
			
			// adding the consistencylevel header value if there is a $count parameter in the request as this is needed to get a count
			// this only needs to be done one time so only add it if it does not exist already.  It is case sensitive as well.
			// if this value is not added to the header, the results will not sort properly -- if that even matters for your scenario
			if(url.Contains("&$count", StringComparison.OrdinalIgnoreCase))
            {
                if (!_httpClient.DefaultRequestHeaders.Contains("ConsistencyLevel"))
                {
					_httpClient.DefaultRequestHeaders.Add("ConsistencyLevel", "eventual");
                }
            }
			
			// while loop to handle paging
			while(url != string.Empty)
            {
				HttpResponseMessage response = await _httpClient.GetAsync(new Uri(url));
				url = string.Empty; // clear now -- repopulate if there is a nextlink value.

				if (response.IsSuccessStatusCode)
				{
					json = await response.Content.ReadAsStringAsync();

					// Console.WriteLine(json);

					using (JsonDocument document = JsonDocument.Parse(json))
					{
						JsonElement root = document.RootElement;
						// check for the nextLink property to see if there is paging that is occuring for our while loop
						if (root.TryGetProperty("@odata.nextLink", out JsonElement nextPage))
                        {
							url = nextPage.GetString();
                        }
						JsonElement valueElement = root.GetProperty("value"); // the values

						// loop through each value in the value array
						foreach (JsonElement value in valueElement.EnumerateArray())
						{
							if (value.TryGetProperty("@odata.type", out JsonElement objtype))
							{
								// only getting groups -- roles will show up in this graph query as well.
								// If you want those too, then remove this if filter check
								if (objtype.GetString() == "#microsoft.graph.group")
								{
									Group g = new Group();

									// specifically get each property you want here and populate it in our new group object
									if (value.TryGetProperty("id", out JsonElement id)) { g.Id = id.GetString(); }
									if (value.TryGetProperty("displayName", out JsonElement displayName)) { g.DisplayName = displayName.GetString(); }

									groups.Add(g);
								}
							}
						}
					}
				} else
                {
					Console.WriteLine($"Error making graph request:\n{response.ToString()}");
                }
			} // end while loop
	
			return groups;
        }

Get_Groups_GraphSDK_Method

Benzer şekilde, Graph SDK'sının bir giriş yöntemi vardır: Get_Groups_GraphSDK_Method. Bu yöntem, grupların listesini almak için öğesini çağırır Get_GroupList_GraphSDK ve konsol penceresinde görüntüler.

/// <summary>
		/// Entry point to make the request to Microsoft Graph using the Graph SDK and outputs the list to the console.
		/// </summary>
		/// <param name="graphToken"></param>
		/// <returns></returns>
		private static async Task Get_Groups_GraphSDK_Method(string graphToken, bool me_endpoint)
        {
			List<Group> groupList = new List<Group>();

			groupList = await Get_GroupList_GraphSDK(graphToken, me_endpoint);
			foreach (Group g in groupList)
			{
				Console.WriteLine($"Group Id: {g.Id} : Display Name: {g.DisplayName}");
			}
		}

Get_GroupList_GraphSDK yöntemi

Bu yöntem, grup listesini almak için uç noktanın mı yoksa uç noktanın users mı kullanılacağını me belirler. Microsoft Graph erişim belirtecini almak için istemci kimlik bilgileri verme akışını kullanıyorsanız uç noktayı kullanın me . Aksi takdirde (örneğin, erişim belirteci için temsilcili bir akış kullanılır), uç noktayı kullanın users . Kullanılan yöntemden bağımsız olarak, varsayılan olarak sayfa başına yalnızca 100 kayıt döndürülür. Disk belleği değeri üzerinden @odata.nextLink belirlenir. Bu özellik için bir değer varsa, sonraki veri sayfası için tam URL çağrılır. Sayfalama hakkında daha fazla bilgi için bkz . Uygulamanızda Microsoft Graph verilerini sayfalama.

/// <summary>
		/// Calls the Me.MemberOf endpoint in Microsoft Graph and handles paging
		/// </summary>
		/// <param name="graphToken"></param>
		/// <returns>List of Microsoft Graph Groups</returns>
		private static async Task<List<Group>> Get_GroupList_GraphSDK(string graphToken, bool use_me_endpoint)
        {

			GraphServiceClient client;

			Authentication.ManualTokenProvider authProvider = new Authentication.ManualTokenProvider(graphToken);

			client = new GraphServiceClient(authProvider);
			IUserMemberOfCollectionWithReferencesPage membershipPage = null;

			HeaderOption option = new HeaderOption("ConsistencyLevel","eventual");

			if (use_me_endpoint)
            {
                if (!client.Me.MemberOf.Request().Headers.Contains(option))
                {
					client.Me.MemberOf.Request().Headers.Add(option);
                }

				membershipPage = await client.Me.MemberOf
					.Request()
					.OrderBy("displayName&$count=true") // todo: find the right way to add the generic query string value for count
					.GetAsync();
            } else
            {
                if (!client.Users[userId].MemberOf.Request().Headers.Contains(option))
                {
					client.Users[userId].MemberOf.Request().Headers.Add(option);
                }

				membershipPage = await client.Users[userId].MemberOf
					.Request()
					.OrderBy("displayName&$count=true")
					.GetAsync();
            }

			List<Group> allItems = new List<Group>();			
			
			if(membershipPage != null)
            {
				foreach(DirectoryObject o in membershipPage)
                {
					if(o is Group)
                    {
						allItems.Add((Group)o);
                    }
                }

				while (membershipPage.AdditionalData.ContainsKey("@odata.nextLink") && membershipPage.AdditionalData["@odata.nextLink"].ToString() != string.Empty)
                {
					membershipPage = await membershipPage.NextPageRequest.GetAsync();
					foreach (DirectoryObject o in membershipPage)
					{
						if (o is Group)
						{
							allItems.Add(o as Group);
						}
					}
				}

            }

             return allItems;

		}

Yardım için bize ulaşın

Sorularınız veya yardıma ihtiyacınız varsa bir destek isteği oluşturun veya Azure topluluk desteği isteyin. Ürün geri bildirimini Azure geri bildirim topluluğuna da gönderebilirsiniz.