액세스 제어 #

저장소 엔진에는 객체에 대한 액세스를 제어하는 두 가지 기능이 있습니다. 객체 소유권 및 액세스 권한.

객체 소유권 #

소유자와 함께 저장소 객체가 생성됩니다. 소유자는 객체를 만든 사용자, 시스템 소유자 또는 코드 런타임으로 객체를 만들 때 할당된 소유자입니다.

코드 런타임에서 객체를 작성할 때 소유자는 명시적으로 설정되지 않는 한 시스템 사용자입니다. 클라이언트에서 저장소 객체를 작성하는 사용자는 기본적으로 소유자로 설정됩니다.

시스템 소유 객체는 시스템 사용자로 생성되며 서버에서 nil UUID(00000000-0000-0000-0000-000000000000)로 표시됩니다. 시스템 소유 객체에는 클라이언트가 가져오기 전에 공개 읽기 액세스 권한이 있어야 합니다.

이 코드 예제는 시스템이 소유한 객체(공개 읽기로 표시됨)를 검색하는 방법을 보여줍니다.

Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
curl -X POST "http://127.0.0.1:7350/v2/storage" \
  -H 'Authorization: Bearer <session token>' \
  -d '{
    "object_ids": [
      {
        "collection": "configuration",
        "key": "config",
      }
    ]
  }'
Client
1
2
3
4
5
6
7
const objects = await client.readStorageObjects(session, {
  "object_ids": [{
    "collection": "configurations",
    "key": "config"
  }]
});
console.info("Read objects: %o", objects);
Client
1
2
3
4
5
6
var result = await client.ReadStorageObjectsAsync(session, new StorageObjectId {
    Collection = "configuration",
    Key = "config"
});

Console.WriteLine("Read objects: [{0}]", string.Join(",\n  ", result.Objects));
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
auto successCallback = [](const NStorageObjects& objects)
{
  for (auto& object : objects)
    {
        std::cout << "Object key: " << object.key << ", value: " << object.value << std::endl;
    }
};

std::vector<NReadStorageObjectId> objectIds;
NReadStorageObjectId objectId;
objectId.collection = "configurations";
objectId.key = "config";
objectIds.push_back(objectId);
client->readStorageObjects(session, objectIds, successCallback);
Client
1
2
3
4
StorageObjectId objectId = new StorageObjectId("configuration");
objectId.setKey("config");
StorageObjects objects = client.readStorageObjects(session, objectId).get();
System.out.format("Read objects %s", objects.getObjectsList().toString());
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var result : NakamaAPI.ApiStorageObjects = yield(client.read_storage_objects_async(session, [
    NakamaStorageObjectId.new("configuration", "config")
]), "completed")

if result.is_exception():
    print("An error occurred: %s" % result)
    return

print("Read objects:")

for o in result.objects:
    print("%s" % o)
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
POST /v2/storage
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
{
  "object_ids": [
    {
      "collection": "configuration",
      "key": "config"
    }
  ]
}
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
local objects_ids = {
  {
				collection = "configuration",
				key = "config"
  }
}

local result = client.read_storage_objects(objects_ids)

if result.error then
  print(result.message)
  return
end

for _,object in ipairs(result.objects) do
  pprint(object)
end

코드 런타임을 사용하여 객체를 가져올 수도 있습니다. 코드 런타임은 서버에서 권한 부여 코드로 실행되기 때문에 액세스 권한에 대한 표준 규칙에서 제외됩니다.

Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
local object_ids = {
  { collection = "configuration", key = "config", user_id = nil },
}

local objects = nk.storage_read(object_ids)

for _, o in ipairs(objects) do
  local message = ("value: %q"):format(o.value)
  nk.logger_info(message)
end
Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
objectIds := []*runtime.StorageRead{
    &runtime.StorageRead{
        Collection: "configuration",
        Key: "config",
    },
}

objects, err := nk.StorageRead(ctx, objectIds)

if err != nil {
    // Handle error.
} else {
    for _, object := range objects {
        logger.Info("value: %s", object.Value)
    }
}
Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
let objectIds: nkruntime.StorageReadRequest[] = [
  { collection: 'configuration', key: 'config', userId: '<uuid>' },
]

let objects: nkruntime.StorageObject[] = [];

try {
  let objects = nk.storageRead(objectIds);
} catch (error) {
  // Handle error
}

objects.forEach(function (o) {
  logger.info('value: %q', o.value);
});

객체 권한 #

객체에는 객체를 작성하거나 업데이트할 때 해당 객체의 소유자에게 적용되는 권한이 있습니다:

  • ReadPermission 의 경우 Public Read (2), Owner Read (1) 또는 No Read (0)입니다.
  • WritePermission 의 경우 Owner Write (1) 또는 No Write (0)입니다.

이러한 권한은 서버가 권한이 있고 항상 객체를 읽고 쓸 수 있으므로 코드 런타임을 통해 저장소 엔진과 상호 작용할 때 무시됩니다. 따라서 No Read / No Write 권한은 클라이언트가 객체를 읽고 쓸 수 없음을 의미합니다.

Owner ReadOwner Write 권한이 있는 객체는 이 객체를 소유한 사용자만 액세스하거나 수정할 수 있습니다. 다른 클라이언트는 이 객체에 액세스할 수 없습니다.

