sql >> データベース >  >> RDS >> PostgreSQL

ユーザーIDをPostgreSQLトリガーに渡す

    オプションは次のとおりです。

    • 接続を開くと、CREATE TEMPORARY TABLE current_app_user(username text); INSERT INTO current_app_user(username) VALUES ('the_user'); 。次に、トリガーで、SELECT username FROM current_app_user おそらくサブクエリとして、現在のユーザー名を取得します。

    • postgresql.confmy_app.username = 'unknown';のようなカスタムGUCのエントリを作成します 。接続を作成するときはいつでも、SET my_app.username = 'the_user';を実行します。 。次に、トリガーで、current_setting('my_app.username')を使用します 値を取得する関数。事実上、セッション変数を提供するためにGUC機構を悪用しています。 カスタムGUCは9.2で変更されたため、サーバーのバージョンに適したドキュメントをお読みください

    • すべてのアプリケーションユーザーのデータベースロールを持つようにアプリケーションを調整します。 SET ROLE 仕事をする前にそのユーザーに。これにより、組み込みのcurrent_userを使用できるだけでなく SELECT current_user;への変数のような関数 、データベースのセキュリティを強化することもできます。 。この質問を参照してください。 SET ROLEを使用する代わりに、ユーザーとして直接ログインできます。 、しかしそれは接続プールを難しくする傾向があります。

    接続プールを使用している3つのケースすべてで、DISCARD ALL;に注意する必要があります。 プールへの接続を返すとき。 (そのように文書化されていませんが、DISCARD ALL RESET ROLEを実行します 。

    デモの一般的な設定:

    CREATE TABLE tg_demo(blah text);
    INSERT INTO tg_demo(blah) VALUES ('spam'),('eggs');
    
    -- Placeholder; will be replaced by demo functions
    CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
    SELECT 'unknown';
    $$ LANGUAGE sql;
    
    CREATE OR REPLACE FUNCTION tg_demo_trigger() RETURNS trigger AS $$
    BEGIN
        RAISE NOTICE 'Current user is: %',get_app_user();
        RETURN NULL;
    END;
    $$ LANGUAGE plpgsql;
    
    CREATE TRIGGER tg_demo_tg
    AFTER INSERT OR UPDATE OR DELETE ON tg_demo 
    FOR EACH ROW EXECUTE PROCEDURE tg_demo_trigger();
    

    GUCの使用:

    • CUSTOMIZED OPTIONS postgresql.confのセクション 、myapp.username = 'unknown_user'のような行を追加します 。 9.2より古いバージョンのPostgreSQLでは、custom_variable_classes = 'myapp'も設定する必要があります。 。
    • PostgreSQLを再起動します。これで、SHOW myapp.usernameができるようになります 値unknown_userを取得します 。

    これで、SET myapp.username = 'the_user';を使用できます。 接続を確立するとき、または代わりにSET LOCAL myapp.username = 'the_user'; BEGINの後 トランザクションをローカルにしたい場合は、トランザクションを作成します。これは、プールされた接続に便利です。

    get_app_user 関数の定義:

    CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
        SELECT current_setting('myapp.username');
    $$ LANGUAGE sql;
    

    SET LOCALを使用したデモ トランザクションの場合-ローカルの現在のユーザー名:

    regress=> BEGIN;
    BEGIN
    regress=> SET LOCAL myapp.username = 'test_user';
    SET
    regress=> INSERT INTO tg_demo(blah) VALUES ('42');
    NOTICE:  Current user is: test_user
    INSERT 0 1
    regress=> COMMIT;
    COMMIT
    regress=> SHOW myapp.username;
     myapp.username 
    ----------------
     unknown_user
    (1 row)
    

    SETを使用する場合 SET LOCALの代わりに 設定はコミット/ロールバック時に元に戻されないため、セッション全体で保持されます。それでもDISCARD ALLによってリセットされます :

    regress=> SET myapp.username = 'test';
    SET
    regress=> SHOW myapp.username;
     myapp.username 
    ----------------
     test
    (1 row)
    
    regress=> DISCARD ALL;
    DISCARD ALL
    regress=> SHOW myapp.username;
     myapp.username 
    ----------------
     unknown_user
    (1 row)
    

    また、SETは使用できないことに注意してください またはSET LOCAL サーバー側のバインドパラメータを使用します。バインドパラメータ(「プリペアドステートメント」)を使用する場合は、関数形式set_config(...)の使用を検討してください。 。システム管理機能を参照してください

    一時テーブルの使用

    このアプローチでは、すべてのセッションで必要な一時テーブルから値を読み取ろうとするトリガー(またはトリガーによって呼び出されるヘルパー関数が望ましい)を使用する必要があります。一時テーブルが見つからない場合は、デフォルト値が提供されます。これはやや遅い可能性があります 。注意深くテストしてください。

    get_app_user() 定義:

    CREATE OR REPLACE FUNCTION get_app_user() RETURNS text AS $$
    DECLARE
        cur_user text;
    BEGIN
        BEGIN
            cur_user := (SELECT username FROM current_app_user);
        EXCEPTION WHEN undefined_table THEN
            cur_user := 'unknown_user';
        END;
        RETURN cur_user;
    END;
    $$ LANGUAGE plpgsql VOLATILE;
    

    デモ:

    regress=> CREATE TEMPORARY TABLE current_app_user(username text);
    CREATE TABLE
    regress=> INSERT INTO current_app_user(username) VALUES ('testuser');
    INSERT 0 1
    regress=> INSERT INTO tg_demo(blah) VALUES ('42');
    NOTICE:  Current user is: testuser
    INSERT 0 1
    regress=> DISCARD ALL;
    DISCARD ALL
    regress=> INSERT INTO tg_demo(blah) VALUES ('42');
    NOTICE:  Current user is: unknown_user
    INSERT 0 1
    

    安全なセッション変数

    PostgreSQLに「セキュアセッション変数」を追加する提案もあります。これらはパッケージ変数に少し似ています。 PostgreSQL 12の時点では、この機能は含まれていませんが、これが必要な場合は、ハッカーリストに注意して発言してください。

    詳細:共有メモリ領域を備えた独自の拡張機能

    高度な使用法では、独自のC拡張機能に共有メモリ領域を登録させ、DSAセグメントの値を読み取り/書き込みするC関数呼び出しを使用してバックエンド間で通信することもできます。詳細については、PostgreSQLのプログラミング例を参照してください。 Cの知識、時間、そして忍耐力が必要です。



    1. キーワードによるOracleパーティション

    2. ディレクトリに保存する前にアップロードしたファイルの名前を変更するにはどうすればよいですか?

    3. node.jsを使用してmySQLに一括挿入するにはどうすればよいですか?

    4. 異なるデータベース間のMySQLInnoDB外部キー