App.yaml ile GAE'de ortam değişkenlerini güvenli bir şekilde depolama


101

app.yamlGAE'de dağıtım için API anahtarlarını ve diğer hassas bilgileri ortam değişkenleri olarak saklamam gerekiyor . Bununla ilgili sorun, app.yamlGitHub'a gönderirsem, bu bilginin herkese açık hale gelmesidir (iyi değil). Projeye uygun olmadığı için bilgiyi bir veri deposunda saklamak istemiyorum. Bunun yerine, .gitignoreuygulamanın her dağıtımında listelenen bir dosyadaki değerleri değiştirmek istiyorum .

İşte benim app.yaml dosyam:

application: myapp
version: 3 
runtime: python27
api_version: 1
threadsafe: true

libraries:
- name: webapp2
  version: latest
- name: jinja2
  version: latest

handlers:
- url: /static
  static_dir: static

- url: /.*
  script: main.application  
  login: required
  secure: always
# auth_fail_action: unauthorized

env_variables:
  CLIENT_ID: ${CLIENT_ID}
  CLIENT_SECRET: ${CLIENT_SECRET}
  ORG: ${ORG}
  ACCESS_TOKEN: ${ACCESS_TOKEN}
  SESSION_SECRET: ${SESSION_SECRET}

Herhangi bir fikir?


77
GAE'nin geliştirici konsolu aracılığıyla örnek ortam değişkenlerini ayarlama seçeneğini eklemesini isterdim (aşina olduğum diğer tüm PaaS gibi).
İspanya Treni

5
Datastore'u kullanabilirsiniz. Lütfen şu yanıta bakın: stackoverflow.com/a/35254560/1027846
Mustafa İlhan

Mustilica'nın yukarıdaki veri deposunu kullanma hakkındaki yorumunu genişletiyoruz. Bunu yapmak için projelerimde kullandığım kod için aşağıdaki cevabıma bakın: stackoverflow.com/a/35261091#35261091 . Aslında, geliştirici konsolundan ortam değişkenlerini düzenlemenize olanak tanır ve yer tutucu değerleri otomatik olarak oluşturulur.
Martin Omander

Teşekkürler mustilica ve Martin. Aslında bir süredir veri deposu yaklaşımını kullanıyoruz ve bunun bu soruna en iyi çözüm olduğuna katılıyorum. Bir CI / CD kurulumuyla yapmak, json dosya yaklaşımından daha kolaydır, IMO.
İspanya Treni

1
2019 ve GAE bu sorunu hala çözmedi : /
Josh Noe

Yanıtlar:


55

Hassas verilerse, kaynak kontrolünde kontrol edileceği için kaynak kodunda saklamamalısınız. Yanlış kişiler (kuruluşunuzun içinde veya dışında) onu orada bulabilir. Ayrıca geliştirme ortamınız muhtemelen üretim ortamınızdan farklı yapılandırma değerleri kullanır. Bu değerler kodda saklanırsa, geliştirme ve üretimde farklı kodlar çalıştırmanız gerekecektir, bu da karmaşık ve kötü bir uygulamadır.

Projelerimde, bu sınıfı kullanarak veri deposuna yapılandırma verilerini koyuyorum:

from google.appengine.ext import ndb

class Settings(ndb.Model):
  name = ndb.StringProperty()
  value = ndb.StringProperty()

  @staticmethod
  def get(name):
    NOT_SET_VALUE = "NOT SET"
    retval = Settings.query(Settings.name == name).get()
    if not retval:
      retval = Settings()
      retval.name = name
      retval.value = NOT_SET_VALUE
      retval.put()
    if retval.value == NOT_SET_VALUE:
      raise Exception(('Setting %s not found in the database. A placeholder ' +
        'record has been created. Go to the Developers Console for your app ' +
        'in App Engine, look up the Settings record with name=%s and enter ' +
        'its value in that record\'s value field.') % (name, name))
    return retval.value

Uygulamanız bir değer elde etmek için bunu yapacaktır:

API_KEY = Settings.get('API_KEY')

Veri deposunda bu anahtar için bir değer varsa, onu alırsınız. Yoksa, bir yer tutucu kaydı oluşturulacak ve bir istisna atılacaktır. İstisna, Developers Console'a gitmenizi ve yer tutucu kaydını güncellemenizi hatırlatacaktır.

