Դուք երբևէ ստացել եք ձեր հարևանի փաթեթը ձեր մուտքի դռան մոտ: (Գուցե նույնիսկ պատահաբար բացե՞լ եք այն): Որպես հավելված մշակողներ, ձեր խնդիրն է ապահովել, որ ձեր հավելվածում պահվող զգայուն տվյալները պատահաբար չհանձնվեն այլ կողմին:
Հաճախորդների տվյալները ապահով պահելու համար մատչելի են բազմաթիվ տեխնիկա, և շատերը չափազանց բարդ են և դժվար իրագործելի: Իդեալում, կարելի է ապահովել հաճախորդների բոլոր տվյալները մեկ տվյալների բազայում՝ պահպանելով գործառույթի դիզայնը պարզ և անվտանգ:
Տողերի մակարդակի անվտանգությունը (RLS) տվյալների բազայի աղյուսակի ներսում տվյալների որոշակի տողերի մուտքն ապահովելու և վերահսկելու ունակություն է: Այն հզոր գործիք է, որը թույլ է տալիս պահպանել ձեր հաճախորդների բոլոր տվյալները մեկ տվյալների բազայում՝ առանց որևէ մտահոգության՝ կապված հաշվում տվյալների արտահոսքի հետ: Այնուամենայնիվ, RLS-ի ճիշտ իրականացումը կարող է բարդ գործընթաց լինել, որը ներառում է մուտքի մանրամասները ձեր տվյալների բազայի թույլտվությունների հետ համատեղելը: Neon Authorize-ը հեշտացնում է այս գործընթացը՝ ավտոմատ կերպով ինտեգրելով նույնականացումը ձեր OAuth մատակարարից ձեր PostgreSQL տվյալների բազայի հետ:
Neon Authorize-ն օգտագործում է ձեր գոյություն ունեցող նույնականացման շերտը՝ յուրաքանչյուր մուտք գործած օգտվողին նույնականացնելու համար և ձեր տվյալների բազայի բոլոր տվյալները կապում է նրանց մուտքի հավատարմագրերի հետ: Սա երաշխավորում է, որ տվյալների բազայում պահվող տվյալները կարող են մուտք գործել միայն մուտք գործած օգտվողների համար, և որ միայն մուտք գործած օգտվողները կարող են տեսնել իրենց տվյալները:
Այս ձեռնարկը ձեզ կսովորեցնի, թե ինչպես ստեղծել Remix հավելված՝ օգտագործելով Clerk-ը որպես նույնականացման շերտ: Clerk-ը օգտատերերի նույնականացման և կառավարման հանրաճանաչ գործիք է: Դուք կօգտագործեք Neon Postgres-ը որպես ձեր տվյալների շերտ և կօգտագործեք Neon Authorize-ը, որպեսզի ապահովի բոլոր տվյալները յուրաքանչյուր մուտք գործած հաճախորդի համար: Աղյուսակի յուրաքանչյուր տող կնշանակի userID, որը տրամադրվում է Clerk-ի կողմից: Միայն userID-ով վավերացվածները կարող են շփվել տողում գտնվող տվյալների հետ:
Մեր օրինակելի հավելվածը պարզ է. այն գրանցում է յուրաքանչյուր մուտք RLS տվյալների բազա՝ օգտագործելով userID-ը: Երբ էջը բեռնվի, կցուցադրվեն վավերացված օգտատիրոջ վերջին 10 մուտքերը, և այլ օգտվողի տվյալներ (պահված նույն PostgreSQL աղյուսակում) չեն հայտնվի։ Եկեք սկսենք:
Սկսեք ստեղծելով Remix հավելված և տեղադրելով կախվածություններ՝ օգտագործելով ստորև բերված կոդի հատվածը: Ավելի մանրամասն հրահանգների համար տես Remix-ի արագ մեկնարկի ուղեցույցը :
##make a directory and initialise your NPM project mkdir neon-authorize-remix-clerk-app cd neon-authorize-remix-clerk-app npm init -y ## install runtime dependecies for Remix npm i @remix-run/node @remix-run/react @remix-run/serve isbot@4 react react-dom @remix-run/router drizzle-orm npm install @neondatabase/serverless npm install @clerk/remix npm i -D @remix-run/dev vite
Քանի որ Remix-ն օգտագործում է Vite՝ Javascript-ի կառուցման գործիք, ստեղծեք vite.config.js
արմատային գրացուցակում.
import { vitePlugin as remix } from "@remix-run/dev"; import { defineConfig } from "vite"; export default defineConfig({ plugins: [remix()], });
Նախքան որևէ զարգացում կատարելը, մենք պետք է հաշիվներ ստեղծենք Clerk-ում և Neon-ում՝ նրանց ծառայություններից օգտվելու համար.
Մուտք գործեք Clerk վահանակ՝ նոր նախագիծ ստեղծելու համար:
Ձախ նավարկությունում ընտրեք API ստեղներ :
.env
ֆայլի մեջ:Ձախ նավարկությունում ընտրեք « JWT կաղապարներ. »
Մուտք գործեք Neon վահանակ և ստեղծեք նոր նախագիծ:
Ձախ նավիգացիոն ընտրացանկից ընտրեք Թույլտվություն :
Ստեղծեք նոր մատակարար և տեղադրեք Clerk JWKS URL-ը , որը նախկինում պատճենել եք Clerk-ից:
Օրինակը ստեղծելուց հետո սեղմեք «Սկսել»: Կողքի վահանակը կբացվի մի շարք քայլերով՝ ձեր Neon Authorize-ի ինտեգրումն ավարտելու համար:
Սկսելու կարգավորումը ձեզ տրամադրում է քայլեր՝ կարգավորելու հիմնական լիազորման նախագիծը Clerk-ի հետ:
1. Set up Neon Extension and Roles Privileges. Run these steps in the Dashboard. 2. Grant privileges to the roles in the neondb database.
Տրամադրված կոդը նախատեսված է todos հավելվածի համար: Todos հավելվածի համար Neon-ից տրամադրված կաթսայատան կոդը օգտագործելու փոխարեն մենք կստեղծենք login_history
աղյուսակ և դրա վրա կտեղադրենք RLS: Բացեք SQL Editor-ը Neon վահանակում և գործարկեք ստորև նշված կոդը: login_history
աղյուսակը կօգտագործվի յուրաքանչյուր օգտվողի համար մուտքի ժամանակները պահելու համար:
Նկատի ունեցեք, որ
login_history
ունի ընդամենը երեք սյունակ՝ id, user_id և login_at: Վերջին երկու սյունակները կցուցադրեն հավելվածի ամենավերջին մուտքերը:
CREATE TABLE login_history ( id bigint generated by default as identity primary key, user_id text not null default (auth.user_id()), login_at timestamp not null default now() ); -- 1st enable row level security for your table ALTER TABLE login_history ENABLE ROW LEVEL SECURITY; -- 2nd create policies for your table CREATE POLICY "Individuals can add login." ON login_history FOR INSERT TO authenticated WITH CHECK ((select auth.user_id()) = user_id); CREATE POLICY "Individuals can view their own logins. " ON login_history FOR SELECT TO authenticated USING ((select auth.user_id()) = user_id);
Ավելացրեք տրամադրված բնապահպանական փոփոխականները ձեր .env
Կարգավորման այս քայլերն ավարտվելուց հետո ձեր .env
պետք է ունենա չորս փոփոխական՝ երկուսը Clerk-ից և երկուսը Neon-ից:
CLERK_PUBLISHABLE_KEY=pk_test_.... CLERK_SECRET_KEY=sk_test_... # Database owner connection string DATABASE_URL='postgresql://neondb_owner:...' # Neon "authenticated" role connection string DATABASE_AUTHENTICATED_URL='postgresql://authenticated@ep-...
Հավելվածն այժմ պատրաստ է ստեղծման։ Ամբողջական կոդը հասանելի է GitHub- ում, սակայն այստեղ կարևորվում են ամենակարևոր հատկանիշները: Հավելվածի առանցքը app/routes/_index.tsx
ում է՝
export const loader: LoaderFunction = async (args) => { const { userId, getToken } = await getAuth(args); if (!userId) { return redirect("/sign-in"); } const authToken = await getToken(); console.log(userId); if (!authToken) { return null; } const DATABASE_AUTHENTICATED_URL= process.env.NEXT_PUBLIC_DATABASE_AUTHENTICATED_URL; try { const sql = neon(DATABASE_AUTHENTICATED_URL ?? '', { authToken, }); const loginResponse = await sql(`INSERT INTO login_history ("user_id") VALUES ($1) RETURNING *`,[userId]); // Retrieve last 10 logins const last10LoginsResponse = await sql(`SELECT * FROM login_history WHERE user_id = $1 ORDER BY login_at DESC LIMIT 10`, [userId]); console.log(`loginResponse: ${JSON.stringify(loginResponse)}`); return last10LoginsResponse as Array<LoginHistory>; } catch (error) { console.error(`Error inserting into login_history table: ${error.message}`); console.error(`Error details: ${JSON.stringify(error)}`); throw error; } }
LoaderFunction
ը _index.tsx
ֆայլում ավարտում է առաջադրանքները սերվերի վրա՝ նախքան հաճախորդի համար էջը մատուցելը: Այս հավելվածում բեռնիչը կատարում է հավելվածի ծանրաբեռնվածության մեծ մասը:
Ֆունկցիան նախ ստուգում է, արդյոք օգտատերը մուտք գործած չէ, և այնուհետև վերահղում է օգտատիրոջը /sign-in
էջ: Մուտքի էջը կարող է կազմաձևվել Clerk-ի վահանակում՝ ընդունելու մուտքի տարբեր տեսակներ, ինչպիսիք են Google-ը և էլփոստի մուտքերը.
Մուտքի էջ ստեղծելու համար անցեք Clerk վահանակ և ստեղծեք նախագծի համար մուտքի անհրաժեշտ մեթոդները:
Եթե օգտատերը մուտք է գործել, ֆունկցիան առբերում է userId
ը և authToken
Clerk-ից: Այս արժեքները կարևոր են՝ համոզվելու համար, որ օգտատերը մուտք է գործել, և այնուհետև կարող եք օգտագործել userId
ը՝ ձեր տվյալների բազայի յուրաքանչյուր տողը համալրելու համար:
RLS-ով ապահովված տվյալների բազայում փոփոխություններ կատարելու համար անհրաժեշտ է շրջակա միջավայրի փոփոխականներից հանել DATABASE_AUTHENTCATED_URL
ը:
RLS անվտանգության ներդրման հիմնական տրամաբանությունը գտնվում է LoaderFunction
ում: SQL Neon օրինակը սկզբնավորվում է շրջակա միջավայրի փոփոխականների և վավերացման նշանի միջոցով: loginResponse
ֆունկցիան կատարում է SQL զանգ և տեղադրում է user_id-ը (և ընթացիկ ժամանակը) PostgreSQL տվյալների բազայում, որից հետո last10LoginsResponse
ֆունկցիան հարցում է կատարում DB-ին ամենավերջին 10 մուտքերի համար:
Վերջապես, last10LoginsResponse
ը վերադարձվում է բեռնիչ ֆունկցիայից:
Index()
ֆունկցիան _index.tsx
ֆայլում ներկայացնում է էջի դասավորությունը, ինչպես ցույց է տրված ստորև բերված հատվածում.
export default function Index() { const logins = useLoaderData(); return ( <div> <h1>Signed in</h1> <p>You are signed in!</p> <p> <UserButton /></p> <div> <h1>Recent Logins</h1> {logins?.map((logins) => ( <li key={logins.id}> {logins.user_id} login at: {logins.login_at} </li> ))} </div> <p>< SignOutButton > Sign Out</ SignOutButton ></p> </div> ); }
Վերոնշյալ կոդը վերցնում է LoaderFunction
ի պատասխանը, որը պարունակում է մուտքի վերջին 10 գրառումները: Այս պատասխանը ստեղծում է էջ, որն ասում է օգտվողին, որ նա մուտք է գործել, ցուցակագրում է վերջին 10 մուտքերը և ցույց է տալիս Դուրս գալու կոճակը, ինչպես ցույց է տրված ստորև.
Այս օրինակում user_id
ը նույնպես ցուցադրվում է՝ հստակ ցույց տալու համար, որ տեսանելի են միայն մուտք գործած օգտվողի մուտքի տվյալները:
Օգտագործելով ինկոգնիտո պատուհան, դուք կարող եք մուտք գործել երկրորդ Google հաշիվ և դիտել կողք կողքի տվյալները տարբեր օգտվողների համար.
Նկատի ունեցեք, որ մուտքի ժամանակները համընկնում են, բայց տվյալների բազայում օգտագործելով Row-Level Security, դուք կկանխեք տվյալների արտահոսքը հաշիվներից: Տողերը կարող են արդյունահանվել և ցուցադրվել միայն վավերացված օգտվողի համար:
Տվյալների գաղտնի պահելը օգտագործման կարևորագույն դեպք է: Քանի որ հավելվածները հաճախ պահում են անձնական տեղեկատվություն, այն պետք է ապահովված լինի՝ տվյալները ճիշտ ձեռքերում պահելու համար: Սպառողներն ունեն ավելի ու ավելի շատ իրավական պաշտպանություն, ինչպիսին է GDPR-ը, և Neon Authorize-ի նման գործիքները հեշտացնում են Row Level Security-ի ներդրումը` ձեր հաճախորդի տվյալները պաշտպանելու համար:
Այս գրառման մեջ մենք անցել ենք այն քայլերը, որոնք անհրաժեշտ են նեոնային տվյալների բազայում շարքի մակարդակի անվտանգությունը միացնելու համար: Մեր հաճախորդի տվյալների հետ RLS-ի օգտագործումը երաշխավորում է, որ միայն մուտք գործած օգտվողն ունի իր սեփական տվյալները հանելու հավատարմագրերը:
Այսօր Neon-ի միջոցով ձեր հավելվածին ավելացրեք Row Layer Security :