Sıfır güven zihniyetine doğru ilerledikçe, geleneksel RBAC sistemi gibi kaba taneli güvenlik önlemlerinin sınırlamaları netleşiyor. Sıfır güvene geçişin çoğu zaman tartışılmayan önemli bir parçası, kaba taneli güvenlikten ince taneli güvenliğe geçiştir.
Ayrıntılı yetkilendirme, erişimi kullanıcı rolleri, eylemler ve hatta zaman veya konum gibi bağlamlara dayandırarak bu sorunu giderir ve bu tür ayrıntılı erişim kontrolü, modern uygulamalar için hayati öneme sahiptir. Bu makalede bunun nasıl yapılacağı anlatılmaktadır.
ZITADEL'in roller, meta veriler ve eylemler gibi özellikleri sayesinde kullanıcılar, sıfır güven ortamına uygun son derece ayrıntılı erişim kontrolü elde edebilir. Ayrıca ZITADEL dış yetkilendirme hizmetleriyle de çalışabilmektedir.
ZITADEL bir
Birincil hedefleri arasında kimlik doğrulama, yetkilendirme, oturum açma ve tek oturum açma (SSO) için anahtar teslim özellikler sağlamanın yanı sıra kullanıcı arayüzleri aracılığıyla özelleştirmeye izin vermek yer alır.
Tüm değişiklikleri izlemek için kapsamlı bir denetim iziyle birlikte gelir, geliştiricilerin işlevleri özel kodlarla (eylemler) genişletmesine olanak tanır, OIDC, OAuth, SAML ve LDAP gibi yaygın olarak tanınan standartları destekler, kullanım kolaylığını ve ölçeklenebilirliği vurgular ve kapsamlı API'ler sunar. çok yönlü entegrasyon.
ZITADEL, izinlerin rollere bağlandığı ve kullanıcılara bu rollerin tahsis edildiği kullanıcı izinlerini yönetmek için RBAC'ı kullanır. Bu, kurumsal rollerine göre kullanıcı erişim yönetimini basitleştirir. Ek bir özellik, rollerin diğer kuruluşlara devredilmesine olanak tanıyarak izinlerin harici varlıklarla paylaşılmasını kolaylaştırır.
Bu, özellikle birbirine bağlı veya hiyerarşik organizasyonlar için değerlidir.
Bu yetenekler sağlam erişim kontrolü sunarken, karmaşık yetkilendirme ihtiyaçları için yeterli olmayabilir, dolayısıyla ZITADEL'de ayrıntılı yetkilendirmeyi keşfetmenin önemi budur.
ZITADEL, dinamiğini sunarak geleneksel RBAC'ı geliştiriyor
ZITADEL'in eylemleriyle, belirli kullanıcı özelliklerini analiz etmek ve gerektiğinde erişimi engellemek için kimlik doğrulama sonrası komut dosyaları oluşturulabilir.
Eylemler ayrıca ABAC sistemini güçlendirmek için özel talepler oluşturabilir; konum, zaman veya tanımlanabilir herhangi bir faktöre dayalı olarak erişimi kısıtlayan gelişmiş yetkilendirme modellerine olanak tanır.
ZITADEL, yöneticilerin veya izin verilen geliştiricilerin kullanıcılara ve kuruluşlara özel meta veriler eklemesine olanak tanıyarak ayrıntılı erişim kontrolü olanaklarını artırır.
CRM veya İK araçları gibi harici sistemlerden ekstra veri toplayarak toplu talepleri destekler. ZITADEL ayrıca sevkıyat siparişleri veya IoT cihazları gibi benzersiz kaynakları da yönetebilir ve Kullanıcı-Alt, Roller, Talepler, IP ve daha fazlası gibi özelliklere dayalı olarak erişimi belirleyebilir.
ZITADEL ile gelen kapsamlı özelliklere rağmen, daha özelleştirilmiş veya ayrıntılı bir yaklaşımın gerekli olduğu durumlar olabilir.
Şu anda, ZITADEL'de ayrıntılı yetkilendirme uygulamanın en etkili yolu, daha küçük projeler için özel uygulama mantığını kullanmak veya daha büyük ölçekli projeler için, garanti.dev , cerbos.dev vb. gibi mevcut bir üçüncü taraf araçtan yararlanmaktır.
Bu araçlar ZITADEL ile entegre olarak incelikli, ayrıntılı yetkilendirme kapasitenizi daha da artırabilir.
Diyelim ki bir medya şirketinde arka uç API ile konuşan varsayımsal bir Haber Odası Uygulaması var. Gazeteciler bunu yazmak için kullanır, editörler ise bu makaleleri düzenleyip yayınlar. Bu örnekte Python Flask'ta yazılan bu API'nin belirli uç noktaları vardır ve bu uç noktalara erişim, kullanıcının rolüne ve ne kadar deneyimli olduğuna bağlıdır. Uç noktalar:
write_article
: Yalnızca gazetecilerin yazması için.
edit_article
: Sadece editörlerin makaleleri düzenlemesi için.
review_articles
: Kıdemli gazetecilerin ve orta ve kıdemli editörlerin makaleleri incelemesi için.
publish_article
: Orta ve kıdemli gazetecilerin ve kıdemli editörlerin yayınlaması için. Dahili olarak API, kimin istekte bulunduğunu kontrol etmek için ZITADEL tarafından yayınlanan bir JWT'yi kullanır. Kullanıcıların isteklerinin başlığında geçerli bir JWT göndermeleri gerekir. Bu JWT, kullanıcı oturum açtığında elde edildi.
JWT, kullanıcı hakkında, rolü ve deneyimi gibi bilgileri içerir. Özel taleplerde yer alan bu bilgi, bu kullanım senaryosunun anahtarıdır. Arka uç, bu bilgiye dayanarak kullanıcının istenen kaynağa erişip erişemeyeceğine karar verir.
journalist
veya editor
. Kurulumumuzda kimin hangi erişime sahip olacağını belirlediği için bu çok önemlidir. Deneyimi/Kıdemliliği Yönetme: Rollerin yanı sıra, bir kullanıcının deneyimi (örneğimizde junior
, intermediate
ve senior
gibi) izlenir. Bir kullanıcının deneyimi değişirse ZITADEL bunu meta veri olarak günceller. Bir kullanıcı ZITADEL'e katıldığında herhangi bir deneyim seviyesi belirtilmemişse, sistem bunun sadece 'junior' olduğunu varsayar.
Endişelerin Ayrılması : Bu API'nin tasarımında iş mantığı ve erişim kontrol kurallarının temiz bir şekilde ayrılmasına özellikle dikkat edildi. Bu, uygulamanın sürdürülebilirliği ve ölçeklenebilirliği açısından çok önemlidir. İş mantığını ve erişim kurallarını ayrı tutarak daha temiz, modüler bir tasarım elde ediyoruz.
Bu, iş eylemlerini ve erişim kurallarını birbirini etkilemeden güncellememize olanak tanır. Bu, kodun sürdürülebilirliğini artırır ve uygulama ölçeklendikçe yönetimi kolaylaştırır.
Ayrıca bu tasarım, erişim kuralları ana iş mantığından soyutlandığı için sistemi daha güvenli hale getirir ve iş mantığını değiştirirken yanlışlıkla güvenlik açıklarının ortaya çıkması riskini azaltır.
Medya Evi organizasyonunu oluşturun, Projeler'e gidin ve Haber Odası adında yeni bir proje oluşturun.
Haber Odası projesinde yeni bir uygulama oluşturmak için Yeni düğmesine tıklayın.
Kuruluşunuzda aşağıda gösterildiği gibi Kullanıcılar sekmesine gidin ve Hizmet Kullanıcıları sekmesine gidin. Bu demoda hizmet kullanıcıları oluşturacağız. Bir hizmet kullanıcısı eklemek için Yeni düğmesine tıklayın.
Ardından, hizmet kullanıcısının ayrıntılarını ekleyin, Erişim Belirteci Türü için JWT'yi seçin ve Oluştur'a tıklayın.
Sağ üst köşedeki Eylemler düğmesini tıklayın. Açılır menüden İstemci Sırrı Oluştur'u seçin.
Müşteri Kimliğinizi ve Müşteri Sırrınızı kopyalayın. Kapat'ı tıklayın.
Artık müşteri kimlik bilgileriyle birlikte bir hizmet kullanıcınız var.
Yetkiler'e gidin. Yeni'yi tıklayın.
Yetkinin oluşturulması gereken kullanıcıyı ve projeyi seçin. Devam'ı tıklayın.
Burada bir rol seçebilirsiniz. Geçerli kullanıcı için gazeteci rolünü seçin. Kaydet'i tıklayın.
Hizmet kullanıcısı Lois Lane'in artık Haber Odası projesinde gazeteci rolüne sahip olduğunu görebilirsiniz.
Şimdi kullanıcı profiline kıdem düzeylerini belirtmek için meta veriler ekleyelim. Anahtar olarak 'experience_level'ı kullanın ve değeri için 'junior', 'intermediate' veya 'senior' arasından seçim yapın.
Genellikle bu meta verinin İK uygulaması tarafından yapılan bir API çağrısı aracılığıyla ayarlandığını varsayabilsek de, basitlik ve anlama kolaylığı için meta veriyi doğrudan konsolda ayarlayacağız.
Meta Veriler'e gidin. Düzenle'yi tıklayın.
Anahtar olarak deneyim_düzeyini ve değer olarak kıdemli değerini sağlayın. Kaydet simgesine tıklayın ve Kapat düğmesine tıklayın.
Kullanıcı artık hesabıyla ilişkili gerekli meta verilere sahiptir.
Ayrıca önceki adımları kullanarak demoyu test etmek için farklı rollere ve deneyim düzeylerine (meta verileri kullanarak) sahip birkaç hizmet kullanıcısı daha ekleyebilirsiniz.
1. Eylemler'e tıklayın. Yeni bir eylem oluşturmak için Yeni'ye tıklayın.
2. Eylem Oluştur bölümünde, eyleme işlev adıyla aynı adı verin, yani questRoleAndExperienceClaims. Komut dosyası alanına aşağıdaki kodu kopyalayın/yapıştırın ve ardından Ekle öğesine tıklayın.
function assignRoleAndExperienceClaims(ctx, api) { // Check if grants and metadata exist if (!ctx.v1.user.grants || !ctx.v1.claims['urn:zitadel:iam:user:metadata']) { return; } // Decode experience level from Base64 - metadata is Base64 encoded let experience_encoded = ctx.v1.claims['urn:zitadel:iam:user:metadata'].experience_level; let experience = ''; try { experience = decodeURIComponent(escape(String.fromCharCode.apply(null, experience_encoded.split('').map(function(c) { return '0x' + ('0' + c.charCodeAt(0).toString(16)).slice(-2); })))); } catch (e) { return; // If decoding fails, stop executing the function } // Check if the experience level exists if (!experience) { return; } // Iterate through the user's grants ctx.v1.user.grants.grants.forEach(grant => { // Iterate through the roles of each grant grant.roles.forEach(role => { // Check if the user is a journalist if (role === 'journalist') { // Set custom claims with the user's role and experience level api.v1.claims.setClaim('journalist:experience_level', experience); } // Check if the user is an editor else if (role === 'editor') { // Set custom claims with the user's role and experience level api.v1.claims.setClaim('editor:experience_level', experience); } }); }); }
Artık bir kullanıcı bir erişim belirteci istediğinde, kullanıcı rolleri ve meta veriler gerekli formata dönüştürülerek ve bunları belirtece özel bir talep olarak eklenerek eylem yürütülecektir. Bu özel talep daha sonra üçüncü taraf uygulamalar tarafından ayrıntılı kullanıcı erişimini yönetmek için kullanılabilir.
Projeyi GitHub'dan kopyalayın:
Projeyi bu GitHub deposundan kopyalamak için aşağıdaki komutu çalıştırın:
git clone https://github.com/zitadel/example-fine-grained-authorization.git
Proje Dizinine gidin:
Klonlamadan sonra proje dizinine gidin.
cd example-fine-grained-authorization
.
Python Ortamı Kurun:
Python 3 ve pip'in kurulu olduğundan emin olun. Bunu çalıştırarak kontrol edebilirsiniz
python3 --version
vepip3 --version
terminalinizde. Python veya pip yüklü değilse bunları yüklemeniz gerekecektir.
Daha sonra çalıştırarak bu proje için yeni bir sanal ortam oluşturun.
python3 -m venv env
.
Aşağıdakileri çalıştırarak ortamı etkinleştirin:
.\env\Scripts\activate
source env/bin/activate
Bu komutu çalıştırdıktan sonra terminaliniz artık env sanal ortamında çalıştığınızı belirtmelidir.
Bağımlılıkları yükleyin:
Proje dizinindeki terminalle (Requirements.txt dosyasını içeren), çalıştırın
pip3 install -r requirements.txt
gerekli bağımlılıkları yüklemek için.
Ortam Değişkenlerini Yapılandırın:
Proje belirli ortam değişkenlerini gerektirir. .env
dosyasını ZITADEL'den aldığımız değerlerle doldurun.
PROJECT_ID="<YOUR PROJECT ID>" ZITADEL_DOMAIN="<YOUR INSTANCE DOMAIN eg https://instance-as23uy.zitadel.cloud>" ZITADEL_TOKEN_URL="<YOUR TOKEN URL eg https://instance-as23uy.zitadel.cloud/oauth/v2/token" CLIENT_ID="<YOUR SERVICE USER'S CLIENT ID FROM THE GENERATED CLIENT CREDENTIALS eg sj_Alice>" CLIENT_SECRET="<YOUR SERVICE USER'S SECRET FROM THE GENERATED CLIENT CREDENTIALS"> ZITADEL_INTROSPECTION_URL="<YOUR INTROSPECTION URL eg https://instance-as23uy.zitadel.cloud/oauth/v2/introspect>" API_CLIENT_ID="<THE CLIENT ID OF YOUR API APPLICATION FOR BASIC AUTH eg 324545668690006737@api>" API_CLIENT_SECRET="<THE CLIENT SECRET OF YOUR API APPLICATION FOR BASIC AUTH>"
Uygulamayı çalıştırın:
Flask API ( app.py
içinde), ayrıntılı erişim kontrolü için JWT belirteçlerini ve özel talepleri kullanır. Kimliği doğrulanmış kullanıcının istenen uç noktaya erişip erişemeyeceğine karar vermek için bu bilgiyi kullanarak, her istekte journalist
ve editor
rolleri için özel talep deneyimi_düzeyini kontrol eder.
uygulama.py
from flask import Flask, jsonify from auth import token_required from access_control import authorize_access app = Flask(__name__) # Define the /write_article route. @app.route('/write_article', methods=['POST']) @token_required def write_article(): authorization = authorize_access('write_article') if authorization is not True: return authorization # Resource-specific code goes here... return jsonify({"message": "Article written successfully!"}), 200 # Define the /edit_article route. @app.route('/edit_article', methods=['PUT']) @token_required def edit_article(): authorization = authorize_access('edit_article') if authorization is not True: return authorization # Resource-specific code goes here... return jsonify({"message": "Article edited successfully!"}), 200 # Define the /review_article route. @app.route('/review_articles', methods=['GET']) @token_required def review_article(): authorization = authorize_access('review_article') if authorization is not True: return authorization # Resource-specific code goes here... return jsonify({"message": "Article review accessed successfully!"}), 200 # Define the /publish_article route. @app.route('/publish_article', methods=['POST']) @token_required def publish_article(): authorization = authorize_access('publish_article') if authorization is not True: return authorization # Resource-specific code goes here... return jsonify({"message": "Article published successfully!"}), 200 # Add more endpoints as needed... if __name__ == '__main__': app.run(debug=True)
auth.py
import os import jwt import requests from functools import wraps from flask import request, jsonify, g ZITADEL_INTROSPECTION_URL = os.getenv('ZITADEL_INTROSPECTION_URL') API_CLIENT_ID = os.getenv('API_CLIENT_ID') API_CLIENT_SECRET = os.getenv('API_CLIENT_SECRET') # This function checks the token introspection and populates the flask.g variable with the user's token def token_required(f): @wraps(f) def decorated(*args, **kwargs): token = request.headers.get('Authorization') if not token: abort(401) # Return status code 401 for Unauthorized if there's no token else: token = token.split(' ')[1] # The token is in the format "Bearer <token>", we want to extract the actual token # Call the introspection endpoint introspection_response = requests.post( ZITADEL_INTROSPECTION_URL, auth=(API_CLIENT_ID, API_CLIENT_SECRET), data={'token': token} ) if not introspection_response.json().get('active', False): return jsonify({"message": "Invalid token"}), 403 # Decode the token and print it for inspection decoded_token = jwt.decode(token, options={"verify_signature": False}) print(f"\n\n***** Decoded Token: {decoded_token} \n\n******") # Add the decoded token to Flask's global context g.token = decoded_token return f(*args, **kwargs) return decorated
Access_control.py (kural motorunu simüle eden örnek kod)
import base64 import jwt from flask import g, jsonify # The access_requirements dictionary represents your access control rules. access_requirements = { 'write_article': [{'role': 'journalist', 'experience_level': 'junior'}, {'role': 'journalist', 'experience_level': 'intermediate'}, {'role': 'journalist', 'experience_level': 'senior'}], 'edit_article': [{'role': 'editor', 'experience_level': 'junior'}, {'role': 'editor', 'experience_level': 'intermediate'}, {'role': 'editor', 'experience_level': 'senior'}], 'review_articles': [{'role': 'journalist', 'experience_level': 'senior'}, {'role': 'editor', 'experience_level': 'intermediate'}, {'role': 'editor', 'experience_level': 'senior'}], 'publish_article': [{'role': 'journalist', 'experience_level': 'intermediate'}, {'role': 'journalist', 'experience_level': 'senior'}, {'role': 'editor', 'experience_level': 'senior'}] # Add more endpoints as needed... } # This function checks if the user is authorized to access the given endpoint. def authorize_access(endpoint): # We assume that the token has already been decoded in auth.py decoded_token = g.token # Initialize role and experience_level variables role = None experience_level = None for claim, value in decoded_token.items(): if ':experience_level' in claim: role, _ = claim.split(':') experience_level = base64.b64decode(value).decode('utf-8') break # If there's no role in the token, return an error if not role: return jsonify({"message": "Missing role"}), 403 # If there's a role in the token but no experience level, default the experience level to 'junior' if role and not experience_level: experience_level = 'junior' # If there's no role or experience level in the token, return an error if not role or not experience_level: return jsonify({"message": "Missing role or experience level"}), 403 # Get the requirements for the requested endpoint endpoint_requirements = access_requirements.get(endpoint) # If the endpoint is not in the access control list, return an error if not endpoint_requirements: return jsonify({"message": "Endpoint not found in access control list"}), 403 # Check if the user's role and experience level meet the requirements for the requested endpoint for requirement in endpoint_requirements: required_role = requirement['role'] required_experience_level = requirement['experience_level'] # Experience level hierarchy experience_levels = ['junior', 'intermediate', 'senior'] if role == required_role and experience_levels.index(experience_level) >= experience_levels.index(required_experience_level): return True #return jsonify({"message": "Access denied"}), 403 return jsonify({"message": f"Access denied! You are a {experience_level} {role} and therefore cannot access {endpoint}"}), 403
Flask uygulamasını aşağıdakileri çalıştırarak çalıştırın:
python3 app.py
Her şey doğru ayarlanmışsa Flask uygulamanız artık çalışıyor olmalıdır.
Bu proje Python 3 ile geliştirilmiş ve test edilmiştir, dolayısıyla Python 3 yorumlayıcısı kullandığınızdan emin olun.
Depoyu klonladığınızdan ve daha önce açıklandığı gibi gerekli bağımlılıkları yüklediğinizden emin olun.
Erişim belirteci oluşturmak için client_credentials_token_generator.py
betiğini çalıştırın.
client_credentials_token_generator.py
import os import requests import base64 from dotenv import load_dotenv load_dotenv() ZITADEL_DOMAIN = os.getenv("ZITADEL_DOMAIN") CLIENT_ID = os.getenv("CLIENT_ID") CLIENT_SECRET = os.getenv("CLIENT_SECRET") ZITADEL_TOKEN_URL = os.getenv("ZITADEL_TOKEN_URL") PROJECT_ID = os.getenv("PROJECT_ID") # Encode the client ID and client secret in Base64 client_credentials = f"{CLIENT_ID}:{CLIENT_SECRET}".encode("utf-8") base64_client_credentials = base64.b64encode(client_credentials).decode("utf-8") # Request an OAuth token from ZITADEL headers = { "Content-Type": "application/x-www-form-urlencoded", "Authorization": f"Basic {base64_client_credentials}" } data = { "grant_type": "client_credentials", "scope": f"openid profile email urn:zitadel:iam:org:project:id:{PROJECT_ID}:aud urn:zitadel:iam:org:projects:roles urn:zitadel:iam:user:metadata" } response = requests.post(ZITADEL_TOKEN_URL, headers=headers, data=data) if response.status_code == 200: access_token = response.json()["access_token"] print(f"Response: {response.json()}") print(f"Access token: {access_token}") else: print(f"Error: {response.status_code} - {response.text}")
Terminalinizi açın ve proje dizinine gidin, ardından betiği python3 kullanarak çalıştırın:
python3 client_credentials_token_generator.py
Başarılı olursa, terminalinize bir erişim belirteci yazdırılacaktır. Bu, API'ye yönelik isteklerinizin kimliğini doğrulamak için kullanacağınız belirteçtir.
Flask API'sini daha önce başlatmadıysanız, proje dizininde başka bir terminal açıp şunu çalıştırarak API'yi çalıştırın:
python3 app.py
API sunucusu artık çalışıyor ve istekleri kabul etmeye hazır olmalıdır.
Artık API'ye istekte bulunmak için cURL'yi veya başka herhangi bir HTTP istemcisini (Postacı gibi) kullanabilirsiniz. curl komutlarındaki your_access_token
2. adımda elde ettiğiniz erişim jetonuyla değiştirmeyi unutmayın.
Senaryo 1: Yardımcı Editör Bir Makaleyi Düzenlemeye Çalışıyor (Başarılı)
editor
rolüne ve junior
sahip kullanıcı, edit_article
uç noktasını çağırmaya çalışır.
curl -H "Authorization: Bearer <your_access_token>" -X POST http://localhost:5000/edit_article
Beklenen Çıktı: {"message": "Article edited successfully"}
Senaryo 2: Yardımcı Editör Bir Makaleyi Yayınlamaya Çalışıyor (Başarısızlık)
editor
rolüne ve junior
sahip kullanıcı, publish_article
uç noktasını çağırmaya çalışır.
curl -H "Authorization: Bearer <your_access_token>" -X POST http://localhost:5000/publish_article
Beklenen çıktı: {"message": "Access denied! You are a junior editor and therefore cannot access publish_article"}
Senaryo 3: Kıdemli Gazeteci Makale Yazmaya Çalışıyor (Başarılı)
journalist
rolüne ve senior
deneyim düzeyine sahip kullanıcı, write_article
uç noktasını çağırmaya çalışır.
curl -H "Authorization: Bearer <your_access_token>" -X POST http://localhost:5000/write_article
Beklenen çıktı: {"message": "Article written successfully"}
Senaryo 4: Asistan Gazeteci Makaleleri İncelemeye Çalışıyor (Başarısızlık)
journalist
rolüne ve 'kıdemsiz' deneyim_düzeyine sahip kullanıcı, review_articles
uç noktasını çağırmaya çalışır.
curl -H "Authorization: Bearer <your_access_token>" -X POST http://localhost:5000/review_articles
Beklenen çıktı: {"message": "Access denied! You are a junior journalist and therefore cannot access review_articles"}
Senaryo 5: Kıdemli Editör Makaleleri İncelemeye Çalışıyor (Başarılı)
editor
rolüne ve senior
deneyim düzeyine sahip kullanıcı, review_articles
uç noktasına erişmeye çalışır.
curl -H "Authorization: Bearer <your_access_token>" -X POST http://localhost:5000/review_articles
Beklenen çıktı: {"message": "Article reviewed successfully"}
Senaryo 6: Orta Seviye Gazeteci Makale Yayınlamaya Çalışıyor (Başarılı)
journalist
rolüne ve intermediate
deneyime sahip kullanıcı, publish_article
uç noktasına erişmeye çalışır.
curl -H "Authorization: Bearer <your_access_token>" -X POST http://localhost:5000/publish_article
{"message": "Article published successfully"}
Bu makalede, ZITADEL kullanarak geleneksel RBAC'den daha ayrıntılı, ayrıntılı bir yetkilendirme yaklaşımına geçmenin önemini araştırdık.
ABAC için dinamik eylemler, üçüncü taraf araçlarla entegrasyon yeteneği gibi özelliklerini inceledik ve bu yeteneklerin gerçek dünya senaryosunda pratik olarak nasıl uygulanabileceğini gördük.
Siber güvenliğe yönelik talepler arttıkça ZITADEL gibi platformlar karmaşık yetkilendirme zorlukları için gerekli çözümleri sağlıyor.