メインコンテンツまでスキップ

Data Access の保護

Squid が提供するさまざまな decorator を使用して、built-in internal database を含む、Squid に接続された任意の database を保護します。​

各 decorator は database の異なる部分を保護するよう設計されています。security function は boolean を返します。true は request を許可し、false は拒否します。

特定 type の action を保護するには、異なる context object が function に渡されます。たとえば、read operation を保護する場合、context object は QueryContext type になります。一方、write operation では MutationContext object が使用されます。

適切な decorator を使用して、次の type の data access を保護できます。

  • read
  • insert
  • update
  • delete
  • write
  • all

write decorator には insert、update、delete operation が含まれるため、database のすべての type の write operation を包括的に保護できます。

@secureDatabase​

Squid が提供する @secureDatabase decorator は、access する table や collection に関係なく、すべての database access を保護するために使用できます。この decorator は、database に access するすべての action で authorization check を適用します。

たとえば、developer は @secureDatabase decorator を使用して、authenticated user のみが database に access できるようにできます。そのためには、user が authenticated かを check する function を定義します。

Backend code
import { secureDatabase, SquidService } from '@squidcloud/backend';

export class ExampleService extends SquidService {
@secureDatabase('all', 'usersDatabase')
verifyUserAuthenticated(): boolean {
return this.isAuthenticated();
}
}

admin property を持つ user のみが usersDatabase を変更できるようにするには、developer は @secureDatabase decorator と、user が authenticated されており admin property を持つか check する verifyUserAuthenticated function を組み合わせて使用できます。

Backend code
import { secureDatabase, SquidService, MutationContext } from '@squidcloud/backend';

export class ExampleService extends SquidService {
@secureDatabase('write', 'usersDatabase')
verifyUserAuthenticated(context: MutationContext): boolean {
const userAuth = this.getUserAuth();
if (!userAuth) return false;
return !!userAuth.attributes['admin'];
}
}

scenario によっては、client が authorized かを判断するため action の context に access する必要があります。たとえば、次の function は user が authenticated されているか、また実行しようとする write が update ではなく insert かを check します。

Backend code
import { secureDatabase, SquidService, MutationContext } from '@squidcloud/backend';

export class ExampleService extends SquidService {
@secureDatabase('write', 'usersDatabase')
allowOnlyInsertsAndAuthenticated(context: MutationContext): boolean {
return this.isAuthenticated() && context.getMutationType() === 'insert';
}
}

@secureCollection​

developer は @secureCollection decorator を使用して、database 内の特定 collection を保護できます。これにより、authorized user のみが特定 collection 内の data に access・変更できるようになります。

たとえば、developer は @secureCollection decorator を使用して、user が owner column に自身の userId を持つ document のみを read できるようにできます。以下は code snippet の例です。

Backend code
import { secureCollection, SquidService, QueryContext } from '@squidcloud/backend';

export class ExampleService extends SquidService {
@secureCollection('Items', 'read')
secureItemsRead(context: QueryContext<Item>): boolean {
const userId = this.getUserAuth()?.userId;
if (!userId) return false;
return context.isSubqueryOf('owner', '==', userId);
}
}

user が所有する Item のみを update、delete、insert できるようにすることもできます。

Backend code
import { secureCollection, SquidService, MutationContext } from '@squidcloud/backend';

export class ExampleService extends SquidService {
@secureCollection('Items', 'write')
secureItemWrite(context: MutationContext<Item>): boolean {
const userId = this.getUserAuth()?.userId;
if (!userId) return false;
const { before, after } = context.beforeAndAfterDocs;
if (before && before.owner !== userId) return false;
if (after && after.owner !== userId) return false;
return true;
}
}

@publicCollection​

default では、collection の read は @secureCollection または @secureDatabase rule により許可されるまで拒否されます。unauthenticated client を含む誰もが安全に read できる data を collection が保持する場合は、@publicCollection decorator を使用して read が意図的に public であることを宣言します。public read は security rule evaluation を完全に bypass します。Squid は backend を呼び出さずにこれらを処理するため、read rule は実行されません。誰に対しても公開して安全な data にのみ使用してください。

この page の他の decorator とは異なり、@publicCollection は method ではなく class に適用します。public にできるのは read のみです。write は常に security rule を通過するため、public-read collection でも @secureCollection で insert、update、delete、write を制限できます。