Public Read 모든 사용자가 해당 객체를 읽을 수 있음을 의미합니다. 이것은 사용자가 자신의 게임 상태 또는 그 일부를 다른 사용자와 공유해야 하는 게임 플레이의 경우 매우 유용합니다. 예를 들어 서로 싸우고 싶어하는 고유한 "Army" 객체를 가진 사용자가 있을 수 있습니다. 각 사용자는 공개 읽기로 자신의 객체를 작성할 수 있고 다른 사용자가 읽을 수 있으므로 서로의 장치에서 렌더링이 가능합니다.

클라이언트에서 객체를 수정할 때 객체의 기본 권한은 Owner ReadOwner Write(으)로 설정됩니다. 코드 런타임에서 객체를 수정할 때 객체의 기본 권한은 No ReadNo Write(으)로 설정됩니다. 객체를 나열할 때 적절한 권한이 있는 객체만 다시 가져옵니다.

Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# "2" refers to Public Read permission
# "1" refers to Owner Write permission
curl -X PUT "http://127.0.0.1:7350/v2/storage" \
  -H 'Authorization: Bearer <session token>' \
  -d '{
    "objects": [
      {
        "collection": "battle",
        "key": "army",
        "value": "{"soldiers": 50}",
        "permission_read": 2,
        "permission_write": 1
      }
    ]
  }'
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
var army_setup = { "soldiers": 50 };
// "2" refers to Public Read permission
// "1" refers to Owner Write permission
const object_ids = await client.writeStorageObjects(session, [
  {
    "collection": "saves",
    "key": "savegame",
    "value": army_setup,
    "permission_read": 2,
    "permission_write": 1
  }
]);

console.info("Stored objects: %o", object_ids);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var armySetup = "{ "soldiers": 50 }";
// "2" refers to Public Read permission
// "1" refers to Owner Write permission
var result = await client.WriteStorageObjectsAsync(session, new WriteStorageObject
{
    Collection = "saves",
    Key = "savegame",
    Value = armySetup,
    PermissionRead = 2,
    PermissionWrite = 1
});

Console.WriteLine("Stored objects: [{0}]", string.Join(",\n  ", result.Objects));
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
auto successCallback = [](const NStorageObjectAcks& acks)
{
};

std::vector<NStorageObjectWrite> objects;
NStorageObjectWrite object;
object.collection = "saves";
object.key = "savegame";
object.value = "{ "soldiers": 50 }";
object.permissionRead = NStoragePermissionRead::PUBLIC_READ;   // Public Read permission
object.permissionWrite = NStoragePermissionWrite::OWNER_WRITE; // Owner Write permission
objects.push_back(object);
client->writeStorageObjects(session, objects, successCallback);
Client
1
2
3
4
String armySetup = "{ "soldiers": 50 }";
StorageObjectWrite object = new StorageObjectWrite("saves", "savegame", armySetup, PermissionRead.PUBLIC_READ, PermissionWrite.OWNER_WRITE);
StorageObjectAcks acks = client.writeStorageObjects(session, object).get();
System.out.format("Stored objects %s", acks.getAcksList());
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
var army_setup = "{ "soldiers": 50 }";
# "2" refers to Public Read permission
# "1" refers to Owner Write permission
var acks : NakamaAPI.ApiStorageObjectAcks = yield(client.write_storage_objects_async(session, [
    NakamaWriteStorageObject.new("saves", "savegame", 2, 1, army_setup, "")
]), "completed")

if acks.is_exception():
    print("An error occurred: %s" % acks)
    return

print("Stored objects: %s" % [acks.acks])
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
PUT /v2/storage
Host: 127.0.0.1:7350
Accept: application/json
Content-Type: application/json
Authorization: Bearer <session token>
{
  "objects": [
    {
      "collection": "battle",
      "key": "army",
      "value": "{ "soldiers": 50 }",
      "permission_read": 2,
      "permission_write": 1
    }
  ]
}
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
local army_setup = json.encode({ soldiers = 50 })
local can_read = 2
local can_write = 1

local objects = {
  {
    collection = "battle",
    key = "army",
    permissionRead = can_read,
    permissionWrite = can_write,
    value = army_setup,
    version = version
  }
}

local result = client.write_storage_objects(objects)

if result.error then
  print(result.message)
  return
end

for _,ack in ipairs(result.acks) do
  pprint(ack)
end

코드 런타임에서 사용자 지정 권한이 있는 객체를 저장할 수 있습니다.

Code snippet for this language TypeScript has not been found. Please choose another language to show equivalent examples.
Server
1
2
3
4
5
6
7
local user_id = "4ec4f126-3f9d-11e7-84ef-b7c182b36521" -- Some user ID.

local new_objects = {
  { collection = "battle", key = "army", user_id = user_id, value = {}, permission_read = 2, permission_write = 1 }
}

nk.storage_write(new_objects)
Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
userID := "4ec4f126-3f9d-11e7-84ef-b7c182b36521" // Some user ID.
objects := []*runtime.StorageWrite{
    &runtime.StorageWrite{
        Collection:      "battle",
        Key:             "army",
        UserID:          userID,
        Value:           "{}",
        PermissionRead:  2,
        PermissionWrite: 1,
    },
}

if _, err := nk.StorageWrite(ctx, objects); err != nil {
    // Handle error.
}

Related Pages