Bunun, yapılandırma değerlerini ayarlamanın tahminini ortadan kaldırdığını görüyorum. Hangi yapılandırma değerlerini ayarlayacağınızdan emin değilseniz, kodu çalıştırın ve size söyleyecektir!

Yukarıdaki kod, memcache ve başlık altındaki veri deposunu kullanan ndb kitaplığını kullanır, bu nedenle hızlıdır.


Güncelleme:

jelder , Datastore değerlerinin App Engine konsolunda nasıl bulunacağını ve ayarlanacağını sordu. İşte nasıl:

  1. Https://console.cloud.google.com/datastore/ adresine gidin

  2. Zaten seçilmemişse, sayfanın üst kısmından projenizi seçin.

  3. Gelen Tür açılır kutusundan seçin Ayarlar .

  4. Yukarıdaki kodu çalıştırdıysanız, anahtarlarınız görünecektir. Hepsi AYARLANMAYAN değere sahip olacaktır . Her birine tıklayın ve değerini ayarlayın.

Bu yardımcı olur umarım!

Ayarlar sınıfı tarafından oluşturulan ayarlarınız

Düzenlemek için tıkla

Gerçek değeri girin ve kaydedin


3
Verilen tüm cevaplar arasında bu, Heroku'nun işleri nasıl ele aldığına en yakın gibi görünüyor. GAE'de oldukça yeni olduğum için, Developers Console'da yer tutucu kaydını nerede bulacağımı tam olarak anlamıyorum. Açıklayabilir misiniz veya bonus puanlar için ekran görüntüleri yayınlayabilir misiniz?
jelder

3
dam ~… gcloud'a tüm saygımla, bu özel ihtiyaç için başka bir hizmet kullanmak zorunda olmak oldukça kötü görünüyor. Bunun yanı sıra, google firebase işlevlerindeki env değişkenler için "% 100 -herokuish" yaklaşımı sağlar, ancak gcloud işlevleri için kullanmayın (en azından belgelenmemiş ... eğer yanılmıyorsam)
Ben

2
İşte size benzersizlik ve çevre değişkeni geri dönüşü
İspanya Treni

3
@Ben Firebase dışı işlevler, ortam değişkenlerini desteklemektedir (şimdi, en azından).
NReilingh

3
@obl - Bir App Engine uygulamasının kimliği otomatik olarak kendi veri deposunda doğrulanır, kimlik doğrulama ayrıntıları gerekmez. Oldukça temiz :-)
Martin Omander

59

Bu çözüm basittir ancak tüm farklı ekiplere uygun olmayabilir.

İlk olarak, ortam değişkenlerini env_variables.yaml içine koyun , ör.

env_variables:
  SECRET: 'my_secret'

Sonra bunlar aşağıdakileri env_variables.yamldeapp.yaml

includes:
  - env_variables.yaml

Son olarak, gizli değişkenlerin bilgi havuzunda bulunmaması için env_variables.yamlto 'u ekleyin .gitignore.

Bu durumda, env_variables.yamldağıtım yöneticileri arasında paylaşılması gerekir.


2
Bazıları için açık olmayabilecek şeyleri eklemek için, ortam değişkenleriniz daha sonra bulunur process.env.MY_SECRET_KEYve yerel geliştirme ortamınızda bu ortam değişkenlerine ihtiyacınız varsa düğüm dotenvpaketini kullanabilirsiniz
Dave Kiss

4
Nasıl olur env_variables.yamltüm örneklere olsun bulmacanın eksik parçası.
Christopher Oezbek

1
Ayrıca: Bu yerel olarak nasıl kullanılır?
Christopher Oezbek

@ChristopherOezbek 1. Nasıl konuşlandırılır? gcloud app deployGoogle Cloud'a dağıtım yapmak için normalde yaptığınız gibi kullanın . 2. Gizli ortam değişkenleri yerel olarak nasıl ayarlanır? Birçok yolu var. Yalnızca exportkomut isteminde kullanabilir veya @DaveKiss'in önerdiği gibi herhangi bir aracı kullanabilirsiniz.
Shih-Wen Su

1
Bu en basit çözümdür. Sırlara uygulamanızdan erişebilirsiniz os.environ.get('SECRET').
Quinn Comendant

20