Backend code
import { publicCollection, secureCollection, SquidService, MutationContext } from '@squidcloud/backend';

// Anyone can read the 'articles' collection, but only authenticated users can write to it.
@publicCollection('articles', 'read')
export class ArticleService extends SquidService {
@secureCollection('articles', 'write')
secureArticlesWrite(context: MutationContext): boolean {
return this.isAuthenticated();
}
}

decorator は collection name、action type(read のみサポート)、collection を保持する connector の optional ID を受け取ります。connector ID を省略した場合、built-in database が default になります。

Backend code
// Public read on a collection in a specific connector.
@publicCollection('articles', 'read', 'YOUR_CONNECTOR_ID')
export class ArticleService extends SquidService {}

conflict がある場合は secure rule が優先されます。同じ collection に @secureCollection または @secureDatabase の read(または all)rule も適用される場合、その rule が runtime で優先され、public declaration は無視されます。

Native Query の保護​

native queryを保護するには、database の connector ID を渡して @secureNativeQuery() decorator を使用します。次の例では、user が authenticated かを check する function を定義します。

Backend code
import { secureNativeQuery, SquidService } from '@squidcloud/backend';

export class ExampleService extends SquidService {
@secureNativeQuery('YOUR_CONNECTOR_ID')
verifyUserAuthenticated(): boolean {
return this.isAuthenticated();
}
}

次の例のように、auth token attribute を使用して、より fine-grained な access を追加できます。

Backend code
import { secureNativeQuery, SquidService } from '@squidcloud/backend';

export class ExampleService extends SquidService {
@secureNativeQuery('YOUR_CONNECTOR_ID')
verifyAdminUser(): boolean {
// Get the authenticated user's details
const userAuth = this.getUserAuth();
if (!userAuth) {
return false;
}

// Check for the admin attribute
return !!userAuth.attributes['admin'];
}
}

collection を使用して auth permission を保存することもできます。collection は Security Service function で保護してください。

Backend code
import { secureNativeQuery, SquidService } from '@squidcloud/backend';

export class ExampleService extends SquidService {
@secureNativeQuery('YOUR_CONNECTOR_ID')
verifyNativeQueryAccess(): Promise<boolean> {
// Get the authenticated user's ID
const userId = this.getUserAuth()?.userId;
if (!userId) {
return false;
}

// Check if the user's ID is in the collection listing users permitted to access native query
const userTableAccess = await this.squid.collection('table_access').doc(userId).snapshot();
return !!userTableAccess;
}
}

Native Query Context​

native relational query または MongoDB query の実行時、client が実行しようとする native query の type('relational' または 'mongo')および query type に基づくその他の attribute を示す context を Squid backend で利用できます。

native relational query の実行時には、次の context type が提供されます。

Backend code
RelationalNativeQueryContext  {
type: 'relational';
query: string;
params: Record<string, any>;
}

この context を使用して、client が実行できる native query の type を制限します。たとえば、次の code は、YEAR field の value が 1980 より大きい SQUIDS collection(または table の row)を select する 1 type の native query のみを client に許可します。client が別の query を実行しようとした場合、または 1980 より前の value を table に query した場合、query は failure します。

Backend code
import { secureNativeQuery, SquidService, RelationalNativeQueryContext } from '@squidcloud/backend';

export class ExampleService extends SquidService {
@secureNativeQuery('YOUR_CONNECTOR_ID')
verifyNativeQueryAccess(context: RelationalNativeQueryContext): boolean {
if (context.query !== 'SELECT * FROM SQUIDS WHERE YEAR = ${year}' || context.params.year < 1980) {
return false;
}
return true;
}
}

native MongoDB query の実行時には、次の context type が提供されます。

Backend code
MongoNativeQueryContext {
type: 'mongo';
collectionName: string;
aggregationPipeline: Array<any | undefined>;
}

この context を使用して、client が Mongo aggregation pipeline に実行できる aggregation pipeline query の type を制限します。次の例では、user は ORDERS collection 内でのみ MongoDB aggregation pipeline を実行できます。

Backend code
import { secureNativeQuery, SquidService, MongoNativeQueryContext } from '@squidcloud/backend';

export class ExampleService extends SquidService {
@secureNativeQuery('YOUR_CONNECTOR_ID')
verifyNativeMongoQueryAccess(context: MongoNativeQueryContext): boolean {
if (context.collectionName !== 'ORDERS') {
return false;
}
return true;
}
}