PostgreSQL row-level security (RLS) SaaS ਵਿੱਚ ਡੇਟਾਬੇਸ ਦੇ ਅੰਦਰ ਟੇਨੈਂਟ ਆਇਸੋਲੇਸ਼ਨ ਲਾਗੂ ਕਰਨ ਵਿੱਚ ਮਦਦ ਕਰਦਾ ਹੈ। ਜਾਣੋ ਕਦੋਂ ਵਰਤਣਾ ਹੈ, ਨੀਤੀਆਂ ਕਿਵੇਂ ਲਿਖਣੀਆਂ ਹਨ, ਅਤੇ ਕੀ ਬਚਾਉਣਾ ਚਾਹੀਦਾ ਹੈ।

SaaS ਐਪ ਵਿੱਚ, ਸਭ ਤੋਂ ਖਤਰਨਾਕ ਸੁਰੱਖਿਆ ਬੱਗ ਉਹ ਹੁੰਦੀ ਹੈ ਜੋ ਤਦੋਂ ਸਾਹਮਣੇ ਆਉਂਦੀ ਹੈ ਜਦੋਂ ਤੁਸੀਂ ਸਕੇਲ ਕਰ ਲੈਂਦੇ ਹੋ। ਤੁਸੀਂ ਇੱਕ ਸਧਾਰਨ ਨਿਯਮ ਨਾਲ ਸ਼ੁਰੂ ਕਰਦੇ ਹੋ ਜਿਵੇਂ “ਉਪਭੋਗੀ ਸਿਰਫ਼ ਆਪਣੇ ਟੇਨੈਂਟ ਦਾ ਡੇਟਾ ਦੇਖ ਸਕੇ,” ਫਿਰ ਤੁਸੀਂ ਤੇਜ਼ੀ ਨਾਲ ਨਵਾਂ ਐਂਡਪੋਇੰਟ ਸ਼ਿਪ ਕਰਦੇ ਹੋ, ਇੱਕ ਰਿਪੋਰਟਿੰਗ ਕੂਐਰੀ ਜੋੜਦੇ ਹੋ, ਜਾਂ ਇਕ ਜੋਇਨ ਆ ਜਾਂਦਾ ਹੈ ਜੋ ਚੁਪਚਾਪ ਚੈਕ ਨੂੰ ਛੱਡ ਦਿੰਦਾ ਹੈ।
ਐਪ-ਅਨੁਮਤੀ (app-only authorization) ਦਬਾਅ ਹੇਠ ਟੁੱਟ ਜਾਂਦੀ ਹੈ ਕਿਉਂਕਿ ਨਿਯਮ ਟਿੱਕ-ਟਿੱਕ ਹੋ ਕੇ ਫੈਲ ਜਾਂਦੇ ਹਨ। ਇੱਕ ਕੰਟਰੋਲਰ tenant_id ਚੈੱਕ ਕਰਦਾ ਹੈ, ਦੂਜਾ ਮੈਂਬਰਸ਼ਿਪ ਚੈੱਕ ਕਰਦਾ ਹੈ, ਇੱਕ ਬੈਕਗ੍ਰਾਊਂਡ ਜੌਬ ਭੁੱਲ ਜਾਂਦਾ ਹੈ, ਅਤੇ ਇੱਕ “ਅਡਮਿਨ ਐਕਸਪੋਰਟ” ਰਸਤਾ ਮਹੀਨਿਆਂ ਤੱਕ “ਅਸਥਾਈ” ਰਹਿੰਦਾ ਹੈ। ਇਥੇ ਤੱਕ ਕਿ ਧਿਆਨ ਰੱਖਣ ਵਾਲੀਆਂ ਟੀਮਾਂ ਵੀ ਇੱਕ ਸਥਾਨ ਭੁੱਲ ਜਾਂਦੀਆਂ ਹਨ।
PostgreSQL row-level security (RLS) ਇੱਕ ਖਾਸ ਸਮੱਸਿਆ ਹੱਲ ਕਰਦਾ ਹੈ: ਇਹ ਡੇਟਾਬੇਸ ਨੂੰ ਇਹ ਨਿਰਦੇਸ਼ ਦਿੰਦਾ ਹੈ ਕਿ ਕਿਸ ਨਿਵੇਦਨ ਲਈ ਕਿਹੜੀਆਂ ਰੋਜ਼ ਦਿਸਾਈਆਂ ਜਾਂਦੀਆਂ ਹਨ। ਮਾਨਸਿਕ ਮਾਡਲ ਸਧਾਰਣ ਹੈ: ਹਰ SELECT, UPDATE, ਅਤੇ DELETE ਨੀਤੀਆਂ ਰਾਹੀਂ ਆਪੋ-ਆਪਣੇ ਫਿਲਟਰ ਹੁੰਦੇ ਹਨ, ਉਸੇ ਤਰ੍ਹਾਂ ਜਿਵੇਂ ਹਰ ਰਿਕਵੇਸਟ ਆਥੈਂਟੀਕੇਸ਼ਨ ਮਿੱਡਲਵੇਅਰ ਦੁਆਰਾ ਛਾਣੀ ਜਾਂਦੀ ਹੈ।
"ਰੋਜ਼" ਵਾਲਾ ਹਿੱਸਾ ਮਹੱਤਵਪੂਰਨ ਹੈ। RLS ਸਭ ਕੁਝ ਰੱਖ ਕੇ ਨਹੀਂ ਰੱਖਦਾ:
ਇਕ ਸਪੱਸ਼ਟ ਉਦਾਹਰਨ: ਤੁਸੀਂ ਡੈਸ਼ਬੋਰਡ ਲਈ ਪ੍ਰੋਜੈਕਟਾਂ ਦੀ ਲਿਸਟ ਵਿਖਾਉਂਦਾ ਐਂਡਪੋਇੰਟ ਜੋੜਦੇ ਹੋ ਜਿਸ ਵਿੱਚ invoices ਨਾਲ ਜੋਇਨ ਹੈ। ਐਪ-ਕੇਵਲ ਆਥਰਾਈਜ਼ੇਸ਼ਨ ਨਾਲ, ਆਸਾਨੀ ਨਾਲ projects ਨੂੰ ਟੇਨੈਂਟ ਦੁਆਰਾ ਫਿਲਟਰ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ ਪਰ invoices ਨੂੰ ਫਿਲਟਰ ਕਰਨਾ ਭੁੱਲ ਜਾਇਆ ਜਾ ਸਕਦਾ ਹੈ, ਜਾਂ ਇੱਕ ਕਾਫ਼ੀ ਸੱਖਤ ਜੋਇਨ ਟੇਨੈਂਟ ਪਾਰ ਕਰ ਸਕਦੀ ਹੈ। RLS ਨਾਲ, ਦੋਹਾਂ ਟੇਬਲ ਟੇਨੈਂਟ ਆइसੋਲੇਸ਼ਨ ਲਾਗੂ ਕਰ ਸਕਦੀਆਂ ਹਨ, ਇਸ ਲਈ ਕੂਐਰੀ ਸੇਫ਼ ਫੇਲ ਕਰਦੀ ਹੈ ਬਜਾਏ ਡੇਟਾ ਲੀਕ ਹੋਣ ਦੇ।
ਤਣਾਅ ਅਸਲ ਹੈ। ਤੁਸੀਂ ਘੱਟ ਦੁਹਰਾਏ ਆਥਰਾਈਜ਼ੇਸ਼ਨ ਕੋਡ ਲਿਖਦੇ ਹੋ ਅਤੇ ਲੀਕ ਹੋਣ ਵਾਲੀਆਂ ਥਾਵਾਂ ਘਟਾਉਂਦੇ ਹੋ। ਪਰ ਤੁਸੀਂ ਨਵਾਂ ਕੰਮ ਵੀ ਲੈਂਦੇ ਹੋ: ਨੀਤੀਆਂ ਨੂੰ ਧਿਆਨ ਨਾਲ ਡਿਜ਼ਾਈਨ ਕਰਨਾ, ਉਨ੍ਹਾਂ ਦੀ ਪਹਿਲਾਂ ਤੋਂ ਤਸਦੀਕ ਕਰਨੀ, ਅਤੇ ਇਸ ਗੱਲ ਨੂੰ ਸਵੀਕਾਰ ਕਰਨਾ ਕਿ ਕੋਈ ਨੀਤੀ ਉਸ ਕੂਐਰੀ ਨੂੰ ਰੋਕ ਸਕਦੀ ਹੈ ਜਿਸਦੀ ਤੁਸੀਂ ਉਮੀਦ ਸੀ ਕਿ ਕਾਮ ਕਰੇਗੀ।
RLS ਤੱਕ ਅਨੁਭੂਤ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਤੱਕ ਤੁਸੀਂ ਕੁਝ ਐਂਡਪੋਇੰਟ ਤੋਂ ਵੱਧ ਨਾ ਹੋਵੋ। ਜੇ ਤੁਹਾਡੇ ਕੋਲ ਸਖਤ ਟੇਨੈਂਟ ਸਰਹਦਾਂ ਹਨ ਅਤੇ ਬਹੁਤ ਸਾਰੇ ਕੂਐਰੀ ਰਸਤੇ ਹਨ (ਲਿਸਟ ਸਕ੍ਰੀਨ, ਖੋਜ, ਐਕਸਪੋਰਟ, ਐਡਮਿਨ ਟੂਲ), ਤਾਂ ਨਿਯਮ ਨੂੰ ਡੇਟਾਬੇਸ ਵਿੱਚ ਰੱਖਣਾ ਇਸਦਾ ਮਤਲਬ ਹੈ ਕਿ ਤੁਹਾਨੂੰ ਹਰ ਥਾਂ ਉਹੀ ਫਿਲਟਰ ਯਾਦ ਨਹੀਂ ਰੱਖਣਾ ਪੈਂਦਾ।
RLS ਉਹ ਵੇਲੇ ਚੰਗਾ ਫਿੱਟ ਹੁੰਦਾ ਹੈ ਜਦ ਨਿਯਮ ਬੋਰਿੰਗ ਅਤੇ ਯੂਨੀਵਰਸਲ ਹੁੰਦੇ ਹਨ: “ਉਪਭੋਗੀ ਸਿਰਫ਼ ਆਪਣੇ ਟੇਨੈਂਟ ਦੀਆਂ ਰੋਜ਼ ਦੇਖ ਸਕਦਾ ਹੈ” ਜਾਂ “ਉਪਭੋਗੀ ਸਿਰਫ਼ ਉਹੀ ਪ੍ਰੋਜੈਕਟ ਦੇਖ ਸਕਦਾ ਹੈ ਜਿਸਦਾ ਉਹ ਮੈਂਬਰ ਹੈ।” ਐਸੇ ਸੈਟਅੱਪ ਵਿੱਚ, ਨੀਤੀਆਂ ਗਲਤੀਆਂ ਘਟਾਉਂਦੀਆਂ ਹਨ ਕਿਉਂਕਿ ਹਰ SELECT, UPDATE, ਅਤੇ DELETE ਇੱਕੋ ਗੇਟ ਰਾਹੀਂ ਲੰਘਦੇ ਹਨ, ਭਾਵੇਂ ਕੂਐਰੀ ਬਾਅਦ ਵਿੱਚ ਜੋੜੀ ਜਾਵੇ।
ਇਹ ਪੜ੍ਹਨ-ਭਾਰ ਵਾਲੀਆਂ ਐਪਾਂ ਵਿੱਚ ਵੀ ਮਦਦ ਕਰਦਾ ਹੈ ਜਿੱਥੇ ਫਿਲਟਰ ਲਾਜਿਕ ਲਗਾਤਾਰ ਹੀ ਰਹਿੰਦੀ ਹੈ। ਜੇ ਤੁਹਾਡੀ API ਕੋਲ invoices ਲੋਡ ਕਰਨ ਦੇ 15 ਤਰੀਕੇ ਹਨ (ਸਥਿਤੀ, ਤਾਰੀਖ, ਗਾਹਕ, ਖੋਜ ਆਦਿ), RLS ਤੁਹਾਨੂੰ ਹਰ ਕੂਐਰੀ 'ਤੇ ਟੇਨੈਂਟ ਫਿਲਟਰ ਦੁਹਰਾਉਣ ਤੋਂ ਬਚਾਊਂਦਾ ਹੈ ਅਤੇ ਫੀਚਰ 'ਤੇ ਧਿਆਨ ਦੇਣ ਦਿੰਦਾ ਹੈ।
RLS ਤਕਲੀਫ਼ ਵਧਾਉਂਦਾ ਹੈ ਜਦ ਨਿਯਮ ਰੋ-ਅਧਾਰਤ ਨਹੀਂ ਹੁੰਦੇ। ਪਰ-ਫੀਲਡ ਨਿਯਮ ਜਿਵੇਂ “ਤੁਸੀਂ ਸੈਲਰੀ ਦੇਖ ਸਕਦੇ ਹੋ ਪਰ ਬੋਨਸ ਨਹੀਂ” ਜਾਂ “ਇਸ ਕਾਲਮ ਨੂੰ HR ਤੋਂ ਇਲਾਵਾ ਮਾਸਕ ਕਰੋ” ਅਕਸਰ ਅਜੀਬ SQL ਅਤੇ ਰੱਖ-ਰਖਾਵ ਵਿੱਚ ਮੁਸ਼ਕਲ ਛੱਡ ਦਿੰਦੀਆਂ ਹਨ।
ਇਹ ਭਾਰੀ ਰਿਪੋਰਟਿੰਗ ਲਈ ਵੀ ਔਖਾ ਫਿੱਟ ਹੁੰਦਾ ਹੈ ਜੋ ਅਸਲ ਵਿੱਚ ਵਿਆਪਕ ਪਹੁੰਚ ਦੀ ਲੋੜ ਰੱਖਦੀ ਹੈ। ਟੀਮਾਂ ਅਕਸਰ “ਸਿਰਫ਼ ਇਹ ਇਕ ਨੌਕਰੀ” ਲਈ ਬਾਈਪਾਸ ਰੋਲ ਬਣਾਉਂਦੀਆਂ ਹਨ, ਅਤੇ ਇੱਥੇ ਗਲਤੀਆਂ ਇਕੱਠੀਆਂ ਹੋ ਜਾਂਦੀਆਂ ਹਨ।
ਕੋਮਿੱਟ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ, ਨਿਰਣਯ ਕਰੋ ਕਿ ਕੀ ਤੁਸੀਂ ਡੇਟਾਬੇਸ ਨੂੰ ਆਖਰੀ ਗੇਟਕੀਪਰ ਬਣਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ। ਜੇ ਹਾਂ, ਤਾਂ ਅਨੁਸ਼ਾਸਨ ਦੀ ਯੋਜਨਾ ਬਣਾਓ: ਡੇਟਾਬੇਸ ਵਿਹਾਰ ਦੀ ਟੈਸਟਿੰਗ ਕਰੋ (ਸਿਰਫ API ਜਵਾਬ ਨਹੀਂ), ਮਾਈਗ੍ਰੇਸ਼ਨਾਂ ਨੂੰ ਸੁਰੱਖਿਆ ਬਦਲ ਸਹਿਤ treat ਕਰੋ, ਜ਼ਲਦੀ ਬਾਈਪਾਸ ਤੋਂ ਬਚੋ, ਫੈਸਲਾ ਕਰੋ ਕਿ ਬੈਕਗ੍ਰਾਊਂਡ ਜੌਬ ਕਿਵੇਂ ਪ੍ਰਮਾਣਿਕ ਹੋਣਗੇ, ਅਤੇ ਨੀਤੀਆਂ ਨੂੰ ਛੋਟਾ ਤੇ ਦੁਹਰਾਏਜੋਗ ਰੱਖੋ।
ਜੇ ਤੁਸੀਂ ਉਹ tooling ਵਰਤਦੇ ਹੋ ਜੋ ਬੈਕਐਂਡ ਬਣਾਉਂਦਾ ਹੈ, ਤਾਂ ਉਹ ਡਿਲਿਵਰੀ ਤੇ ਤੇਜ਼ੀ ਲਿਆ ਸਕਦਾ ਹੈ, ਪਰ ਇਸ ਨਾਲ ਸਪਸ਼ਟ ਰੋਲ, ਟੈਸਟ, ਅਤੇ ਸਧਾਰਨ ਟੇਨੈਂਟ ਮਾਡਲ ਦੀ ਲੋੜ ਨਹੀਂ ਘਟਦੀ। (ਉਦਾਹਰਨ ਲਈ, Koder.ai Go ਅਤੇ PostgreSQL ਨਾਲ Generated backends ਵਰਤਦਾ ਹੈ, ਅਤੇ ਫਿਰ ਵੀ ਤੁਸੀਂ RLS ਨੂੰ ਨਹੀੰ “ਬਾਅਦ ਵਿੱਚ ਛਿੜਕਣਾ” ਚਾਹੁੰਦੇ—ਇਸਨੂੰ ਜਰੂਰਲੀ ਤਰੀਕੇ ਨਾਲ ਡਿਜ਼ਾਈਨ ਕਰੋ।)
RLS ਉਸ ਵੇਲੇ ਸਭ ਤੋਂ ਆਸਾਨ ਹੁੰਦਾ ਹੈ ਜਦ ਤੁਹਾਡੀ ਸਕੀਮਾ ਪਹਿਲਾਂ ਹੀ ਸਾਫ਼ ਦੱਸਦੀ ਹੋ ਕਿ ਕਿਸ ਦੀ ਕੀ ਮਾਲਕੀ ਹੈ। ਜੇ ਤੁਸੀਂ ਇੱਕ ਧੁੰਧਲਾ ਮਾਡਲ ਨਾਲ ਸ਼ੁਰੂ ਕਰਦੇ ਹੋ ਅਤੇ ਉਹਨੂੰ “ਨੀਤੀਆਂ ਨਾਲ ਠੀਕ ਕਰਨ” ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਹੋ, ਤਾਂ ਅਕਸਰ ਤੁਹਾਨੂੰ ਸੁਸਤ ਕੂਐਰੀਆਂ ਅਤੇ ਗੁੰਝਲਦਾਰ ਬੱਗ ਮਿਲਦੇ ਹਨ।
ਇੱਕ tenant ਕੁੰਜੀ (ਜਿਵੇਂ org_id) ਚੁਣੋ ਅਤੇ ਇਸਨੂੰ ਲਗਾਤਾਰ ਵਰਤੋ। ਜ਼ਿਆਦਾਤਰ ਟੇਨੈਂਟ-ਮਲਕੀਅਤ ਵਾਲੇ ਟੇਬਲਾਂ ਵਿੱਚ ਇਹ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ, ਭਾਵੇਂ ਉਹ ਕਿਸੇ ਹੋਰ ਟੇਬਲ ਨੂੰ ਸੰਦਰਭ ਵੀ ਦਿੰਦੇ ਹੋਣ ਜੋ ਇਸਨੂੰ ਰੱਖਦਾ ਹੈ। ਇਹ ਨੀਤੀਆਂ ਅੰਦਰ ਜੋਇਨਾਂ ਤੋਂ ਬਚਾਉਂਦਾ ਹੈ ਅਤੇ USING ਚੈੱਕ ਬਨਾਏ ਰੱਖਦਾ ਹੈ।
ਇੱਕ ਕਾਰਗਰ ਨਿਯਮ: ਜੇ ਕੋਈ ਰੋ ਗਾਹਕ ਦੇ ਰੱਦ ਹੋਣ 'ਤੇ ਲਾਪਤਾ ਹੋ ਜਾਵੇ ਤਾਂ, ਉਹ ਸੰਭਵਤ: org_id ਰੱਖਣੀ ਚਾਹੀਦੀ ਹੈ।
RLS ਨੀਤੀਆਂ ਅਕਸਰ ਇੱਕ ਸਵਾਲ ਦਾ ਜਵਾਬ ਦਿੰਦੀਆਂ ਹਨ: “ਕੀ ਇਹ ਯੂਜ਼ਰ ਇਸ org ਦਾ ਮੈਂਬਰ ਹੈ, ਅਤੇ ਉਹ ਕੀ ਕਰ ਸਕਦਾ ਹੈ?” ਇਹ ਆਦ-ਹੌਕ ਕਾਲਮਾਂ ਤੋਂ ਅਨੁਮਾਨ ਲਗਾਣ ਲਈ ਮੁਸ਼ਕਲ ਹੈ।
ਕੋਰ ਟੇਬਲਾਂ ਨੈੜੇ ਅਤੇ ਸਧਾਰਨ ਰੱਖੋ:
users (ਹਰ ਵਿਅਕਤੀ ਲਈ ਇੱਕ ਪੰਗਤੀ)orgs (ਹਰ ਟੇਨੈਂਟ ਲਈ ਇੱਕ ਪੰਗਤੀ)org_memberships (user_id, org_id, role, status)project_membershipsਇਸ ਨਾਲ, ਤੁਹਾਡੀਆਂ ਨੀਤੀਆਂ ਇੱਕ ਇੰਡੈਕਸ ਕੀਤੀ ਲੁਕਅਪ ਨਾਲ ਮੈਂਬਰਸ਼ਿਪ ਦੀ ਜਾਂਚ ਕਰ ਸਕਦੀਆਂ ਹਨ।
ਹਰ ਚੀਜ਼ ਨੂੰ org_id ਦੀ ਲੋੜ ਨਹੀਂ ਹੁੰਦੀ। ਦੇਸ਼ਾਂ, ਉਤਪਾਦ ਦੀਆਂ ਵਰਗੀਆਂ ਰੈਫਰੈਂਸ ਟੇਬਲਾਂ ਆਮਤੌਰ 'ਤੇ ਸਾਰਿਆਂ ਟੇਨੈਂਟਾਂ ਲਈ ਸਾਂਝੀਆਂ ਹੁੰਦੀਆਂ ਹਨ। ਉਨ੍ਹਾਂ ਨੂੰ ਜ਼ਿਆਦਾਤਰ ਰੋਲਾਂ ਲਈ ਰੀਡ-ਓਨਲੀ ਬਣਾਓ ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਕਿਸੇ ਇਕ org ਨਾਲ ਨਾ ਜੋੜੋ।
ਟੇਨੈਂਟ-ਮਲਕੀਅਤ ਡੇਟਾ (projects, invoices, tickets) ਨੂੰ ਸਾਂਝੇ ਟੇਬਲਾਂ ਰਾਹੀਂ ਟੇਨੈਂਟ-ਨਿਯਮ ਲੈ ਕੇ ਆਉਣ ਤੋਂ ਬਚਾਉ। ਸਾਂਝੇ ਟੇਬਲਾਂ ਨੂੰ ਨਿਊਨਤਮ ਅਤੇ ਸਥਿਰ ਰੱਖੋ।
Foreign keys RLS ਨਾਲ ਅਜੇ ਵੀ ਕੰਮ ਕਰਦੇ ਹਨ, ਪਰ deletes ਤੁਹਾਨੂੰ ਹੈਰਾਨ ਕਰ ਸਕਦੀਆਂ ਹਨ ਜੇ delete ਕਰਨ ਵਾਲਾ ਰੋਲ ਨਿਰਪੇਖ ਰੋਜ਼ ਨੂੰ “ਦੇਖ” ਨਹੀਂ ਸਕਦਾ। cascade ਯੋਜਨਾ ਧਿਆਨ ਨਾਲ ਬਣਾਓ ਅਤੇ ਅਸਲੀ ਡੀਲੀਟ ਫਲੋਜ਼ ਦੀ ਜਾਂਚ ਕਰੋ।
ਉਹ ਕਾਲਮ ਇੰਡੈਕਸ ਕਰੋ ਜਿਨ੍ਹਾਂ 'ਤੇ ਤੁਹਾਡੀਆਂ ਨੀਤੀਆਂ ਫਿਲਟਰ ਕਰਦੀਆਂ ਹਨ, ਖਾਸ ਕਰਕੇ org_id ਅਤੇ ਮੈਂਬਰਸ਼ਿਪ ਕੁੰਜੀਆਂ। ਇੱਕ ਨੀਤੀ ਜੋ ਇੰਝ ਲਿਖੀ ਹੋਵੇ “WHERE org_id = ...” ਉਸ ਨੂੰ ਮਿਲਦੀ ਇੰਡੈਕਸ ਨਾ ਮਿਲਣ 'ਤੇ ਮਿਲੀਅਨ ਰੋਜ਼ ਵਾਲੀ ਟੇਬਲ ਤੇ ਫੁੱਲ-ਟੇਬਲ ਸਕੈਨ ਬਣਨ ਨਾ ਦਿਓ।
RLS ਇੱਕ ਪ੍ਰਤੀ-ਟੇਬਲ ਸਵਿੱਚ ਹੈ। ਇੱਕ ਵਾਰੀ ਯੋਗ ਹੋ ਜਾਣ 'ਤੇ, PostgreSQL ਤੁਹਾਡੇ ਐਪ ਕੋਡ ਨੂੰ ਟੇਨੈਂਟ ਫਿਲਟਰ ਯਾਦ ਰੱਖਣ 'ਤੇ ਭਰੋਸਾ ਕਰਨਾ ਬੰਦ ਕਰ ਦਿੰਦਾ ਹੈ। ਹਰ SELECT, UPDATE, ਅਤੇ DELETE ਨੀਤੀਆਂ ਰਾਹੀਂ ਫਿਲਟਰ ਹੁੰਦੇ ਹਨ, ਅਤੇ ਹਰ INSERT ਅਤੇ UPDATE ਨੀਤੀਆਂ ਨਾਲ ਵੇਰੀਫਾਈ ਹੁੰਦੇ ਹਨ।
ਸਭ ਤੋਂ ਵੱਡਾ ਮਾਨਸਿਕ ਤਬਦੀਲੀ: RLS ਚਾਲੂ ਹੋਣ 'ਤੇ, ਉਹ ਕੂਐਰੀਆਂ ਜੋ ਪਹਿਲਾਂ ਡੇਟਾ ਵਾਪਸ ਕਰਦੀਆਂ ਸਨ ਹੁਣ ਬਿਨਾਂ ਐਰਰ ਦੇ ਜ਼ੀਰੋ ਰੋਜ਼ ਵਾਪਸ ਕਰ ਸਕਦੀਆਂ ਹਨ। ਇਹ PostgreSQL ਦੁਆਰਾ ਐਕਸੈੱਸ ਕੰਟਰੋਲ ਕਰਨਾ ਹੈ।
ਨੀਤੀਆਂ ਥੋੜੀਆਂ ਨਿਯਮਾਂ ਹੁੰਦੀਆਂ ਹਨ ਜੋ ਇੱਕ ਟੇਬਲ ਨਾਲ ਜੁੜੀਆਂ ਹੁੰਦੀਆਂ ਹਨ। ਉਹ ਦੋ ਚੈੱਕ ਵਰਤਦੀਆਂ ਹਨ:
USING ਪੜ੍ਹਨ ਫਿਲਟਰ ਹੈ। ਜੇ ਕੋਈ ਰੋ USING ਨਾਲ ਮੇਲ ਨਹੀਂ ਖਾਂਦੀ ਤਾਂ ਉਹ SELECT ਲਈ ਅਦ੍ਰਸ਼ਯ ਹੈ, ਅਤੇ ਉਸਨੂੰ UPDATE ਜਾਂ DELETE ਲਈ ਟਾਰਗੇਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ।WITH CHECK ਲਿਖਣ ਦਾ ਦਰਵਾਜ਼ਾ ਹੈ। ਇਹ ਫੈਸਲਾ ਕਰਦਾ ਹੈ ਕਿ ਨਵੀਆਂ ਜਾਂ ਬਦਲੀ ਹੋਈਆਂ ਰੋਜ਼ INSERT ਜਾਂ UPDATE ਦੌਰਾਨ ਮਨਜ਼ੂਰ ਹਨ ਕਿ ਨਹੀਂ।ਇੱਕ ਆਮ SaaS ਪੈਟਰਨ: USING ਇਹ ਨਿਸ਼ਚਿਤ ਕਰਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਸਿਰਫ਼ ਆਪਣੇ ਟੇਨੈਂਟ ਦੀਆਂ ਰੋਜ਼ ਵੇਖੋ, ਅਤੇ WITH CHECK ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦਾ ਹੈ ਕਿ ਤੁਸੀਂ ਗਲਤ tenant ID ਭੇਜ ਕਰ ਹੋਰ ਕਿਸੇ ਦੇ ਟੇਨੈਂਟ ਵਿੱਚ ਰੋ ਸ਼ਾਮਲ ਨਹੀਂ ਕਰ ਸਕਦੇ।
ਜਦੋਂ ਤੁਸੀਂ ਬਾਅਦ ਵਿੱਚ ਹੋਰ ਨੀਤੀਆਂ ਜੋੜਦੇ ਹੋ, ਇਹ ਮੈਟਰ ਕਰਦਾ ਹੈ:
PERMISSIVE (ਡਿਫਾਲਟ): ਕੋਈ ਵੀ ਨੀਤੀ ਜੇ ਰੋ ਨੂੰ ਮਨਜ਼ੂਰ ਕਰਦੀ ਹੈ ਤਾਂ ਰੋ ਅਨੁਮਤ ਹੁੰਦੀ ਹੈ।RESTRICTIVE: ਇੱਕ ਰੋ ਸਿਰਫ਼ ਤਦ ਹੀ ਅਨੁਮਤ ਹੋਵੇਗੀ ਜਦ ਸਾਰੀ ਵੱਖ-ਵੱਖ restrictive ਨੀਤੀਆਂ ਵੀ ਉਸਨੂੰ ਮਨਜ਼ੂਰ ਕਰਨ—ਪ੍ਰਯੋਗਕਰ PERMISSIVE ਵਿਹਾਰ ਦੇ ਉੱਪਰ।ਜੇ ਤੁਸੀਂ ਟੇਨੈਂਟ ਮੇਚ + ਰੋਲ ਚੈੱਕ + ਪ੍ਰੋਜੈਕਟ ਮੈਂਬਰਸ਼ਿਪ ਵਰਗੇ ਲੇਅਰ ਕਰਨ ਦੀ ਯੋਜਨਾ ਬਣਾਉਂਦੇ ਹੋ, ਤਾਂ restrictive ਨੀਤੀਆਂ ਇਰਾਦੇ ਨੂੰ ਸਪਸ਼ਟ ਕਰ ਸਕਦੀਆਂ ਹਨ, ਪਰ ਜੇ ਤੁਸੀਂ ਇੱਕ ਸ਼ਰਤ ਭੁੱਲ ਜਾਂਦੇ ਹੋ ਤਾਂ ਇਹ ਤੁਹਾਨੂੰ ਬਾਹਰ ਬਾਹਰ ਕਰਨਾ ਆਸਾਨ ਕਰ ਦਿੰਦੀਆਂ ਹਨ।
RLS ਨੂੰ ਇੱਕ ਭਰੋਸੇਯੋਗ “ਕੌਣ ਕਾਲ ਕਰ ਰਿਹਾ ਹੈ” ਮੁੱਲ ਚਾਹੀਦਾ ਹੈ। ਆਮ ਵਿਕਲਪ:
app.user_id ਅਤੇ app.tenant_id)।SET ROLE ... ਪ੍ਰਤੀ-ਰਿਕਵੇਸਟ), ਜੋ ਕੰਮ ਕਰ ਸਕਦਾ ਹੈ ਪਰ ਇਸ ਨਾਲ ਆਪਰੇਸ਼ਨਲ ਓਵਰਹੈੱਡ ਵਧਦਾ ਹੈ।ਇੱਕ ਢੰਗ ਚੁਣੋ ਅਤੇ ਸਾਰਿਆਂ ਥਾਵਾਂ ਤੇ ਉਹੀ ਅਪਲਾਈ ਕਰੋ। ਸੇਵਾ-ਆਧਾਰਿਤ ਆਈਡੈਂਟੀਟੀ ਸਰੋਤਾਂ ਨੂੰ ਮਿਲਾ-ਝੁਲਾ ਕਰਨਾ ਗਲਤੀਆਂ ਵਧਾਉਂਦਾ ਹੈ।
ਇੱਕ ਪੂਰਨ ਪਰੰਪਰਾ ਵਰਤੋ ਤਾਂ ਕਿ ਸਕੀਮਾ ਡੰਪ ਅਤੇ ਲਾੱਗ ਪੜ੍ਹਨਯੋਗ ਰਹਿਣ। ਉਦਾਹਰਨ: {table}__{action}__{rule}, ਜਿਵੇਂ projects__select__tenant_match।
ਜੇ ਤੁਸੀਂ RLS ਲਈ ਨਵੇਂ ਹੋ, ਤਾਂ ਇੱਕ ਟੇਬਲ ਨਾਲ ਸ਼ੁਰੂ ਕਰੋ ਅਤੇ ਇੱਕ ਛੋਟਾ ਪ੍ਰੂਫ਼ ਕਰੋ। ਮਕਸਦ ਪੂਰੀ ਕਵਰੇਜ ਨਹੀਂ—ਮਕਸਦ ਇਹ ਹੈ ਕਿ ਡੇਟਾਬੇਸ ਅਜਿਹੀਆਂ ਹਾਲਤਾਂ ਵਿੱਚ ਵੀ ਕ੍ਰਾਸ-ਟੇਨੈਂਟ ਪਹੁੰਚ ਨੂੰ ਇਨਕਾਰ ਕਰੇ ਜਦ ਐਪ ਵਿੱਚ ਬਗ ਆ ਜਾਵੇ।
ਮੰਨ ਲਓ ਇੱਕ ਸਧਾਰਨ projects ਟੇਬਲ ਹੈ। ਪਹਿਲਾਂ, tenant_id ਐਸੇ ਤਰੀਕੇ ਨਾਲ ਜੋੜੋ ਜੋ ਲਿਖਤਾਂ ਨੂੰ ਨਾਭਾ ਨਾ ਦੇਵੇ।
ALTER TABLE projects ADD COLUMN tenant_id uuid;
-- Backfill existing rows (example: everyone belongs to a default tenant)
UPDATE projects SET tenant_id = '11111111-1111-1111-1111-111111111111'::uuid
WHERE tenant_id IS NULL;
ALTER TABLE projects ALTER COLUMN tenant_id SET NOT NULL;
ਅਗਲੇ, ਮਾਲਕੀ ਨੂੰ ਪਹੁੰਚ ਤੋਂ ਵੱਖ ਕਰੋ। ਇੱਕ ਆਮ ਪੈਟਰਨ ਹੈ: ਇੱਕ ਰੋਲ ਟੇਬਲਾਂ ਦਾ ਮਾਲਕ ਹੁੰਦਾ ਹੈ (app_owner), ਦੂਜਾ ਰੋਲ API ਦੁਆਰਾ ਵਰਤਿਆ ਜਾਂਦਾ ਹੈ (app_user)। API ਰੋਲ ਟੇਬਲ ਮਾਲਕ ਨਹੀਂ ਹੋਣਾ ਚਾਹੀਦਾ, ਨਹੀਂ ਤਾਂ ਉਹ ਨੀਤੀਆਂ ਨੂੰ ਬਾਈਪਾਸ ਕਰ ਸਕਦਾ ਹੈ।
ALTER TABLE projects OWNER TO app_owner;
REVOKE ALL ON projects FROM PUBLIC;
GRANT SELECT, INSERT, UPDATE, DELETE ON projects TO app_user;
ਹੁਣ ਫੈਸਲਾ ਕਰੋ ਕਿ ਰਿਕਵੇਸਟ Postgres ਨੂੰ ਕਿਵੇਂ ਦੱਸਦੀ ਹੈ ਕਿ ਉਹ ਕਿਹੜਾ ਟੇਨੈਂਟ ਸਰਵ ਕਰ ਰਿਹਾ ਹੈ। ਇਕ ਸਧਾਰਨ ਤਰੀਕਾ ਹੈ ਇਕ ਰਿਕਵੇਸਟ-ਸਕੋਪਡ ਸੈਟਿੰਗ। ਤੁਹਾਡੀ ਐਪ ਟ੍ਰਾਂਜ਼ੈਕਸ਼ਨ ਖੋਲ੍ਹਣ ਤੋਂ ਬਾਅਦ ਇਸਨੂੰ ਸੈਟ ਕਰਦੀ ਹੈ।
-- inside the same transaction as the request
SELECT set_config('app.current_tenant', '22222222-2222-2222-2222-222222222222', true);
RLS ਚਾਲੂ ਕਰੋ ਅਤੇ ਪਹਿਲਾਂ ਪੜ੍ਹਨ ਦੀ ਪਹੁੰਚ ਨਾਲ ਸ਼ੁਰੂ ਕਰੋ।
ALTER TABLE projects ENABLE ROW LEVEL SECURITY;
CREATE POLICY projects_tenant_select
ON projects
FOR SELECT
TO app_user
USING (tenant_id = current_setting('app.current_tenant')::uuid);
ਦੋ ਵੱਖ-ਵੱਖ ਟੇਨੈਂਟਾਂ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਕੇ ਇਹ ਦੱਸੋ ਕਿ ਰੋ ਕਿਵੇਂ ਗਿਣਤੀ ਵਿੱਚ ਬਦਲਦੀ ਹੈ।
WITH CHECK) ਜੋੜੋਪੜ੍ਹਨ ਵਾਲੀਆਂ ਨੀਤੀਆਂ ਲਿਖਣ ਨੂੰ ਨਹੀਂ ਬਚਾਉਂਦੀਆਂ। WITH CHECK ਜੋੜੋ ਤਾਂ ਕਿ INSERT ਅਤੇ UPDATE ਰਾਹੀਂ ਦੂਜੇ ਟੇਨੈਂਟ ਵਿੱਚ ਰੋ ਸਮੇਤਣ ਨਾ ਹੋ ਸਕੇ।
CREATE POLICY projects_tenant_write
ON projects
FOR INSERT, UPDATE
TO app_user
WITH CHECK (tenant_id = current_setting('app.current_tenant')::uuid);
ਇੱਕ ਤੇਜ਼ ਤਰੀਕਾ ਤਾਂ ਕਿ ਵਿਹਾਰ (ਤੱਖ-ਕਾਮਯਾਬੀਆਂ ਸਮੇਤ) ਦੀ ਜਾਂਚ ਕੀਤੀ ਜਾਵੇ ਉਹ ਹੈ ਕਿ ਹਰ ਮਾਈਗ੍ਰੇਸ਼ਨ ਤੋਂ ਬਾਅਦ ਇੱਕ ਛੋਟੀ SQL ਸਕ੍ਰਿਪਟ ਰੱਖੋ ਅਤੇ ਚਲਾਓ:
BEGIN; SET LOCAL ROLE app_user;SELECT set_config('app.current_tenant', '\u003ctenant A\u003e', true); SELECT count(*) FROM projects;INSERT INTO projects(id, tenant_id, name) VALUES (gen_random_uuid(), '\u003ctenant B\u003e', 'bad'); (ਫੇਲ ਹੋਣਾ ਚਾਹੀਦਾ)UPDATE projects SET tenant_id = '\u003ctenant B\u003e' WHERE ...; (ਫੇਲ ਹੋਣਾ ਚਾਹੀਦਾ)ROLLBACK;ਜੇ ਤੁਸੀਂ ਇਹ ਸਕ੍ਰਿਪਟ ਚਲਾ ਸਕਦੇ ਹੋ ਅਤੇ ਹਰ ਵਾਰੀ ਉਹੀ ਨਤੀਜੇ ਮਿਲਦੇ ਹਨ, ਤਾਂ ਤੁਹਾਡੇ ਕੋਲ RLS ਨੂੰ ਹੋਰ ਟੇਬਲਾਂ 'ਤੇ ਫੈਲਾਉਣ ਤੋਂ ਪਹਿਲਾਂ ਇੱਕ ਭਰੋਸੇਯੋਗ ਬੇਸਲਾਈਨ ਹੈ।
ਜਦੋਂ ਟੀਮਾਂ ਹਰ ਕੂਐਰੀ 'ਤੇ ਇੱਕੋ ਜਿਹੇ ਆਥਰਾਈਜ਼ੇਸ਼ਨ ਚੈਕ ਦੁਹਰਾਉਣ ਤੋਂ ਥੱਕ ਜਾਂਦੀਆਂ ਹਨ ਤਾਂ ਉਹ RLS ਅਪਣਾਉਂਦੀਆਂ ਹਨ। ਚੰਗੀ ਖ਼ਬਰ ਇਹ ਹੈ ਕਿ ਜਿਨ੍ਹਾਂ ਨੀਤੀ ਸ਼ੇਪਾਂ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ ਉਹ ਆਮ ਤੌਰ ਤੇ ਇਕੋ ਜਿਹੀਆਂ ਹੁੰਦੀਆਂ ਹਨ।
ਕੁਝ ਟੇਬਲ ਕੁਦਰਤੀ ਤੌਰ ਤੇ ਇੱਕ ਯੂਜ਼ਰ ਵੱਲੋਂ ਮਲਕੀਅਤ ਹਨ (ਨੋਟਸ, API ਟੋਕਨ)। ਹੋਰ ਟੇਬਲ ਟੇਨੈਂਟ-ਅਧਾਰਤ ਹੁੰਦੀਆਂ ਹਨ ਜਿੱਥੇ ਪਹੁੰਚ ਮੈਂਬਰਸ਼ਿਪ ਉੱਤੇ ਨਿਰਭਰ ਕਰਦੀ ਹੈ। ਇਨ੍ਹਾਂ ਨੂੰ ਵੱਖ-ਵੱਖ ਪੈਟਰਨ ਵਜੋਂ ਟਰੀਟ ਕਰੋ।
ਮਾਲਕ-ਕੇਵਲ ਡੇਟਾ ਲਈ, ਨੀਤੀਆਂ ਅਕਸਰ created_by = app_user_id() ਦੀ ਜਾਂਚ ਕਰਦੀਆਂ ਹਨ। ਟੇਨੈਂਟ ਡੇਟਾ ਲਈ, ਨੀਤੀਆਂ ਆਮਤੌਰ 'ਤੇ ਜਾਂਚਦੀਆਂ ਹਨ ਕਿ ਕੀ ਯੂਜ਼ਰ ਲਈ org_memberships ਵਿੱਚ ਰੋ ਮੌਜੂਦ ਹੈ।
ਨਿਤੀਆਂ ਪੜ੍ਹਨਯੋਗ ਰੱਖਣ ਲਈ ਇੱਕ ਕਾਰਗਰ ਤਰੀਕਾ ਇਹ ਹੈ ਕਿ ਆਈਡੈਂਟੀਟੀ ਸੈਂਟਰਲਾਈਜ਼ਡ ਛੋਟੇ SQL ਹੇਲਪਰਾਂ ਵਿੱਚ ਰੱਖੋ ਅਤੇ ਦੁਹਰਾਓ:
-- Example helpers
create function app_user_id() returns uuid
language sql stable as $$
select current_setting('app.user_id', true)::uuid
$$;
create function app_is_admin() returns boolean
language sql stable as $$
select current_setting('app.is_admin', true) = 'true'
$$;
ਪੜ੍ਹਨ ਅਕਸਰ ਲਿਖਣ ਨਾਲੋਂ ਵੱਡੀ ਪਹੁੰਚ ਦਿੰਦੇ ਹਨ। ਉਦਾਹਰਨ ਲਈ, ਕੋਈ ਵੀ org ਮੈਂਬਰ SELECT ਕਰ ਸਕਦਾ ਹੈ, ਪਰ ਸਿਰਫ਼ ਐਡੀਟਰ UPDATE ਕਰ ਸਕਦੇ ਹਨ, ਅਤੇ ਸਿਰਫ਼ ਮਾਲਕ DELETE ਕਰ ਸਕਦੇ ਹਨ।
ਇਸਨੂੰ explicit ਰੱਖੋ: ਇੱਕ ਨੀਤੀ SELECT ਲਈ (ਮੈਂਬਰਸ਼ਿਪ), ਇੱਕ ਨੀਤੀ INSERT/UPDATE ਅਤੇ WITH CHECK ਲਈ (ਰੋਲ ਅਨੁਸਾਰ), ਅਤੇ ਇੱਕ DELETE ਲਈ (ਆਮ ਤੌਰ 'ਤੇ update ਨਾਲੋਂ ਜ਼ਿਆਦਾ ਸਖ਼ਤ)।
ਐਡਮਿਨ ਲਈ RLS ਬੰਦ ਨਾ ਕਰੋ। ਬਜਾਏ, ਨੀਤੀਆਂ ਵਿੱਚ ਇੱਕ ਐਸਕੇਪ ਹੈਚ ਵਰਗਾ ਜੋੜੋ, ਜਿਵੇਂ app_is_admin() ਤਾਂ ਜੋ ਤੁਸੀਂ ਕਿਸੇ ਸਾਂਝੇ ਸਰਵਿਸ ਰੋਲ ਨੂੰ ਅਕਸਮਾਤ ਪੂਰੀ ਪਹੁੰਚ ਨਾ ਦੇ ਦਿਓ।
ਜੇ ਤੁਸੀਂ deleted_at ਜਾਂ status ਵਰਤਦੇ ਹੋ, ਤਾਂ ਇਸਨੂੰ SELECT ਨੀਤੀ ਵਿੱਚ ਸ਼ਾਮਿਲ ਕਰੋ (deleted_at is null)—ਨਾਹ ਤਾਂ ਕੋਈ ਵਿਅਕਤੀ ਉਹੀ ਫਲੈਗ ਫਲਿ�ਪ ਕਰਕੇ ਰੋਜ਼ “ਜਿੰਦਾਬਾਦ” ਕਰ ਸਕਦਾ ਹੈ ਜਿਸਨੂੰ ਐਪ ਨੇ ਤਸਵੀਰਕਤ ਮੰਨਿਆ ਸੀ।
WITH CHECK ਨੂੰ ਮਿੱਤਰਪੂਰਨ ਰੱਖੋINSERT ... ON CONFLICT DO UPDATE ਦੌਰਾਨ WITH CHECK ਨੂੰ ਲਿਖੇ ਗਏ ਅੰਤਿਮ ਰੋ ਤੇ ਮਿਲਣਾ ਚਾਹੀਦਾ ਹੈ। ਜੇ ਤੁਹਾਡੀ ਨੀਤੀ created_by = app_user_id() ਮੰਗਦੀ ਹੈ, ਤਾਂ ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਤੁਹਾਡਾ upsert insert 'ਤੇ created_by ਸੈੱਟ ਕਰਦਾ ਹੈ ਅਤੇ update 'ਤੇ ਇਸਨੂੰ ਓਵਰਰਾਈਟ ਨਹੀਂ ਕਰਦਾ।
ਜੇ ਤੁਸੀਂ ਬੈਕਐਂਡ ਕੋਡ ਜਨਰੇਟ ਕਰਦੇ ਹੋ, ਤਾਂ ਇਹ ਪੈਟਰਨਜ਼ ਅੰਦਰੂਨੀ ਟੈੰਪਲੇਟਾਂ ਵਿੱਚ ਰੱਖਣ ਯੋਗ ਹਨ ਤਾਂ ਕਿ ਨਵੀਆਂ ਟੇਬਲ ਸੇਫ ਡੀਫ਼ਾਲਟ ਨਾਲ ਆਉਣ ਨਾਂਹ ਕਿ ਖਾਲੀ ਸਲੇਟ ਨਾਲ।
RLS ਵਧੀਆ ਹੈ ਜਦ ਤੱਕ ਇੱਕ ਛੋਟਾ ਵੇਰਵਾ PostgreSQL ਨੂੰ “ਅਚਾਨਕ” ਡੇਟਾ ਛੁਪਾਉਣ ਜਾਂ ਦਿਖਾਉਣ ਵਾਲਾ ਬਣਾਉਂਦਾ। ਹੇਠਾਂ ਦਿੱਤੀਆਂ ਗਲਤੀਆਂ ਸਭ ਤੋਂ ਵਧੇਰੇ ਸਮਾਂ ਖਰਚ ਕਰਦੀਆਂ ਹਨ।
ਪਹਿਲੀ ਫਸਲ ਹੈ WITH CHECK ਨੂੰ ਯਾਦ ਨਾ ਕਰਨਾ। USING ਜੋ ਤੁਹਾਨੂੰ ਦਿਖਾਈ ਜਾਂਦੀ ਹੈ ਉਸ ਨੂੰ ਨਿਯੰਤਰਿਤ ਕਰਦਾ ਹੈ, ਪਰ ਜੋ ਤੁਸੀਂ ਬਣਾਉਂਦੇ ਹੋ ਉਹ ਨਹੀਂ। WITH CHECK ਤੋਂ ਬਿਨਾਂ, ਇੱਕ ਐਪ ਬੱਗ ਗਲਤ ਟੇਨੈਂਟ ਵਿੱਚ ਰੋ ਲਿਖ ਸਕਦਾ ਹੈ, ਅਤੇ ਤੁਸੀਂ ਨੋਟਿਸ ਨਹੀਂ ਕਰੋਗੇ ਕਿਉਂਕਿ ਉਸੇ ਯੂਜ਼ਰ ਲਈ ਪੜ੍ਹਨ ਲਈ ਉਹ ਰੋ ਅਦ੍ਰਸ਼ਯ ਹੈ।
ਦੂਜਾ ਆਮ ਲੀਕ “ਲੀਕੀ ਜੋਇਨ” ਹੈ। ਤੁਸੀਂ projects ਨੂੰ ਸਹੀ ਤਰ੍ਹਾਂ ਫਿਲਟਰ ਕਰਦੇ ਹੋ, ਫਿਰ invoices, notes, ਜਾਂ files ਨਾਲ ਜੋਇਨ ਕਰਦੇ ਹੋ ਜੋ ਇਕੋ ਤਰ੍ਹਾਂ பாதுகਤ ਨਹੀਂ ਹਨ। ਸਹੀ ਠੀਕ ਸੁਧਾਰ ਸਖਤ ਪਰ ਸਿੱਧਾ ਹੈ: ਹਰ ਟੇਬਲ ਜੋ ਟੇਨੈਂਟ ਡੇਟਾ ਬਿਆਨ ਕਰ ਸਕਦਾ ਹੈ ਉਸਨੂੰ ਆਪਣੀ ਨੀਤੀ ਚਾਹੀਦੀ ਹੈ, ਅਤੇ views ਨੂੰ ਇਸ ਗੱਲ 'ਤੇ ਨਿਰਭਰ ਨਾ ਕਰਨ ਦਿਓ ਕਿ ਕੇਵਲ ਇੱਕ ਟੇਬਲ ਸੁਰੱਖਿਅਤ ਹੈ।
ਆਮ ਨਕਲੀ ਨਮੂਨੇ ਸ਼ੁਰੂ ਵਿੱਚ ਹੀ ਸਾਹਮਣੇ ਆਉਂਦੇ ਹਨ:
WITH CHECK ਛੱਡਦੀ ਹੈ।tenant_id ਸੈੱਟ ਕਰਦਾ ਹੈ” ਤੇ ਨਿਰਭਰ ਹੋ, ਅਤੇ ਇੱਕ ਬੈਕਗ੍ਰਾਊਂਡ ਜੌਬ ਭੁੱਲ ਜਾਂਦਾ ਹੈ।ਜੋ ਨੀਤੀਆਂ ਇੱਕੋ टੇਬਲ ਨੂੰ ਸਿਧੇ ਜਾਂ view ਰਾਹੀਂ reference ਕਰਦੀਆਂ ਹਨ ਉਹ recursion surprises ਪੈਦਾ ਕਰ ਸਕਦੀਆਂ ਹਨ। ਇੱਕ ਨੀਤੀ ਮੈਂਬਰਸ਼ਿਪ ਦੀ ਜਾਂਚ view ਦੇ ਕੇ ਕਰ ਸਕਦੀ ਹੈ ਜੋ ਸੁਰੱਖਿਅਤ ਟੇਬਲ ਨੂੰ ਮੁੜ ਪੜ੍ਹਦਾ ਹੈ, ਜਿਸ ਨਾਲ ਐਰਰ, ਸਲੋ ਕੂਐਰੀ, ਜਾਂ ਇੱਕ ਅਜਿਹਾ ਨਤੀਜਾ ਆ ਸਕਦਾ ਹੈ ਜੋ ਕਦੇ ਵੀ ਮੇਲ ਨਹੀਂ ਖਾਂਦਾ।
ਰੋਲ ਸੈਟਅੱਪ ਵੀ ਗੁੰਝਲਦਾਰ ਵੇਲੇ-ਵਿਚਾਰ ਦਾ ਸਰੋਤ ਹੈ। ਟੇਬਲ ਮਾਲਕ ਅਤੇ ਉੱਚ ਅਧਿਕਾਰ ਵਾਲੇ ਰੋਲ RLS ਨੂੰ ਬਾਈਪਾਸ ਕਰ ਸਕਦੇ ਹਨ, ਇਸ ਲਈ ਤੁਹਾਡੇ ਟੈਸਟਾਂ ਵਿੱਚ ਸਫਲਤਾ ਹੋ ਸਕਦੀ ਹੈ ਜਦ ਕਿ ਅਸਲੀ ਯੂਜ਼ਰ ਫੇਲ ਹੁੰਦੇ ਹਨ (ਅਥਵਾ ਇਸਦੇ ਉਲਟ)। ਹਮੇਸ਼ਾਂ ਉਹੋ ਹੀ ਘੱਟ-ਅਧਿਕਾਰ ਰੋਲ ਨਾਲ ਟੈਸਟ ਕਰੋ ਜੋ ਤੁਹਾਡੀ ਐਪ ਵਰਤਦੀ ਹੈ।
SECURITY DEFINER ਫੰਕਸ਼ਨਾਂ ਨਾਲ ਸਾਵਧਾਨ ਰਹੋ। ਉਹ ਫੰਕਸ਼ਨ ਮਾਲਕ ਦੇ ਅਧਿਕਾਰਾਂ ਨਾਲ ਚੱਲਦੇ ਹਨ, ਇਸ ਲਈ ਇੱਕ ਹੇਲਪਰ ਜਿਵੇਂ current_tenant_id() ਠੀਕ ਹੋ ਸਕਦਾ ਹੈ, ਪਰ ਇੱਕ “ਸੁਵਿਧਾ” ਫੰਕਸ਼ਨ ਜੋ ਡੇਟਾ ਪੜ੍ਹਦਾ ਹੈ ਉਹ ਅਕਸਮਾਤ ਟੇਨੈਂਟ-ਪਾਰ ਡੇਟਾ ਪੜ੍ਹ ਸਕਦਾ ਹੈ ਜੇ ਤੁਸੀਂ ਉਸਨੂੰ RLS ਦਾ ਆਦਰ ਕਰਨ ਵਾਲਾ ਨਹੀਂ ਬਣਾਉਂਦੇ।
ਸੁਰੱਖਿਅਤ search_path ਵੀ ਸੈੱਟ ਕਰੋ security definer ਫੰਕਸ਼ਨਾਂ ਵਿੱਚ। ਨਹੀਂ ਤਾਂ ਫੰਕਸ਼ਨ ਇਕੋ ਨਾਮ ਵਾਲੇ ਵੱਖ-ਵੱਖ ਓਬਜੈਕਟ ਨੂੰ ਚੁਣ ਸਕਦੀ ਹੈ ਅਤੇ ਤੁਹਾਡੀ ਨੀਤੀ ਲਾਜਿਕ ਅਕਸਮਾਤ ਸੈਸ਼ਨ ਸਥਿਤੀ ਅਨੁਸਾਰ ਗਲਤ ਓਬਜੈਕਟ ਵੇਖਣ ਲੱਗੇਗੀ।
RLS ਦੀਆਂ ਗਲਤੀਆਂ ਆਮ ਤੌਰ 'ਤੇ ਸੰਦਰਭ ਦੀ ਕਮੀ ਹੁੰਦੀਆਂ ਹਨ, ਨਾ ਕਿ “ਖਰਾਬ SQL।” ਇੱਕ ਨੀਤੀ ਕਾਗਜ਼ 'ਤੇ ਸਹੀ ਹੋ ਸਕਦੀ ਹੈ ਅਤੇ ਫਿਰ ਵੀ ਫੇਲ ਹੋ ਸਕਦੀ ਹੈ ਕਿਉਂਕਿ ਸੈਸ਼ਨ ਰੋਲ ਤੁਹਾਡੇ ਸੋਚੇ ਹੋਏ ਨਾਲ ਵੱਖਰਾ ਹੈ, ਜਾਂ ਕਿਉਂਕਿ ਰਿਕਵੇਸਟ ਕਦੇ ਵੀ ਉਹ ਟੇਨੈਂਟ ਅਤੇ ਯੂਜ਼ਰ ਮੁੱਲ ਸੈਟ ਨਹੀਂ ਕਰਦੀ ਜਿਨ੍ਹਾਂ 'ਤੇ ਨੀਤੀ ਨਿਰਭਰ ਕਰਦੀ ਹੈ।
ਇੱਕ ਭਰੋਸੇਯੋਗ ਤਰੀਕਾ ਪ੍ਰੋਡਕਸ਼ਨ ਰਿਪੋਰਟ ਨੂੰ ਦੁਹਰਾਉਣ ਲਈ ਹੈ ਉੱਥੇ ਹੀ ਸੈਸ਼ਨ ਸੈਟਅੱਪ ਲੋਕਲ ਤੌਰ 'ਤੇ ਨਕਲ ਕਰੋ ਅਤੇ ਉਹੀ ਕੂਐਰੀ ਚਲਾਓ। ਇਹ ਆਮਤੌਰ 'ਤੇ ਮਤਲਬ:
SET ROLE app_user; (ਜਾਂ ਅਸਲੀ API ਰੋਲ)SELECT set_config('app.tenant_id', 't_123', true); ਅਤੇ SELECT set_config('app.user_id', 'u_456', true);SELECT current_user, current_setting('app.tenant_id', true), current_setting('app.user_id', true);ਜਦੋਂ ਤੁਸੀਂ ਅਣਜਾਣ ਹੋ ਕਿ ਕਿਹੜੀ ਨੀਤੀ ਲਾਗੂ ਹੋ ਰਹੀ ਹੈ, ਅਨੁਮਾਨ ਲਗਾਉਣ ਦੀ ਥਾਂ ਕੈਟਲੌਗ ਨੂੰ ਚੈੱਕ ਕਰੋ। pg_policies ਹਰ ਨੀਤੀ ਦਿਖਾਉਂਦਾ ਹੈ, ਕਮਾਂਡ, ਅਤੇ USING ਅਤੇ WITH CHECK ਐਕਸਪ੍ਰੈਸ਼ਨ। ਇਸਨੂੰ pg_class ਨਾਲ ਜੋੜੋ ਤਾਂ ਕਿ ਇਹ ਗੱਲ ਵੀ ਪੱਕੀ ਕੀਤਾ ਜਾਵੇ ਕਿ ਟੇਬਲ 'ਤੇ RLS ਯੋਗ ਹੈ ਅਤੇ ਇਹ ਬਾਈਪਾਸ ਨਹੀਂ ਹੋ ਰਿਹਾ।
ਪਰਫਾਰਮੈਂਸ ਮੁੱਦੇ ਵੀ ਆਥਰਾਈਜ਼ੇਸ਼ਨ ਮੁੱਦਿਆਂ ਵਰਗੇ ਲੱਗ ਸਕਦੇ ਹਨ। ਇੱਕ ਨੀਤੀ ਜੋ ਮੈਂਬਰਸ਼ਿਪ ਟੇਬਲ ਨਾਲ ਜੋਇਨ ਕਰਦੀ ਹੈ ਜਾਂ ਕਿਸੇ ਫੰਕਸ਼ਨ ਨੂੰ ਕਾਲ ਕਰਦੀ ਹੈ, ਸਹੀ ਹੋ ਸਕਦੀ ਹੈ ਪਰ ਟੇਬਲ ਵੱਡੀ ਹੋਣ 'ਤੇ ਧੀਮੀ ਹੋ ਸਕਦੀ ਹੈ। ਦੁਹਰਾਉਂਦੇ ਕੂਐਰੀ 'ਤੇ EXPLAIN (ANALYZE, BUFFERS) ਵਰਤੋ ਅਤੇ ਸੋਚੋ ਕਿ ਕੀ ਸਿਕਵੈਂਸ਼ਅਲ ਸਕੈਨ, ਅਣਉਮੀਦNested loops, ਜਾਂ ਫਿਲਟਰ ਦੇਰ ਨਾਲ ਲਾਗੂ ਹੋ ਰਹੇ ਹਨ। (tenant_id, user_id) ਅਤੇ ਮੈਂਬਰਸ਼ਿਪ ਟੇਬਲਾਂ 'ਤੇ ਮਿਲਦੇ ਇੰਡੈਕਸ ਆਮ ਮੁੱਦੇ ਹੁੰਦੇ ਹਨ।
ਇਹ ਵੀ ਮਦਦ ਕਰਦਾ ਹੈ ਕਿ ਹਰ ਰਿਕਵੇਸਟ 'ਤੇ ਐਪ ਲੇਅਰ ਤਿੰਨ ਮੁੱਲ ਲੌਗ ਕਰੇ: tenant ID, user ID, ਅਤੇ ਡੇਟਾਬੇਸ ਰੋਲ। ਜਦੋਂ ਉਹ ਉਹਨਾਂ ਨਾਲ ਮੇਲ ਨਹੀਂ ਖਾਂਦੇ ਜੋ ਤੁਸੀਂ ਸੋਚਦੇ ਹੋ ਕਿ ਤੁਸੀਂ ਸੈਟ ਕੀਤੇ, RLS “ਗਲਤ” ਵਿਹਾਰ ਦਿਖਾਵੇਗੀ ਕਿਉਂਕਿ ਇਨਪੁਟ ਗਲਤ ਹਨ।
ਟੈਸਟਾਂ ਲਈ, ਕੁਝ ਸੀਡ ਟੇਨੈਂਟ ਰੱਖੋ ਅਤੇ ਫੇਲਿਯਰਾਂ ਨੂੰ ਖ਼ਾਸ ਬਣਾਓ। ਇੱਕ ਛੋਟੀ ਸਿ੍ਯੂਟ ਆਮਤੌਰ 'ਤੇ ਸ਼ਾਮਿਲ ਕਰਦੀ ਹੈ: “ਟੇਨੈਂਟ A ਪਰਿਵਾਰ ਟੇਨੈਂਟ B ਨੂੰ ਨਹੀਂ ਪੜ੍ਹ ਸਕਦਾ”, “ਮੈਂਬਰਸ਼ਿਪ ਬਿਨਾਂ ਯੂਜ਼ਰ ਪ੍ਰੋਜੈਕਟ ਨਹੀਂ ਵੇਖ ਸਕਦਾ”, “ਮਾਲਕ update ਕਰ ਸਕਦਾ ਹੈ, viewer ਨਹੀਂ”, “INSERT ਉਸ ਸਮੇਂ ਬਲਾਕ ਹੋ ਜਾਂਦਾ ਹੈ ਜਦੋ tenant_id ਪ੍ਰਸੰਗ ਨਾਲ ਮੇਲ ਨਹੀਂ ਖਾਂਦਾ”, ਅਤੇ “ਐਡਮਿਨ ਓਵਰਰਾਈਡ ਕੇਵਲ ਉਤੇ ਕੀਤਾ ਗਿਆ ਹੈ ਜਿੱਥੇ ਮਨਜ਼ੂਰ ਹੈ”।
RLS ਨੂੰ ਫੀਚਰ ਟੋੱਗਲ ਨਹੀਂ ਸਮਝੋ—ਇਹ ਸੀਟਬੈਲਟ ਦੀ ਤਰ੍ਹਾਂ ਹੈ। ਛੋਟੀਆਂ ਗਲਤੀਆਂ “ਹਰ ਕਿਸੇ ਦਾ ਡੇਟਾ ਵੇਖ ਸਕਦੇ ਹਨ” ਜਾਂ “ਸਭ ਕੁਝ ਜ਼ੀਰੋ ਰੋਜ਼ ਵਾਪਸ ਕਰਦਾ ਹੈ” ਹੋ ਸਕਦੀਆਂ ਹਨ।
ਯਕੀਨੀ ਬਣਾਓ ਕਿ ਤੁਹਾਡਾ ਟੇਬਲ ਡਿਜ਼ਾਈਨ ਅਤੇ ਨੀਤੀ ਨਿਯਮ ਤੁਹਾਡੇ ਟੇਨੈਂਟ ਮਾਡਲ ਨਾਲ ਮਿਲਦੇ ਹਨ।
tenant_id) ਹੋਣੀ ਚਾਹੀਦੀ ਹੈ। ਜੇ ਇਹ ਨਹੀਂ, ਤਾਂ ਲਿਖੋ ਕਿ ਕਿਉਂ (ਉਦਾਹਰਨ: ਗਲੋਬਲ ਰੈਫਰੈਂਸ ਟੇਬਲ)।FORCE ROW LEVEL SECURITY ਬਾਰੇ ਸੋਚੋ।USING ਵਰਤਦਾ ਹੈ। ਲਿਖਣ ਲਈ WITH CHECK ਲਾਜ਼ਮੀ ਹੈ ਤਾਂ ਕਿ inserts ਅਤੇ updates ਹੋਰ ਟੇਨੈਂਟ ਵਿੱਚ ਰੋ ਨਾ ਭੇਜ ਸਕਣ।tenant_id ਤੇ ਫਿਲਟਰ ਕਰਦੀਆਂ ਹਨ ਜਾਂ ਮੈਂਬਰਸ਼ਿਪ टੇਬਲਾਂ ਰਾਹੀਂ ਜੋਇਨ ਕਰਦੀਆਂ ਹਨ, ਤਾਂ ਮਿਲਦੇ ਇੰਡੈਕਸ ਜੋੜੋ।ਇੱਕ ਸਧਾਰਨ ਸੈਨੀਟੀ ਸੀਨਾਰਿਓ: ਟੇਨੈਂਟ A ਦਾ ਯੂਜ਼ਰ ਆਪਣੀਆਂ invoices ਪੜ੍ਹ ਸਕਦਾ ਹੈ, ਸਿਰਫ਼ tenant A ਲਈ invoice insert ਕਰ ਸਕਦਾ ਹੈ, ਅਤੇ invoice ਦਾ tenant_id ਬਦਲ ਕੇ ਨਹੀਂ ਰੱਖ ਸਕਦਾ।
RLS ਉਨ੍ਹਾਂ ਰੋਲਾਂ ਉੱਤੇ ਹੀ ਮਜ਼ਬੂਤ ਹੁੰਦੀ ਹੈ ਜਿਨ੍ਹਾਂ ਦੀ ਤੁਸੀਂ ਵਰਤੋਂ ਕਰਦੇ ਹੋ।
ਕਲਪਨਾ ਕਰੋ ਇੱਕ B2B ਐਪ ਦੀ ਜਿੱਥੇ ਕੰਪਨੀਆਂ (orgs) ਦੇ ਪ੍ਰੋਜੈਕਟ ਹਨ, ਅਤੇ ਪ੍ਰੋਜੈਕਟਸ ਵਿੱਚ ਟਾਸਕ ਹਨ। ਯੂਜ਼ਰ ਕਈ orgs ਦਾ ਮੈਂਬਰ ਹੋ ਸਕਦੇ ਹਨ, ਅਤੇ ਇੱਕ ਯੂਜ਼ਰ ਕੁਝ ਪ੍ਰੋਜੈਕਟਾਂ ਦਾ ਮੈਂਬਰ ਹੋ ਸਕਦਾ ਹੈ ਪਰ ਹੋਰ ਨਹੀਂ। ਇਹ RLS ਲਈ ਇੱਕ ਵਧੀਆ ਫਿੱਟ ਹੈ ਕਿਉਂਕਿ ਡੇਟਾਬੇਸ ਟੇਨੈਂਟ ਆਇਸੋਲੇਸ਼ਨ ਨੂੰ ਲਾਗੂ ਕਰ ਸਕਦਾ ਹੈ ਚਾਹੇ ਕੋਈ API ਐਂਡਪੋਇੰਟ ਫਿਲਟਰ ਭੁੱਲ ਜਾਵੇ।
ਇੱਕ ਸਧਾਰਨ ਮਾਡਲ: orgs, users, org_memberships (org_id, user_id, role), projects (id, org_id), project_memberships (project_id, user_id), tasks (id, project_id, org_id, ...). tasks 'ਤੇ ਵੱਲਾ org_id ਇਰਾਦਾ ਨਾਲ ਹੈ। ਇਹ ਨੀਤੀਆਂ ਸਧਾਰਨ ਰੱਖਦਾ ਹੈ ਅਤੇ ਜੋਇਨਾਂ ਦੇ ਸਮੇਂ ਆਸ਼ਚਰਜ ਘਟਾਂਦਾ ਹੈ।
ਇੱਕ ਕਲਾਸਿਕ ਲੀਕ ਉਸ ਵੇਲੇ ਹੁੰਦੀ ਹੈ ਜਦ tasks ਵਿੱਚ ਸਿਰਫ਼ project_id ਹੁੰਦਾ ਹੈ, ਅਤੇ ਤੁਸੀਂ ਸ਼ੁਧਤਾ ਮਿਲਾਉਣ ਲਈ ਪ੍ਰੋਜੈਕਟਸ ਰਾਹੀਂ ਐਕਸੈਸ ਚੈੱਕ ਕਰਦੇ ਹੋ। ਇਕ ਛੋਟੀ ਗਲਤੀ (projects 'ਤੇ permissive ਨੀਤੀ, ਜੋਇਨ ਜਿਹੜੀ ਸ਼ਰਤ ਘਟਾ ਦਿੰਦੀ, ਜਾਂ ਕੋਈ view ਜੋ context ਬਦਲ ਦਿੰਦਾ) tasks ਨੂੰ ਹੋਰ org ਤੋਂ ਦਰਸਾ ਸਕਦਾ ਹੈ।
ਇੱਕ ਸੁਰੱਖਿਅਤ ਮਾਈਗ੍ਰੇਸ਼ਨ ਰਸਤਾ production ਟ੍ਰੈਫਿਕ ਨੂੰ ਤੋੜੇ ਬਿਨਾਂ ਕੰਮ ਕਰਦਾ ਹੈ:
org_id ਜੋੜੋ, ਮੈਂਬਰਸ਼ਿਪ ਟੇਬਲਾਂ ਜੋੜੋ)।tasks.org_id ਨੂੰ projects.org_id ਤੋਂ backfill ਕਰੋ, ਫਿਰ NOT NULL ਜੋੜੋ।ਸਪੋਰਟ ਪਹੁੰਚ ਆਮ ਤੌਰ 'ਤੇ ਇੱਕ ਸਾਫ਼ ਤੰਗ break-glass ਰੋਲ ਨਾਲ ਸਭ ਤੋਂ ਵਧੀਆ ਹਲ ਹੁੰਦੀ ਹੈ, ਨਾ ਕਿ RLS ਨੂੰ ਨਿਭਾਉਣਾ। ਇਸਨੂੰ ਆਮ ਸਹਾਇਤਾ ਖਾਤਿਆਂ ਤੋਂ ਅਲੱਗ ਰੱਖੋ ਅਤੇ ਜਦ ਵੀ ਇਸਨੂੰ ਵਰਤਿਆ ਜਾਵੇ ਸਪਸ਼ਟ ਦਸਤਾਵੇਜ਼ ਬਣਾਓ।
ਨੀਤੀਆਂ ਦਸਤਾਵੇਜ਼ ਕਰੋ ਤਾਂ ਕਿ ਨੀਤੀਆਂ ਨਹੀਂ ਭਟਕਣ: ਕਿਹੜੀਆਂ ਸੈਸ਼ਨ ਵੈਰੀਅਬਲਾਂ ਦੀ ਲੋੜ ਹੈ (user_id, org_id), ਕਿਹੜੀਆਂ ਟੇਬਲਾਂ 'ਤੇ org_id ਹੋਣਾ ਲਾਜ਼ਮੀ ਹੈ, “ਮਾਂਬਰ” ਦਾ ਮਤਲਬ ਕੀ ਹੈ, ਅਤੇ ਕੁਝ SQL ਉਦਾਹਰਨ ਜੋ ਗਲਤ org ਨਾਲ ਚਲਾਉਂਦਿਆਂ 0 ਰੋਜ਼ ਫੇਰਦੇ ਹਨ।
RLS ਨਾਲ ਜੀਊਣਾ ਉਹ ਵੇਲੇ ਸੌਖਾ ਹੁੰਦਾ ਹੈ ਜਦ ਤੁਸੀਂ ਇਸਨੂੰ ਇੱਕ ਪ੍ਰੋਡਕਟ ਬਦਲ ਦੇ ਤੌਰ 'ਤੇ ਟ੍ਰੀਟ ਕਰੋ। ਇਸਨੂੰ ਛੋਟੇ ਹਿੱਸਿਆਂ ਵਿੱਚ ਰੋਲਆਊਟ ਕਰੋ, ਟੈਸਟ ਨਾਲ ਵਿਹਾਰ ਸਾਬਤ ਕਰੋ, ਅਤੇ ਹਰ ਨੀਤੀ ਦੀ ਇੱਕ ਸਪਸ਼ਟ ਰਿਕਾਰਡ ਰੱਖੋ ਕਿ ਹਰ ਨੀਤੀ ਕਿਉਂ ਮੌਜੂਦ ਹੈ।
ਜੋ ਰੋਲਆਊਟ ਪਲਾਨ ਆਮਤੌਰ 'ਤੇ ਕੰਮ ਕਰਦਾ ਹੈ:
projects) ਨਾਲ ਸ਼ੁਰੂ ਕਰੋ ਜੋ ਸਪਸ਼ਟ ਟੇਨੈਂਟ ਮਾਲਕੀ ਰੱਖਦੀ ਹੋਵੇ ਅਤੇ ਉਸਨੂੰ ਲਾਕ ਡਾਊਨ ਕਰੋ।ਪਹਿਲਾ ਟੇਬਲ ਸਥਿਰ ਹੋਣ ਤੋਂ ਬਾਅਦ, ਨੀਤੀ ਬਦਲਾਅ ਧਿਆਨਪੂਰਵਕ ਕਰੋ। ਮਾਈਗ੍ਰੇਸ਼ਨਾਂ 'ਚ ਨੀਤੀ ਸਮੀਖਿਆ ਕਦਮ ਜੋੜੋ, ਅਤੇ ਮਨਜ਼ੂਰ ਕਰਨ ਵਾਲਾ ਇੱਕ ਛੋਟਾ ਨੋਟ ਮਿਲਾਓ (ਕੌਣ ਕੀ ਦੇਖ ਸਕਦਾ ਹੈ ਅਤੇ ਕਿਉਂ) ਨਾਲ ਇੱਕ ਮੈਚਿੰਗ ਟੈਸਟ ਅਪਡੇਟ ਸ਼ਾਮਿਲ ਕਰੋ। ਇਹ “ਹੋਰ OR ਜੋੜੋ” ਵਾਲੀਆਂ ਨੀਤੀਆਂ ਤੋਂ ਬਚਾਉਂਦਾ ਹੈ ਜੋ ਹੌਲੀ-ਹੌਲੀ ਸੂਰਜਦਿਨੀ ਰਾਹ ਬਣ ਜਾਂਦੀਆਂ ਹਨ।
ਜੇ ਤੁਸੀਂ ਤੇਜ਼ੀ ਨਾਲ ਅੱਗੇ ਵੱਧ ਰਹੇ ਹੋ, ਤਾਂ Koder.ai ਵਰਗੇ ਟੂਲ (koder.ai) ਤੁਹਾਨੂੰ Go + PostgreSQL ਸ਼ੁਰੂਆਤੀ ਬਿੰਦੂ ਚੈਟ ਰਾਹੀਂ ਦੇ ਸਕਦੇ ਹਨ, ਅਤੇ ਫਿਰ ਤੁਸੀਂ ਉਹਨਾਂ 'ਤੇ ਨੀਤੀਆਂ ਅਤੇ ਟੈਸਟ ਉਸੇ ਅਨੁਸ਼ਾਸਨ ਨਾਲ ਲਗਾ ਸਕਦੇ ਹੋ ਜੋ ਹੱਥ-ਬਣੇ ਬੈਕਐਂਡ ਲਈ ਵਰਤੀ ਜਾਂਦੀ ਹੈ।
ਆਖ਼ਰੀ ਗੱਲ, ਰੋਲਆਊਟ ਦੌਰਾਨ ਸੁਰੱਖਿਆ ਰੇਲ ਰੱਖੋ। ਨੀਤੀ ਮਾਈਗ੍ਰੇਸ਼ਨਾਂ ਤੋਂ ਪਹਿਲਾਂ snapshots ਲਓ, ਰੋਲਬੈਕ ਅਭਿਆਸ ਕਰੋ ਤਾਂ ਕਿ ਇਹ ਬੋਰੀੰਗ ਤੱਕ ਆ ਜਾਵੇ, ਅਤੇ ਇੱਕ ਛੋਟਾ break-glass ਰਾਹ ਰੱਖੋ ਜੋ ਸਿਸਟਮ-ਵਿਆਪਕ RLS ਨੂੰ ਬੰਦ ਨਾ ਕਰੇ।
RLS PostgreSQL ਨੂੰ ਇਹ ਨਿਰਦੇਸ਼ ਦਿੰਦਾ ਹੈ ਕਿ ਕਿਸ ਰਿਕਵੇਸਟ ਲਈ ਕਿਹੜੀਆਂ ਰੋਜ਼ ਦਿਖਾਈ ਜਾਂਦੀਆਂ ਜਾਂ ਲਿਖੀਆਂ ਜਾ ਸਕਦੀਆਂ ਹਨ, ਇਸ ਲਈ ਟੇਨੈਂਟ ਆइसੋਲੇਸ਼ਨ ਉੱਤੇ ਭਰੋਸਾ 'WHERE tenant_id = ...' ਵਾਲੀ ਹਰ ਏਂਡਪੋਇੰਟ ਦੀ ਯਾਦ ਤੇ ਨਾ ਰਹੇ। ਵੱਡਾ ਫ਼ਾਇਦਾ ਇਹ ਹੈ ਕਿ ਜਦੋਂ ਤੁਹਾਡੀ ਐਪ ਵਧਦੀ ਹੈ ਅਤੇ ਕਸਟਮ ਕੂਐਰੀਆਂ ਵੱਧਦੀਆਂ ਹਨ ਤਾਂ “ਇੱਕ ਛੁੱਟੀ ਚੈਕ” ਦੀ ਗਲਤੀ ਘੱਟ ਹੁੰਦੀ ਹੈ।
ਜਦੋਂ ਐਕਸੈਸ ਨਿਯਮ ਸਧਾਰਨ ਤੇ ਰੋ-ਅਧਾਰਿਤ ਹੁੰਦੇ ਹਨ—ਜਿਵੇਂ ਟੇਨੈਂਟ ਆਇਸੋਲੇਸ਼ਨ ਜਾਂ ਮੈਂਬਰਸ਼ਿਪ-ਅਧਾਰਿਤ ਪਹੁੰਚ—ਅਤੇ ਤੁਹਾਡੇ ਕੋਲ ਕਈ ਫ਼ਰਕ ਕੂਐਰੀ ਰਸਤੇ ਹਨ (ਖੋਜ, ਐਕਸਪੋਰਟ, ਐਡਮਿਨ ਸਕ੍ਰੀਨ, ਬੈਕਗ੍ਰਾਊਂਡ ਜੌਬ), ਤਾਂ RLS ਫਾਇਦੇਮੰਦ ਹੁੰਦਾ ਹੈ। ਜੇ ज़ਿਆਦਾ ਨਿਯਮ ਫੀਲਡ-ਆਧਾਰਿਤ ਜਾਂ ਬਹੁਤ ਸਾਰੀਆਂ ਛੂਟਾਂ ਵਾਲੇ ਹਨ ਜਾਂ ਵੱਡੇ ਰਿਪੋਰਟਿੰਗ ਲਈ ਕਾਫ਼ੀ ਵਿਆਪਕ ਪੜਚੋਲ ਚਾਹੀਦੀ ਹੈ, ਤਾਂ RLS ਘੱਟ ਉਚਿਤ ਹੋ ਸਕਦਾ ਹੈ।
RLS ਰੋ ਦਿਖਾਈ ਅਤੇ ਮੁੱਖ ਲਿਖਾਈ ਰੋਕਥਾਮ ਲਈ ਵਰਤੋਂਯੋਗ ਹੈ; ਪਰ:
ਇਹਨਾਂ ਲਈ ਹੋਰ ਟੂਲ ਅਤੇ ਧਾਰਣਾਵਾਂ ਵਰਤੋ।
ਇੱਕ ਨੀਵ-ਅਧਿਕਾਰ ਰੋਲ (ਟੇਬਲ ਮਾਲਕ ਨਾ ਹੋਵੇ) ਬਣਾਓ, RLS ਚਾਲੂ ਕਰੋ, ਫਿਰ SELECT ਨੀਤੀ ਅਤੇ INSERT/UPDATE ਲਈ WITH CHECK ਵਾਲੀ ਨੀਤੀ ਜੋੜੋ। ਹਰ ਰਿਕਵੇਸਟ ਲਈ ਇਕ ਸੈਸ਼ਨ ਵੈਰੀਅਬਲ (ਜਿਵੇਂ app.current_tenant) ਸੈਟ ਕਰੋ ਅਤੇ ਜਾਂਚੋ ਕਿ ਉਸਨੂੰ ਬਦਲਣ ਨਾਲ ਦਿਖਾਈ ਜਾਂ ਲਿਖਾਈ ਹੋਣ ਵਾਲੀਆਂ ਰੋਜ਼ ਬਦਲ ਰਹੀਆਂ ਹਨ।
ਅਕਸਰ ਇੱਕ ਰਿਕਵੇਸਟ-ਸਕੋਪਡ ਸੈਸ਼ਨ ਵੈਰੀਅਬਲ ਹੀ ਸਹੀ ਚੋਣ ਹੁੰਦੀ ਹੈ, ਜੋ ਟ੍ਰਾਂਜ਼ੈਕਸ਼ਨ ਦੀ ਸ਼ੁਰੂਆਤ 'ਤੇ ਸੈਟ ਕੀਤੀ ਜਾਵੇ—ਜਿਵੇਂ app.tenant_id ਅਤੇ app.user_id। ਕੁੰਜੀ ਗੱਲ ਹੈ ਲਗਾਤਾਰਤਾ: ਹਰ ਕੋਡ ਪੱਥ (ਵੈੱਬ ਰਿਕਵੇਸਟ, ਜੌਬ, ਸਕ੍ਰਿਪਟ) ਨੂੰ ਉਹੀ ਕਾਨੂੰਨੀ ਸੈਟਿੰਗ ਸੈਟ करनी ਚਾਹੀਦੀ ਹੈ ਜਿੰਨ੍ਹਾਂ ਦੀਆਂ ਨੀਤੀਆਂ ਉਮੀਦ ਕਰਦੀਆਂ ਹਨ, ਨਹੀਂ ਤਾਂ ਅਜਿਹੀਆਂ “ਸਿਰਫ਼ ਜ਼ੀਰੋ ਰੋਜ਼” ਦੀਆਂ ਗਲਤੀਆਂ ਮਿਲ ਸਕਦੀਆਂ ਹਨ।
USING ਇਸਕੂਿਰੀ ਫਿਲਟਰ ਹੈ: ਜੇ ਕੋਈ ਰੋ USING ਨਾਲ ਮੇਲ ਨਹੀਂ ਖਾਂਦੀ ਤਾਂ ਉਹ SELECT ਲਈ ਅਦଢ଼੍ਰਸ਼ਯ ਹੋ ਜਾਂਦੀ ਹੈ ਅਤੇ UPDATE/DELETE ਲਈ ਟਾਰਗੇਟ ਨਹੀਂ ਹੋ ਸਕਦੀ।
ਲਿਖਾਈ ਦਾ ਦਰਵਾਜ਼ਾ ਹੈ: ਇਹ ਫੈਸਲਾ ਕਰਦਾ ਹੈ ਕਿ ਨਵੀਆਂ ਜਾਂ ਬਦਲੀ ਹੋਈਆਂ ਪੰਕਤੀਆਂ / ਦੌਰਾਨ ਮਨਜ਼ੂਰ ਹਨ ਕਿ ਨਹੀਂ।
ਲੋਕ ਲੋਕ ਕਹਿੰਦੇ ਹਨ “WITH CHECK ਨਾ ਭੁੱਲੋ” ਕਿਉਂਕਿ ਜੇ ਤੁਸੀਂ ਸਿਰਫ਼ USING ਜੋੜਦੇ ਹੋ ਤਾਂ ਇੱਕ ਬੱਗੀ ਐਂਡਪੋਇੰਟ ਅਜੇ ਵੀ ਗਲਤ tenant_id ਦੇ ਨਾਲ ਪੰਗਤੀਆਂ INSERT ਜਾਂ UPDATE ਕਰ ਸਕਦਾ ਹੈ, ਅਤੇ ਇਹ ਪੰਗਤੀਆਂ ਲਿਖੀਆਂ ਤਾਂ ਹੋਣਗੀਆਂ ਪਰ ਉਸ ਵਰਤੋਂਕਾਰ ਵੱਲੋਂ ਪੜ੍ਹੀ ਨਹੀਂ ਜਾ ਸਕਦੀਆਂ—ਇਸ ਲਈ ਗਲਤੀ ਨਜ਼ਰ ਨਹੀਂ ਆਵੇਗੀ। ਇਸ ਲਈ ਪੜ੍ਹਨ ਵਾਲੀ ਨੀਤੀ ਨਾਲ ਮਿਲਦੀ-ਜੁਲਦੀ WITH CHECK ਲਿਖੋ ਤਾਂ ਕਿ ਗਲਤ ਡੇਟਾ ਬਣਨਾ ਹੀ ਰੁਕ ਜਾਵੇ।
ਨੀਤੀਆਂ ਅਤੇ ਡੇਟਾ ਮਾਡਲ ਨੂੰ ਸਧਾਰਨ ਰੱਖੋ:
tenant_id ਰੱਖੋ।org_memberships ਅਤੇ (ਆਵਸ਼ਕ ਹੋਵੇ ਤਾਂ) project_memberships ਵਰਗੇ ਟੇਬਲ ਰੱਖੋ, ਤਾਂ ਕਿ ਨੀਤੀਆਂ ਇੱਕ ਇੰਡੈਕਸ ਕੀਤੇ ਹੋਏ ਲੁਕਅਪ ਨਾਲ ਕੰਮ ਕਰ ਸਕਣ।ਇਹ ਚੀਜ਼ਾਂ ਨੀਤੀਆਂ ਨੂੰ ਸਧਾਰਨ ਅਤੇ ਤੇਜ਼ ਰੱਖਦੀਆਂ ਹਨ।
ਪਹਿਲਾਂ ਆਪਣੀ ਐਪ ਵਾਲੀ session ਸੈਟਿੰਗ ਨੂੰ ਮੁਹਿਆ ਕਰਕੇ ਉਹੀ ਸੈਸ਼ਨ ਪ੍ਰਸੰਗ ਰੀਪ੍ਰੋਡਿਊਸ ਕਰੋ: ਉਹੀ ਰੋਲ, ਉਹੀ ਸੈਸ਼ਨ ਸੈਟਿੰਗਾਂ, ਅਤੇ ਉਹੀ SQL ਕੂਐਰੀ ਚਲਾਓ। ਫਿਰ ਵੇਖੋ ਕਿ PostgreSQL ਕਿਹੜੀਆਂ ਸੈਟਿੰਗਾਂ ਵੇਖ ਰਿਹਾ ਹੈ:
SELECT current_user, current_setting('app.tenant_id', true), current_setting('app.user_id', true);
ਜਦੋਂ unsure ਹੋ, ਤਾਂ pg_policies ਦੇਖੋ ਕਿ ਕਿਹੜੀਆਂ ਨੀਤੀਆਂ ਲਾਗੂ ਹਨ। RLS ਅਕਸਰ “ਗਲਤ SQL” ਦੀ ਬਜਾਇ ਗਲਤ ਨਿਸ਼ਾਨਾਤਮਕ ਪ੍ਰਸੰਗ ਦੀ ਵਜ੍ਹਾ ਨਾਲ ਫੇਲ ਹੁੰਦੀ ਹੈ।
ਜੀਨੇਰੇਟਡ ਕੋਡ ਨੂੰ ਇੱਕ ਅਰੰਭ ਬਿੰਦੂ ਸਮਝੋ, ਸੁਰੱਖਿਆ ਪ੍ਰਣਾਲੀ ਨਹੀਂ। ਜੇ ਤੁਸੀਂ Koder.ai ਨਾਲ Go + PostgreSQL ਬੈਕਐਂਡ ਪੈਦਾ ਕਰਦੇ ਹੋ, ਤਾਂ ਵੀ ਆਪਣਾ ਟੇਨੈਂਟ ਮਾਡਲ ਪਰਿਭਾਸ਼ਿਤ ਕਰੋ, ਸੈਸ਼ਨ ਆਈਡੈਂਟੀਟੀ ਲਗਾਤਾਰ ਸੈੱਟ ਕਰੋ, ਅਤੇ ਨੀਤੀਆਂ ਤੇ ਟੈਸਟ ਮਿਲਾ ਕੇ ਹੀ ਨਵੇਂ ਟੇਬਲ ਰਿਲੀਜ਼ ਕਰੋ ਤਾਂ ਜੋ ਉਹ ਗਲਤ ਡੀਫਾਲਟ ਨਾਲ ਨਾ ਆਉਣ।
WITH CHECKINSERTUPDATEਸੰਖੇਪ: USING ਪੜ੍ਹਨ/ਨਿਸ਼ਾਨਾ ਬਣਾਉਣ ਲਈ, WITH CHECK ਲਿਖਣ ਲਈ।