Yaklaşımım, istemci sırlarını yalnızca App Engine uygulamasının içinde depolamaktır . İstemci sırları ne kaynak denetiminde ne de herhangi bir yerel bilgisayarda bulunur. Bu, herhangi bir App Engine ortak çalışanının istemci sırları hakkında endişelenmek zorunda kalmadan kod değişikliklerini dağıtabilmesi avantajına sahiptir .

İstemci sırlarını doğrudan Datastore'da depoluyorum ve sırlara erişimde iyileştirilmiş gecikme için Memcache kullanıyorum. Datastore varlıklarının yalnızca bir kez oluşturulması gerekir ve gelecekteki dağıtımlarda da kalacaktır. Tabii ki App Engine konsolu bu varlıkları herhangi bir zamanda güncellemek için kullanılabilir.

Tek seferlik varlık oluşturmanın iki seçeneği vardır:

  • Varlıkları oluşturmak için App Engine Remote API etkileşimli kabuğunu kullanın.
  • Varlıkları kukla değerlerle başlatacak bir Yalnızca Yönetici işleyicisi oluşturun. Bu yönetici işleyicisini manuel olarak çağırın, ardından varlıkları üretim istemci gizli dizileriyle güncellemek için App Engine konsolunu kullanın.

7
Hiç karmaşık değil. Teşekkürler uygulama motoru.
courtimas

19

Bu, gönderi yayınladığınızda mevcut değildi, ancak burada tökezleyen herkes için, Google artık Gizli Yönetici adlı bir hizmet sunuyor .

Sırlarınızı google bulut platformunda güvenli bir yerde saklamak için basit bir REST hizmetidir (elbette SDK'lar onu sarar). Bu, Veri Deposu'ndan daha iyi bir yaklaşımdır, depolanan sırları görmek için fazladan adımlar gerektirir ve daha ayrıntılı bir izin modeline sahip olursanız, gerekirse projenizin farklı yönleri için ayrı ayrı sırları farklı şekilde güvence altına alabilirsiniz.

Sürüm oluşturma özelliği sunar, böylece parola değişikliklerini göreceli olarak kolaylıkla halledebilirsiniz ve ayrıca, gerekirse çalışma zamanında gizli dizileri keşfetmenize ve oluşturmanıza olanak tanıyan güçlü bir sorgu ve yönetim katmanı.

Python SDK

Örnek kullanım:

from google.cloud import secretmanager_v1beta1 as secretmanager

secret_id = 'my_secret_key'
project_id = 'my_project'
version = 1    # use the management tools to determine version at runtime

client = secretmanager.SecretManagerServiceClient()

secret_path = client.secret_verion_path(project_id, secret_id, version)
response = client.access_secret_version(secret_path)
password_string = response.payload.data.decode('UTF-8')

# use password_string -- set up database connection, call third party service, whatever

3
Bu yeni doğru cevap olmalı. Gizli Yönetici hala Beta sürümündedir, ancak ortam değişkenleriyle çalışırken ileriye giden yol budur.
Kral Leon

@KingLeon, bu, bir grup os.getenv('ENV_VAR')s için yeniden düzenleme yapmak anlamına gelir mi?
Alejandro

Yukarıdakine benzer kodu bir fonksiyona koyarım, sonra benzer bir şey kullanırım SECRET_KEY = env('SECRET_KEY', default=access_secret_version(GOOGLE_CLOUD_PROJECT_ID, 'SECRET_KEY', 1)). Varsayılanı kullanmak için ayarlamaaccess_secret_version
Kral Leon

Ayrıca django-environ kullanıyorum. github.com/joke2k/django-environ
Kral Leon

Aptalca bir soru sormam gerekiyor, ama dediğiniz şey secret_id = 'my_secret_key'sürüm kontrolünüzde yok mu?
dierre

16

Bunu yapmanın en iyi yolu, anahtarları bir client_secrets.json dosyasında saklamak ve .gitignore dosyanızda listeleyerek bunu git'e yüklenmekten hariç tutmaktır. Farklı ortamlar için farklı anahtarlarınız varsa, uygulama kimliğinin ne olduğunu belirlemek ve uygun şekilde yüklemek için app_identity api'yi kullanabilirsiniz.

Burada oldukça kapsamlı bir örnek var -> https://developers.google.com/api-client-library/python/guide/aaa_client_secrets .

İşte bazı örnek kod:

# declare your app ids as globals ...
APPID_LIVE = 'awesomeapp'
APPID_DEV = 'awesomeapp-dev'
APPID_PILOT = 'awesomeapp-pilot'

# create a dictionary mapping the app_ids to the filepaths ...
client_secrets_map = {APPID_LIVE:'client_secrets_live.json',
                      APPID_DEV:'client_secrets_dev.json',
                      APPID_PILOT:'client_secrets_pilot.json'}

# get the filename based on the current app_id ...
client_secrets_filename = client_secrets_map.get(
    app_identity.get_application_id(),
    APPID_DEV # fall back to dev
    )

# use the filename to construct the flow ...
flow = flow_from_clientsecrets(filename=client_secrets_filename,
                               scope=scope,
                               redirect_uri=redirect_uri)

# or, you could load up the json file manually if you need more control ...
f = open(client_secrets_filename, 'r')
client_secrets = json.loads(f.read())
f.close()

2
Kesinlikle doğru yönde, ancak bu app.yaml, uygulamanın dağıtımındaki değerleri değiştirme sorununu ele almıyor . Orada herhangi bir fikir var mı?
Ben

1
Dolayısıyla, her ortam için farklı bir client_secrets dosyasına sahip olun. Örneğin, client_secrets_live.json, client_secrets_dev.json, client_secrets_pilot.json vb. Ardından, hangi sunucuda olduğunuzu belirlemek için python mantığını kullanın ve uygun json dosyasını yükleyin. App_identity.get_application_id () yöntemi, hangi sunucuda olduğunuzu otomatik olarak algılamak için yararlı olabilir. Bu demek istediğin türden bir şey mi?
Gwyn Howell

@BenGrunfeld cevabımı gör. Benim çözümüm tam olarak bunu yapıyor. Bu cevabın soruyu nasıl çözdüğünü anlamıyorum. Hedefin gizli yapılandırmayı git dışında tutmak ve dağıtımın bir parçası olarak git kullanmak olduğunu varsayıyorum. Burada, bu dosyanın hala bir yerde olması ve dağıtım sürecine gönderilmesi gerekiyor. Bu, uygulamanızda yaptığınız bir şey olabilir, ancak sadece vurguladığım teknikleri kullanırsınız, belki de app.yaml ile karşılaştırmak istiyorsanız başka bir dosyada saklayabilirsiniz. Soruyu anlarsam, bu, kütüphane üreticisinin gerçek müşteri sırrı veya üretimiyle açık kaynaklı bir uygulamayı göndermeye benzer bir şey. anahtar.
therewillbesnacks

1
Kafamı karıştırmam biraz zaman aldı, ama bence bu doğru yaklaşım. Uygulama ayarlarını ( app.yaml) gizli anahtarlar ve gizli bilgilerle karıştırmıyorsunuz ve gerçekten hoşuma giden şey, görevi gerçekleştirmek için Google iş akışını kullanıyor olmanız. Teşekkürler @GwynHowell. =)
Ben

