Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

IdentityServer4 Yazı Serisi #19 – IProfileService Arayüzü İle Dinamik Claim Ekleme

Merhaba,

Makale serimizin bu ondokuzuncu içeriğine kadar bir hususun anlaşıldığı kanaatindeyim ki, o da, kullanıcılar hakkında kimlik bilgilerinin ciddi önem arz etmesidir. Kullanıcılarda claim olarak tutulmakta olan bu bilgileri bizler şu ana kadar ön tanımlı bir vaziyette ‘Config.cs’ dosyasından eklemekte ve yönetmekteydik. Halbuki kullanıcılara dair claim’lerin bu şekilde ön tanımlı olarak eklenmesi pekte tercih edilebilir bir yöntem değildir. Nihayetinde claim değerlerinin kodun içerisinde gömülü bir vaziyette olması bir metinsel bağımlılık yaratmaktadır. Ayrıca bu kullanıcı bilgilerini veritabanından yahut benzer bir kaynaktan edinmek istediğimizde işi runtime’da çözmemiz gerekecektir. IdentityServer4, kullanıcıya dair eklenecek olan claim bilgilerini runtime’da dinamik bir şekilde yükleyebilmemizi sağlamakta ve bunun için bir IProfileService arayüzünü sunmaktadır. Bu içeriğimizde ilgili arayüzün nasıl kullanıldığını ve bu arayüzden geliştirilen bir concrete nesnenin sisteme nasıl entegre edildiğini inceleyeceğiz.

İlk olarak IProfileService arayüzünü incelersek eğer
IdentityServer4 Yazı Serisi #19 – IProfileService Arayüzü İle Özelleştirilmiş Claim Ekleme
görüldüğü üzere ‘GetProfileDataAsync’ ve ‘IsActiveAsync’ metotlarının imzalarını barındırmaktadır.

Bu metotlardan ilki için UserInfo Endpoint‘inin programatik kısmını temsil ediyor diyebiliriz. Dinamik olarak claim oluşturma ve ekleme burada gerçekleştirilecektir. İkinci metotta ise genellikle claim eklenecek olan kullanıcının doğrulaması gerçekleştirilmektedir.

Şimdi aşağıdaki örnek kodu ele alırsak;

    public class CustomProfileService : IProfileService
    {
        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            //Kullanıcı veritabanından çekilir.
            //context.Subject.GetSubjectId(); -> Subject Id değerini getirir.

            var claims = new List<Claim>
            {
                new Claim(JwtRegisteredClaimNames.Email, "gncy@gencayyildiz.com"),
                new Claim(JwtRegisteredClaimNames.Website,"https://www.gencayyildiz.com"),
                new Claim("gobekadi", "Ali")
            };

            context.AddRequestedClaims(claims); //Userinfo Token
            context.IssuedClaims = claims; //JWT
        }

        public async Task IsActiveAsync(IsActiveContext context)
        {
            //Kullanıcı doğrulanır.
            context.IsActive = true;
        }
    }

görüldüğü üzere ‘GetProfileDataAsync’ metodu içerisinde ideal olan kullanıcının veritabanından çekilmesi ve ardından çekilen kullanıcının bilgilerinin claim değerlerine verilmesidir. Aksi taktirde bu örnekteki gibi farazi amaçlı verilen statik değerleri kullanmamanız gerekmektedir. Üretilen claim’leri ise ya context.AddRequestedClaims(claims) komutu eşliğinde Userinfo’ya ekleriz ya da context.IssuedClaims = claims komutu ile oluşturulacak JWT’ye dahil ederiz. Tabi aynı anda her ikisini de kullanabilirsiniz.

‘IsActiveAsync’ metodunda ise kullanıcının doğrulama sonucu context.IsActive property’sine bildirilmelidir.

Bir diğer dikkat edilmesi gereken husus ise, burada eklenen claim’lerin identity resource’lerinin tanımlanmış, client tarafından talep edilmiş ve erişilebilir olması gerekmektedir. Yani Özel Identity Resource Ekleme makelesinde yapılması gereken herşeyi bu içerikteki stratejiyi benimserkende uygulamamız gerekmektedir.

Misal olarak biz ‘gobekadi’ claim’inin arkaplandaki inşasını buraya alırsak;

  • 1. Adım
    Identity resource tanımlanmalı,

            public static IEnumerable<IdentityResource> GetIdentityResources()
            {
                return new List<IdentityResource>
                {
                    .
                    .
                    .
                    new IdentityResource{
                        Name = "GobekAdi",
                        DisplayName = "Gobek adı",
                        Description = "Göbek adı",
                        UserClaims = { "gobekadi" }
                    }
                };
            }
    
  • 2. Adım
    Client tarafından ilgili identity resource talep edilmeli,

            public static IEnumerable<Client> GetClients()
            {
                return new List<Client>
                {
                    .
                    .
                    .
                    new Client
                            {
                                .
                                .
                                .
                                AllowedScopes = {
                                    .
                                    .
                                    .
                                    "GobekAdi"
                                                },
                            }
                };
            }
    
  • 3. Adım
    İlgili client uygulamasının ‘Startup.cs’ dosyasından da talep edilmeli ve json eşleştirmesi gerçekleştirilmeli,

                .AddOpenIdConnect("oidc", _ =>
                {
                    .
                    .
                    .
                    _.Scope.Add("GobekAdi");
                    _.ClaimActions.MapUniqueJsonKey("gobekadi", "gobekadi");
                });
    

İşte bu kadar… Tüm yapılanma bu şekilde inşa edildikten sonra ‘IProfileService’ arayüzü ile geliştirilen sınıfımızı Auth Server’ın ‘Startup.cs’ dosyasında ‘AddProfileService’ servisi ile uygulamaya dahil ediyoruz.

            services.AddIdentityServer()
                .AddInMemoryApiResources(Config.GetApiResources())
                .AddInMemoryApiScopes(Config.GetApiScopes())
                .AddInMemoryClients(Config.GetClients())
                .AddTestUsers(Config.GetTestUsers().ToList())
                .AddInMemoryIdentityResources(Config.GetIdentityResources())
                .AddDeveloperSigningCredential()
                .AddProfileService<CustomProfileService>();

Velhasıl, ilgili servisin dahil edilmesinden sonra uygulamayı derleyip, çalıştırdığımızda oluşturulan cookie içerisinde belirtilen authentication property’leri aşağıdaki gibi gözlemleyebilmekteyiz.
IdentityServer4 Yazı Serisi #19 – IProfileService Arayüzü İle Özelleştirilmiş Claim Ekleme

Ayriyetten kimlik doğrulamadan sonra JWT’yi elde edip jwt.io adresinde incelersek eğer claim’lerin context.IssuedClaims = claims kodu sayesinde ilgili JWT’ye eklendiğini görebilmekteyiz.
IdentityServer4 Yazı Serisi #19 – IProfileService Arayüzü İle Özelleştirilmiş Claim Ekleme

Nihai olarak, IProfileService arayüzü sayesinde kullanıcıya dinamik olarak claim’ler ekleyebilmekte ve bu claim’lerin Userinfo bilgileri dışında üretilecek JWT’de saklanıp, saklanmayacağı kararını verebilmekteyiz.

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*