david 5 miesięcy temu
rodzic
commit
94e075ba51
4 zmienionych plików z 150 dodań i 3 usunięć
  1. 10 3
      README.md
  2. 96 0
      backend/src/init_db.ts
  3. 38 0
      backend/src/main.ts
  4. 6 0
      backend/src/user.ts

+ 10 - 3
README.md

@@ -1,4 +1,11 @@
-surreal_access_control_system
-===============
+# surreal_access_control_system
+
+This repository explores how to build a access control system on top of SurrealDB using TypeScript.
+We will build a nodejs backend command line application that uses the SurrealDB Javascript/Typescript SDK to connect to a local SurrealDB instance.
+We will authenticate with various users and display a list of 'product' entries from a test database.
+
+We will use ```DEFINE ACCESS``` statements to define roles based authentication. One of our test users should be able to fully access (create, read, update, delete)
+the 'product' entries the other one should not have access to the table and thus should not be able to retrieve a list of products.
+
+First we add the SDK to our project ```npm install --save surrealdb```.
 
-This repository explores how to build a access control system on top of SurrealDB using TypeScript.

+ 96 - 0
backend/src/init_db.ts

@@ -0,0 +1,96 @@
+import Surreal from 'surrealdb';
+import { argv } from 'process';
+
+const auth = {
+    username: 'root',
+    password: 'root',
+}
+
+const db_url = "http://localhost:8000";
+const db_name = { namespace: "ts_test", database: "access_test" };
+
+async function main() {
+    // Extract username and password from command-line arguments
+    const db = new Surreal();
+    try {
+        await db.connect(db_url, { auth });
+        await db.use(db_name);
+    } catch (err) {
+        console.error("Could not connect to SurrealDB server: ", err instanceof Error ? err.message : String(err));
+        throw (err);
+    }
+
+    try {
+        await db.query(`
+            define table if not exists user schemafull;
+        `);
+
+        await db.query(`
+            define field if not exists username on user type string;
+            define field if not exists password on user type string;
+            define field if not exists roles on user type set<string>;
+        `);
+
+        await db.query(`
+            define index if not exists idx_username on user fields username unique;
+        `);
+    } catch (err) {
+        console.error("Could not create table user or its fields: ", err instanceof Error ? err.message : String(err));
+        throw (err);
+    }
+
+    try {
+        await db.query(`
+            insert into user [
+                {
+                    username: "test1",
+                    password: crypto::argon2::generate("test"),
+                    roles: []
+                },
+                { 
+                    username: "test2",
+                    password: crypto::argon2::generate("test"),
+                    roles: ['product_manager']
+                }
+            ];
+        `)
+    } catch (err) {
+        console.error("Could not create user entries: ", err instanceof Error ? err.message : String(err));
+    }
+
+    try {
+        await db.query(`
+            define table if not exists product schemafull 
+                permissions for select where $auth.roles contains 'product_manager';
+            define field if not exists code on product type string;
+            define field if not exists available on product type bool;
+            define index if not exists idx_code on product fields code;
+        `);
+    } catch (err) {
+        console.error("Could not create table product: ", err instanceof Error ? err.message : String(err));
+        throw (err);
+    }
+
+    try {
+        await db.query(`
+            insert into product {
+                    code: "test_product1",
+                    available: true
+            };
+        `)
+    } catch (err) {
+        console.error("Could not create user entries: ", err instanceof Error ? err.message : String(err));
+    }
+
+    try {
+        await db.query(`
+            define access overwrite user on database type record
+	        signup (create user set username = $username, password = crypto::argon2::generate($password), roles=[])
+	        signin (select * from user where username = $username and crypto::argon2::compare(password, $password));
+            `)
+    } catch (err) {
+        console.error("Could not define access: ", err instanceof Error ? err.message : String(err));
+    }   
+}
+
+main();

+ 38 - 0
backend/src/main.ts

@@ -0,0 +1,38 @@
+import Surreal from 'surrealdb';
+import { argv } from 'process';
+import { User } from './user';
+
+async function main() {
+    // Extract username and password from command-line arguments
+    const username = argv[2];
+    const password = argv[3];
+
+    if (!username || !password) {
+        console.error('Usage: node main.ts <username> <password>');
+        process.exit(1);
+    }
+
+    const db = new Surreal();
+
+    // Connect to the local SurrealDB instance
+    try {
+        await db.connect("ws://localhost:8000");
+        await db.signin({
+            username: username,
+            password: password
+        });
+        await db.use({ namespace: 'ts_test', database: 'ts_test'});
+
+        const products = await db.select('product');
+
+        console.log('Products:');
+        products.forEach(product => {
+            console.log(JSON.stringify(product, null, 2));
+        });
+
+    } catch (err) {
+        console.error("Could not connect to db", err instanceof Error ? err.message : String(err));
+    }
+}
+
+main();

+ 6 - 0
backend/src/user.ts

@@ -0,0 +1,6 @@
+export type User = {  
+  id: string;
+  user_name: string;
+  password: string;
+  roles: Array<string>;
+}