1
Benzer bir yaklaşım, bu JSON dosyasını uygulamanın varsayılan GCS paketindeki ( cloud.google.com/appengine/docs/standard/python/… ) bilinen bir konuma yerleştirmek olacaktır .
İspanya Treni

15

Bu çözüm, kullanımdan kaldırılmış appcfg.py'ye dayanmaktadır

Uygulamanızı GAE'ye dağıtırken ortam değişkenlerini ayarlamak için appcfg.py'nin -E komut satırı seçeneğini kullanabilirsiniz (appcfg.py güncelleme)

$ appcfg.py
...
-E NAME:VALUE, --env_variable=NAME:VALUE
                    Set an environment variable, potentially overriding an
                    env_variable value from app.yaml file (flag may be
                    repeated to set multiple variables).
...

Bu ortam değişkenlerini dağıtımdan sonra bir yerde sorgulayabilir misiniz? (Umarım değildir.)
Ztyx

gcloudYardımcı programı kullanarak ortam değişkenlerini bu şekilde geçirmenin bir yolu var mı ?
Trevor

6

Cevapların çoğu güncel değildir. Google bulut veri deposunu kullanmak şu anda aslında biraz farklı. https://cloud.google.com/python/getting-started/using-cloud-datastore

İşte bir örnek:

from google.cloud import datastore
client = datastore.Client()
datastore_entity = client.get(client.key('settings', 'TWITTER_APP_KEY'))
connection_string_prod = datastore_entity.get('value')

Bu, varlık adının 'TWITTER_APP_KEY', türün 'ayarlar' ve 'değer', TWITTER_APP_KEY varlığının bir özelliği olduğunu varsayar.


