IdentityServer4 Yazı Serisi #16 – Merkezi Üyelik Sistemi – Özel Identity Resource Ekleme

Merhaba,

IdentityServer4 Yazı Serisinin onbirinci makalesi olan Merkezi Üyelik Sistemi Temelleri başlıklı içeriğimizin 5. adımında Identity Resource üzerine odaklanmıştık ve öntanımlı olan ‘OpenId’ ve ‘Profile’ bilgilerini ekleyerek kullanıcı id/subject id değeriyle birlikte kullanıcı profil bilgilerini tanımlamıştık. Bu içeriğimizde ise bu öntanımlı identity resource’lerin dışında custom(özel) identity resource tanımlamayı ele alacak ve bunu client tarafından talep etmeyi inceleyeceğiz.

IdentityServer4 uygulamasına custom identity resource ekleyebilmek için aşağıdaki adımların sırasıyla uygulanması gerekmektedir.

  • Adım 1
    ‘AuthServer’ uygulamasındaki ‘Config.cs’ dosyasında identity resource’lerin tanımlandığı ‘GetIdentityResources’ metoduna aşağıdaki gibi custom değer(ler) oluşturulmalıdır.

            public static IEnumerable<IdentityResource> GetIdentityResources()
            {
                return new List<IdentityResource>
                {
                    new IdentityResources.OpenId(),
                    new IdentityResources.Profile(),
                    new IdentityResource {
                        Name = "PositionAndAuthority",
                        DisplayName = "Position And Authority",
                        Description = "Kullanıcı pozisyonu ve yetkisi.",
                        UserClaims = { "position", "authority" }
                    }
                };
            }
    

    Burada görüldüğü üzere ‘PositionAndAuthority’ isminde bir identity resource oluşturulmuştur ve içerisinde ‘position’ ve ‘authority’ claim’leri mevcuttur.

  • Adım 2
    Yukarıda oluşturulan identity resource claim’lerini kullanıcılar içinde claim olarak tanımlamamız gerekmektedir. Bunun için yine ‘Config.cs’ dosyasındaki ‘GetTestUsers’ metodundaki ilgili kullanıcılara aşağıdaki gibi eklemede bulunmak gerekmektedir.

            public static IEnumerable<TestUser> GetTestUsers()
            {
                return new List<TestUser> {
                    new TestUser {
                        .
                        .
                        .
                        Claims = {
                            new Claim("name","test user1"),
                            new Claim("given_name","test user1 given"),
                            new Claim("website","https://wwww.testuser1.com"),
                            new Claim("gender","1"),
                            new Claim("position" , "Test Kullanıcısı 1"),
                            new Claim("authority", "Test 1")
                        }
                    },
                    new TestUser {
                        .
                        .
                        .
                        Claims = {
                            new Claim("name","test user2"),
                            new Claim("website","https://wwww.testuser2.com"),
                            new Claim("gender","0"),
                            new Claim("position" , "Test Kullanıcısı 2"),
                            new Claim("authority", "Test 2")
                        }
                    }
                };
            }
    

    Görüldüğü üzere identity resource’da oluşturulan ‘position’ ve ‘authority’ claim’lerine karşılık değerler verilmiştir. Tabi burada kafa karıştırabilecek bir durum vardır. O da önceki makalelerde kullanıcılara tanımladığımız ‘website’, ‘gender’ vs. gibi claim bilgileridir. Doğrusu bu bilgileri önceden tanımlandığı için kaldırmaya gerek duymadım. İlgili claim’lere dair 1. adımda olduğu gibi identity resource’ler oluşturup uygulamada client’ın talep edebileceği hale getirebilirsiniz.

  • Adım 3
    İlgili claim’leri kullanıcılar içinde tanımladıktan sonra client’ta bu identity resource’ün ‘AllowedScopes’ property’si ile talep edilmesi gerekmektedir.

            public static IEnumerable<Client> GetClients()
            {
                return new List<Client>
                {
                    new Client
                            {
                                ClientId = "GarantiBankasi",
                                .
                                .
                                .
                                AllowedScopes = { "Garanti.Write", "Garanti.Read" }
                            },
                    new Client
                            {
                                ClientId = "HalkBankasi",
                                .
                                .
                                .
                                AllowedScopes = { "HalkBank.Write", "HalkBank.Read" }
                            },
                    new Client
                            {
                                ClientId = "OnlineBankamatik",
                                .
                                .
                                .
                                AllowedScopes = {
                                    IdentityServerConstants.StandardScopes.OpenId,
                                    IdentityServerConstants.StandardScopes.Profile,
                                    IdentityServerConstants.StandardScopes.OfflineAccess,
                                    "Garanti.Write",
                                    "Garanti.Read",
                                    "PositionAndAuthority"
                                                },
                                .
                                .
                                .
                            }
                };
            }
    

    33. satıra göz atarsanız eğer ilgili identity resource client tarafından scope olarak talep edilmektedir.

  • Adım 4
    Ayriyetten ilgili identity resource değerlerinin client uygulamasının ‘Startup.cs’ dosyasından da scope olarak talep edilmesi gerekmektedir. Bunun için;

        public class Startup
        {
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddAuthentication(_ =>
                {
                    _.DefaultScheme = "OnlineBankamatikCookie";
                    _.DefaultChallengeScheme = "oidc";
                })
                .AddCookie("OnlineBankamatikCookie")
                .AddOpenIdConnect("oidc", _ =>
                {
                    .
                    .
                    .
                    _.Scope.Add("offline_access");
                    _.Scope.Add("Garanti.Write");
                    _.Scope.Add("Garanti.Read");
                    _.Scope.Add("PositionAndAuthority");
                });
                services.AddControllersWithViews();
            }
            .
            .
            .
        }
    

    19. satırda olduğu gibi ‘Scope.Add’ komutuyla talebin eklenmesi yeterlidir.

  • Adım 5
    Bu adıma kadar yapılan konfigürasyon ile client’ın kullanıcıya dair ‘PositionAndAuthority’ name değerine sahip identity resource’u talep etmesi neticesinde ilgili claim değerlerini elde edebileceği bildirilmiştir. Lakin üretilecek JWT’de bu değerlerin hangi claim’ler ile eşleşeceği bildirilmemiştir. Hoca! Zaten ‘Profile’ ve ‘OpenId’ identity resource’lerinde bildirmedik, özel oluşturduğumuzu niye bildirelim! şeklinde sorunuzu duyar gibiyim… Evet, Profile ve OpenId öntanımlı identity resource olduklarından dolayı manuel müdahaleye gerek kalmaksızın direkt olarak JWT’de bir claim ile eşleştirilmektedir. Lakin custom geliştirilen identity resource’ların JWT’de hangi claim ile taşınacağı manuel belirtilmelidir. Bunun için yine client’ın ‘Startup.cs’deki ‘AddOpenIdConnect’ servisinde ‘Microsoft.AspNetCore.Authentication‘ namespace’i altındaki ‘MapUniqueJsonKey’ metoduyla aşağıdaki konfigürasyonlar gerçekleştirilmelidir.

                .
                .
                .AddOpenIdConnect("oidc", _ =>
                {
                    .
                    .
                    .
                    _.ClaimActions.MapUniqueJsonKey("position", "position");
                    _.ClaimActions.MapUniqueJsonKey("authority", "authority");
                });
    

    Burada ‘MapUniqueJsonKey’ metodunun birinci parametresi claim adını, ikinci parametre ise oluşturulacak JWT’de ki karşılığını belirlemektedir. Dolayısıyla ‘position’ claim’i ‘position’ json key’i ile eşleştirilmekte ve böylece oluşturulacak JWT’de ‘position’ değeri ile taşınabileceği bildirilmektedir. Benzer mantık ‘authority’ claim’i içinde geçerlidir.

Evet, işte bu kadar 🙂
Şimdi sıra sisteme yeni eklenen identity resource’e karşılık gelen kullanıcılardaki claim’lerin, client tarafından yapılan talep neticesinde elde edilip edilmediğini test etmeye gelmiştir.

Test Edelim

IdentityServer4 Yazı Serisi #16 - Merkezi Üyelik Sistemi - Özel Identity Resource Ekleme
Görüldüğü üzere kullanıcı giriş yaptıktan sonra bir önceki makalemizde konfigüre ettiğimiz onay sayfası bizleri karşılamakta ve tasarladığımız ‘PositionAndAuthority’ identity resource’unu getirmektedir.

Ayrıca elde edilen access token’ı jwt.io adresinde decode ederek incelersek eğer;
IdentityServer4 Yazı Serisi #16 - Merkezi Üyelik Sistemi - Özel Identity Resource Ekleme
ilgili identity resource’un ‘scope’ kısmına eklendiğini gözlemleyebilmekteyiz.

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

Not : Örnek uygulamayı indirebilmek için buraya tıklayınız.

Bunlar da hoşunuza gidebilir...

Bir cevap yazın

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

*