4

Değişkenleri google kms ile şifrelemeli ve kaynak kodunuza yerleştirmelisiniz. ( https://cloud.google.com/kms/ )

echo -n the-twitter-app-key | gcloud kms encrypt \
> --project my-project \
> --location us-central1 \
> --keyring THEKEYRING \
> --key THECRYPTOKEY \
> --plaintext-file - \
> --ciphertext-file - \
> | base64

şifrelenmiş (şifrelenmiş ve base64 kodlanmış) değeri ortam değişkeninize (yaml dosyasında) koyun.

Şifresini çözmeye başlaman için bazı piton kodu.

kms_client = kms_v1.KeyManagementServiceClient()
name = kms_client.crypto_key_path_path("project", "global", "THEKEYRING", "THECRYPTOKEY")

twitter_app_key = kms_client.decrypt(name, base64.b64decode(os.environ.get("TWITTER_APP_KEY"))).plaintext

3

Görünüşe göre birkaç yaklaşım yapabilirsin. Benzer bir sorunumuz var ve aşağıdakileri yapıyoruz (kullanım durumunuza göre uyarlanmış):

  • Dinamik app.yaml değerlerini depolayan bir dosya oluşturun ve bunu, yapı ortamınızdaki güvenli bir sunucuya yerleştirin. Eğer gerçekten paranoyak iseniz, değerleri asimetrik olarak şifreleyebilirsiniz. Hatta sürüm kontrolü / dinamik çekmeye ihtiyacınız varsa bunu özel bir depoda tutabilir veya kopyalamak / uygun yerden çekmek için bir kabuk komut dosyası kullanın.
  • Dağıtım betiği sırasında git'ten çekin
  • Git çekme işleminden sonra, app.yaml dosyasını yaml kitaplığı kullanarak saf python okuyup yazarak değiştirin.

Bunu yapmanın en kolay yolu Hudson , Bamboo veya Jenkins gibi sürekli bir entegrasyon sunucusu kullanmaktır . Yukarıda bahsettiğim tüm öğeleri yapan bir eklenti, komut dosyası adımı veya iş akışı eklemeniz yeterlidir. Örneğin Bamboo'da yapılandırılan ortam değişkenlerini aktarabilirsiniz.

Özetle, yalnızca erişebildiğiniz bir ortamda oluşturma süreciniz sırasında değerleri itin. Halihazırda yapılarınızı otomatikleştirmiyorsanız, yapmalısınız.

Diğer bir seçenek seçeneği, söylediğiniz şey, veritabanına koyun. Bunu yapmama nedeniniz işlerin çok yavaş olmasıysa, değerleri 2. katman önbelleği olarak memcache'ye aktarın ve değerleri örneklere birinci katman önbellek olarak sabitleyin. Değerler değişebiliyorsa ve örnekleri yeniden başlatmadan güncellemeniz gerekiyorsa, yaptığınız bir şey değerleri değiştirdiğinde ne zaman değiştiklerini veya bir şekilde tetiklediklerini kontrol edebileceğiniz bir karma tutun. Bu olmalı.


1
FWIW, bu yaklaşım 12 Faktör Uygulaması kılavuzundaki ( 12factor.net ) yapılandırma faktörünü en yakından takip eder
İspanya

3

@Jason F'nin Google Datastore kullanımına dayalı cevabı yakın, ancak kod, kütüphane belgelerindeki örnek kullanıma göre biraz eski . İşte benim için işe yarayan pasaj:

from google.cloud import datastore

client = datastore.Client('<your project id>')
key = client.key('<kind e.g settings>', '<entity name>') # note: entity name not property
# get by key for this entity
result = client.get(key)
print(result) # prints all the properties ( a dict). index a specific value like result['MY_SECRET_KEY'])

Bu Medium gönderisinden kısmen ilham alındı


2

Sadece javascript / nodejs'de bu sorunu nasıl çözdüğümü not etmek istedim. Yerel geliştirme için, ortam değişkenlerini bir .env dosyasından process.env'e yükleyen 'dotenv' npm paketini kullandım. GAE'yi kullanmaya başladığımda, ortam değişkenlerinin bir 'app.yaml' dosyasında ayarlanması gerektiğini öğrendim. Yerel geliştirme için 'dotenv' ve GAE için 'app.yaml' kullanmak istemedim (ve iki dosya arasında ortam değişkenlerimi çoğaltmak), bu yüzden app.yaml ortam değişkenlerini işleme yükleyen küçük bir komut dosyası yazdım .env, yerel kalkınma için. Umarım bu birine yardımcı olur:

yaml_env.js:

(function () {
    const yaml = require('js-yaml');
    const fs = require('fs');
    const isObject = require('lodash.isobject')

    var doc = yaml.safeLoad(
        fs.readFileSync('app.yaml', 'utf8'), 
        { json: true }
    );

    // The .env file will take precedence over the settings the app.yaml file
    // which allows me to override stuff in app.yaml (the database connection string (DATABASE_URL), for example)
    // This is optional of course. If you don't use dotenv then remove this line:
    require('dotenv/config');

    if(isObject(doc) && isObject(doc.env_variables)) {
        Object.keys(doc.env_variables).forEach(function (key) {
            // Dont set environment with the yaml file value if it's already set
            process.env[key] = process.env[key] || doc.env_variables[key]
        })
    }
})()

Şimdi bu dosyayı mümkün olduğunca erken kodunuza ekleyin ve bitirdiniz:

require('../yaml_env')

Hala durum bu mu? Çünkü .envgizli değişkenler içeren bir dosya kullanıyorum . Bunları app.yamldosyamda çoğaltmıyorum ve dağıtılan kodum hala çalışıyor. .envYine de buluttaki dosyaya ne olacağı konusunda endişeliyim . Şifreleniyor mu? Dağıtıldıktan sonra gcloud .envdosya değişkenlerine kimsenin erişmediğinden nasıl emin olabilirim ?
Gus

GAE, app.yaml dosyasında tanımlanan tüm değişkenleri düğüm ortamına otomatik olarak eklediğinden buna hiç gerek yoktur. Temelde bu, dotenv'nin .env paketinde tanımlanan değişkenlerle yaptığı ile aynıdır. Ancak, app.yaml ile env vars ile bir
VCS'ye

1

Martin'in cevabını genişletmek

from google.appengine.ext import ndb

class Settings(ndb.Model):
    """
    Get sensitive data setting from DataStore.

    key:String -> value:String
    key:String -> Exception

    Thanks to: Martin Omander @ Stackoverflow
    https://stackoverflow.com/a/35261091/1463812
    """
    name = ndb.StringProperty()
    value = ndb.StringProperty()

    @staticmethod
    def get(name):
        retval = Settings.query(Settings.name == name).get()
        if not retval:
            raise Exception(('Setting %s not found in the database. A placeholder ' +
                             'record has been created. Go to the Developers Console for your app ' +
                             'in App Engine, look up the Settings record with name=%s and enter ' +
                             'its value in that record\'s value field.') % (name, name))
        return retval.value

    @staticmethod
    def set(name, value):
        exists = Settings.query(Settings.name == name).get()
        if not exists:
            s = Settings(name=name, value=value)
            s.put()
        else:
            exists.value = value
            exists.put()

        return True

1

Cloud Datastore'da appengine ortam değişkenlerini kaydetmenize olanak tanıyan gae_env adında bir pypi paketi vardır . Kaputun altında, Memcache de kullanıyor, bu yüzden

Kullanım:

import gae_env

API_KEY = gae_env.get('API_KEY')

Veri deposunda bu anahtar için bir değer varsa, döndürülür. Yoksa, bir yer tutucu kaydı __NOT_SET__oluşturulacak ve bir ValueNotSetErroratılacaktır. İstisna, Developers Console'a gitmenizi ve yer tutucu kaydını güncellemenizi hatırlatacaktır .


Martin'in cevabına benzer şekilde, Datastore'daki anahtarın değerini şu şekilde güncelleyebilirsiniz:

  1. Geliştiriciler konsolunda Datastore Bölümüne gidin

  2. Zaten seçilmemişse, sayfanın üst kısmından projenizi seçin.

  3. Gelen Tür açılır kutusundan seçin GaeEnvSettings.

  4. İstisnanın ortaya çıktığı anahtarların değeri olacaktır __NOT_SET__ .

Ayarlar sınıfı tarafından oluşturulan ayarlarınız

Düzenlemek için tıkla

Gerçek değeri girin ve kaydedin


Kullanım / yapılandırma hakkında daha fazla bilgi için paketin GitHub sayfasına gidin

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.