细粒度访问控制

在创建数据库时,管理员可能需要确定哪些用户可以访问特定信息。

内置角色和权限中所述,Neo4j 已提供预设角色,这些角色配置了特定的权限(即读取、编辑或写入)。虽然这些内置角色涵盖了许多常见的日常场景,但也可以根据特定需求创建自定义角色。

本教程将通过一个医疗保健用例来演示安全和细粒度访问控制的各个方面。

医疗保健用例

为了演示这些工具的应用,考虑一个可能在医疗诊所或医院中使用的“医疗保健”数据库示例。

为简单起见,只使用三个标签来表示以下实体:

(:Patient)

因有症状而到诊所就诊的患者。患者的特定信息可以通过属性捕获:

  • name

  • ssn

  • address

  • dateOfBirth

(:Symptom)

在已知疾病目录中找到的一组症状。它们可以使用以下属性进行描述:

  • name

  • description

(:Disease)

数据库中已知疾病目录中的映射疾病。它们可以使用以下属性进行描述:

  • name

  • description

这些实体被建模为节点,并通过以下类型的关系连接:

(:Patient)-[:HAS]→(:Symptom)

当患者向诊所报到时,他们向护士或医生描述其症状。护士或医生随后将此信息以患者节点与已知症状图之间的连接形式输入到数据库中。此关系中可能感兴趣的属性包括:

  • date - 报告症状的日期。

(:Symptom)-[:OF]→(:Disease)

症状是已知疾病图中的一个子图。症状与疾病之间的关系可以包括一个概率因子,表示患有该疾病的人表达该症状的可能性或普遍性。这将使医生更容易使用统计查询进行诊断。

  • probability - 症状与疾病匹配的概率。

(:Patient)-[:DIAGNOSIS]→(:Disease)

医生可以使用疾病图及其症状对最可能匹配患者的疾病进行初步调查。基于此以及他们对患者的自身评估,医生可能会做出诊断,并通过添加具有适当属性的此关系将其持久化到图中:

  • by: 医生姓名

  • date: 诊断日期

  • description: 医生附加说明

security example
图 1. 医疗保健用例

同一个数据库将由许多不同的用户使用,每个用户都有不同的访问需求:

  • 医生需要诊断患者。

  • 护士需要治疗患者。

  • 接待员需要识别和记录患者信息。

  • 研究人员需要对医疗数据进行统计分析。

  • IT 管理员需要管理数据库,例如创建和分配用户。

要创建数据库,首先创建表示上述实体的节点和关系。

创建 healthcare 数据库

以下步骤假设您已安装 Neo4j Enterprise Edition 并且它正在运行。有关详细信息,请参阅安装

  1. 使用 Cypher Shell,以 neo4j 用户身份登录到 system 数据库:

    cypher-shell -u neo4j -p my-password -d system
  2. 创建 healthcare 数据库:

    CREATE DATABASE healthcare;
  3. healthcare 数据库设置为默认数据库:

    CALL dbms.setDefaultDatabase("healthcare");
    +----------------------------------------------------------------------+
    | result                                                               |
    +----------------------------------------------------------------------+
    | "Old default database unset. New default database set to healthcare" |
    +----------------------------------------------------------------------+
    
    1 row
    ready to start consuming query after 9 ms, results consumed after another 4 ms

将数据导入 healthcare 数据库

医疗保健用例部分中创建表示上述实体的节点和关系。

  1. 切换到 healthcare 数据库:

    :use healthcare;
  2. 为症状创建一些数据:

    WITH ['Itchy','Scratchy','Sore','Swollen','Red','Inflamed','Angry','Sad','Pale','Dizzy'] AS symptoms
                 UNWIND symptoms AS symptom
                 MERGE (s:Symptom {name:symptom})
                 ON CREATE SET s.description = 'Looks ' + toLower(symptom)
                 RETURN s.name, s.description;
    结果:
    +-------------------------------+
    | s.name     | s.description    |
    +-------------------------------+
    | "Itchy"    | "Looks itchy"    |
    | "Scratchy" | "Looks scratchy" |
    | "Sore"     | "Looks sore"     |
    | "Swollen"  | "Looks swollen"  |
    | "Red"      | "Looks red"      |
    | "Inflamed" | "Looks inflamed" |
    | "Angry"    | "Looks angry"    |
    | "Sad"      | "Looks sad"      |
    | "Pale"     | "Looks pale"     |
    | "Dizzy"    | "Looks dizzy"    |
    +-------------------------------+
    
    10 rows
    ready to start consuming query after 53 ms, results consumed after another 24 ms
    Added 10 nodes, Set 20 properties, Added 10 labels
  3. 为疾病创建一些数据:

    WITH
      ['Argitis','Whatitis','Otheritis','Someitis','Placeboitis','Yellowitis'] AS diseases,
      ['Chronic','Acute'] AS severity
    UNWIND diseases AS disease
    UNWIND severity as sev
    MERGE (d:Disease {name:sev+' '+disease})
    ON CREATE SET d.description = sev + ' ' + toLower(disease)
    RETURN d.name, d.description;
    结果:
    +-----------------------------------------------+
    | d.name                | d.description         |
    +-----------------------------------------------+
    | "Chronic Argitis"     | "Chronic argitis"     |
    | "Acute Argitis"       | "Acute argitis"       |
    | "Chronic Whatitis"    | "Chronic whatitis"    |
    | "Acute Whatitis"      | "Acute whatitis"      |
    | "Chronic Otheritis"   | "Chronic otheritis"   |
    | "Acute Otheritis"     | "Acute otheritis"     |
    | "Chronic Someitis"    | "Chronic someitis"    |
    | "Acute Someitis"      | "Acute someitis"      |
    | "Chronic Placeboitis" | "Chronic placeboitis" |
    | "Acute Placeboitis"   | "Acute placeboitis"   |
    | "Chronic Yellowitis"  | "Chronic yellowitis"  |
    | "Acute Yellowitis"    | "Acute yellowitis"    |
    +-----------------------------------------------+
    
    12 rows
    ready to start consuming query after 56 ms, results consumed after another 7 ms
    Added 12 nodes, Set 24 properties, Added 12 labels
  4. 创建症状和疾病之间的关系:

    MATCH (s:Symptom) WITH collect(s) as symptoms
    WITH symptoms, size(symptoms) / 2 as maxsym
    MATCH (d:Disease)
    UNWIND range(0,maxsym) as symi
    WITH d, symi, symptoms, toInteger(size(symptoms) * rand()) as si, rand()/2 + 0.5 AS prob
    WITH d, symptoms[si] AS s, prob
    MERGE (s)-[o:OF]->(d)
    ON CREATE SET o.probability = prob
    RETURN d.name, o.probability, s.name;
    结果:
    +---------------------------------------------------------+
    | d.name                | o.probability      | s.name     |
    +---------------------------------------------------------+
    | "Chronic Argitis"     | 0.5488344602870381 | "Scratchy" |
    | "Chronic Argitis"     | 0.660404649462915  | "Itchy"    |
    | "Chronic Argitis"     | 0.6905998399032373 | "Angry"    |
    | "Chronic Argitis"     | 0.660404649462915  | "Itchy"    |
    | "Chronic Argitis"     | 0.8740581222813869 | "Red"      |
    | "Chronic Argitis"     | 0.7456909803542418 | "Sore"     |
    | "Acute Argitis"       | 0.607200508350778  | "Pale"     |
    | "Acute Argitis"       | 0.5772236253537283 | "Red"      |
    | "Acute Argitis"       | 0.7268375663608245 | "Inflamed" |
    | "Acute Argitis"       | 0.847011132303783  | "Itchy"    |
    | "Acute Argitis"       | 0.8025327549974599 | "Sore"     |
    | "Acute Argitis"       | 0.5772236253537283 | "Red"      |
    | "Chronic Whatitis"    | 0.9185112224896539 | "Sore"     |
    | "Chronic Whatitis"    | 0.8220811592705012 | "Dizzy"    |
    | "Chronic Whatitis"    | 0.8220811592705012 | "Dizzy"    |
    | "Chronic Whatitis"    | 0.9947532896439784 | "Scratchy" |
    | "Chronic Whatitis"    | 0.5479749642339755 | "Red"      |
    | "Chronic Whatitis"    | 0.9466973516593605 | "Inflamed" |
    | "Acute Whatitis"      | 0.7217509679510017 | "Inflamed" |
    | "Acute Whatitis"      | 0.7217509679510017 | "Inflamed" |
    | "Acute Whatitis"      | 0.7073350047270233 | "Scratchy" |
    | "Acute Whatitis"      | 0.7217509679510017 | "Inflamed" |
    | "Acute Whatitis"      | 0.6800748332507602 | "Red"      |
    | "Acute Whatitis"      | 0.6953854679660172 | "Itchy"    |
    | "Chronic Otheritis"   | 0.5570795327063996 | "Scratchy" |
    | "Chronic Otheritis"   | 0.7615506655612736 | "Swollen"  |
    | "Chronic Otheritis"   | 0.7147549568270981 | "Angry"    |
    | "Chronic Otheritis"   | 0.9309059023795485 | "Red"      |
    | "Chronic Otheritis"   | 0.8339105187862091 | "Dizzy"    |
    | "Chronic Otheritis"   | 0.7147549568270981 | "Angry"    |
    | "Acute Otheritis"     | 0.7449502448640619 | "Red"      |
    | "Acute Otheritis"     | 0.6635390850482914 | "Sad"      |
    | "Acute Otheritis"     | 0.6488764428922569 | "Itchy"    |
    | "Acute Otheritis"     | 0.7642990617862074 | "Pale"     |
    | "Acute Otheritis"     | 0.5532690807468361 | "Scratchy" |
    | "Acute Otheritis"     | 0.8062425062999423 | "Inflamed" |
    | "Chronic Someitis"    | 0.580678012588533  | "Sore"     |
    | "Chronic Someitis"    | 0.9569035040624002 | "Red"      |
    | "Chronic Someitis"    | 0.9328323008783481 | "Inflamed" |
    | "Chronic Someitis"    | 0.9569035040624002 | "Red"      |
    | "Chronic Someitis"    | 0.5492540886308123 | "Pale"     |
    | "Chronic Someitis"    | 0.9204301026117075 | "Swollen"  |
    | "Acute Someitis"      | 0.9969140989164824 | "Itchy"    |
    | "Acute Someitis"      | 0.8756876989165112 | "Swollen"  |
    | "Acute Someitis"      | 0.9969140989164824 | "Itchy"    |
    | "Acute Someitis"      | 0.6258855371986936 | "Red"      |
    | "Acute Someitis"      | 0.9928922186427123 | "Angry"    |
    | "Acute Someitis"      | 0.6258855371986936 | "Red"      |
    | "Chronic Placeboitis" | 0.9837947935707738 | "Itchy"    |
    | "Chronic Placeboitis" | 0.7795050137703664 | "Inflamed" |
    | "Chronic Placeboitis" | 0.680595344835278  | "Sad"      |
    | "Chronic Placeboitis" | 0.8383237671521345 | "Scratchy" |
    | "Chronic Placeboitis" | 0.7054054618102132 | "Swollen"  |
    | "Chronic Placeboitis" | 0.7795050137703664 | "Inflamed" |
    | "Acute Placeboitis"   | 0.768802727874529  | "Dizzy"    |
    | "Acute Placeboitis"   | 0.6645530219645431 | "Scratchy" |
    | "Acute Placeboitis"   | 0.9192262998770437 | "Pale"     |
    | "Acute Placeboitis"   | 0.7321327463249545 | "Itchy"    |
    | "Acute Placeboitis"   | 0.5768920173860386 | "Sad"      |
    | "Acute Placeboitis"   | 0.5467367430608921 | "Sore"     |
    | "Chronic Yellowitis"  | 0.657149882924074  | "Dizzy"    |
    | "Chronic Yellowitis"  | 0.5274096280530778 | "Swollen"  |
    | "Chronic Yellowitis"  | 0.657149882924074  | "Dizzy"    |
    | "Chronic Yellowitis"  | 0.9011165844619397 | "Scratchy" |
    | "Chronic Yellowitis"  | 0.5274096280530778 | "Swollen"  |
    | "Chronic Yellowitis"  | 0.7267736062002124 | "Sore"     |
    | "Acute Yellowitis"    | 0.7764355480097833 | "Swollen"  |
    | "Acute Yellowitis"    | 0.9776709262803641 | "Inflamed" |
    | "Acute Yellowitis"    | 0.6495454012653183 | "Red"      |
    | "Acute Yellowitis"    | 0.7764355480097833 | "Swollen"  |
    | "Acute Yellowitis"    | 0.7395280933743617 | "Dizzy"    |
    | "Acute Yellowitis"    | 0.6068906083054821 | "Itchy"    |
    +---------------------------------------------------------+
    
    72 rows
    ready to start consuming query after 339 ms, results consumed after another 28 ms
    Created 59 relationships, Set 59 properties
  5. 确保可以使用尚不存在的类型:

    CALL db.createRelationshipType('DIAGNOSIS');
    CALL db.createProperty('by');
    CALL db.createProperty('date');
    CALL db.createProperty('description');
    CALL db.createProperty('created_at');
    CALL db.createProperty('updated_at');
    结果:
    0 rows
    ready to start consuming query after 22 ms, results consumed after another 0 ms
    0 rows
    ready to start consuming query after 17 ms, results consumed after another 0 ms
    0 rows
    ready to start consuming query after 7 ms, results consumed after another 0 ms
    0 rows
    ready to start consuming query after 7 ms, results consumed after another 0 ms
    0 rows
    ready to start consuming query after 8 ms, results consumed after another 0 ms
    0 rows
    ready to start consuming query after 7 ms, results consumed after another 0 ms
  6. 为患者创建一些数据:

    WITH
      ['Jack','Mary','Sally','Mark','Joe','Jane','Bob','Ally'] AS firstnames,
      ['Anderson','Jackson','Svensson','Smith','Stone'] AS surnames,
      ['mymail.com','example.com','other.org','net.net'] AS domains
    UNWIND range(0,100) AS uid
    WITH 1234567+uid AS ssn,
      firstnames[uid%size(firstnames)] AS firstname,
      surnames[uid%size(surnames)] AS surname,
      domains[uid%size(domains)] AS domain
    WITH ssn, firstname, surname,
      tolower(firstname + '.' + surname + '@' + domain) AS email,
      toInteger(1500000000000 * rand()) AS ts
    MERGE (p:Patient {ssn:ssn})
    ON CREATE SET p.name = firstname + ' ' + surname,
      p.email = email,
      p.address = '1 secret way, downtown',
      p.dateOfBirth = date(datetime({epochmillis:ts}))
    RETURN count(p);
    结果:
    +----------+
    | count(p) |
    +----------+
    | 101      |
    +----------+
    
    1 row
    ready to start consuming query after 49 ms, results consumed after another 38 ms
    Added 101 nodes, Set 505 properties, Added 101 labels
  7. 创建患者和症状之间的关系:

    MATCH (s:Symptom) WITH collect(s) as symptoms
    WITH symptoms, size(symptoms) / 2 as maxsym, 1500000000000 AS base, 75477004177 AS diff
    MATCH (p:Patient)
    UNWIND range(0,maxsym) as symi
    WITH p, symi, symptoms, toInteger(size(symptoms) * rand()) as si, rand()/2 + 0.5 AS prob, base + toInteger(diff * rand()) AS ts
    WITH p, symptoms[si] AS s, prob, ts
    MERGE (p)-[h:HAS]->(s)
    ON CREATE SET h.date = date(datetime({epochmillis:ts}))
    RETURN p.name, p.dateOfBirth, h.date, s.name;
    结果:
    +------------------------------------------------------------+
    | p.name           | p.dateOfBirth | h.date     | s.name     |
    +------------------------------------------------------------+
    | "Jack Anderson"  | 1981-01-10    | 2019-03-03 | "Angry"    |
    | "Jack Anderson"  | 1981-01-10    | 2018-05-05 | "Sad"      |
    | "Jack Anderson"  | 1981-01-10    | 2018-06-05 | "Sore"     |
    | "Jack Anderson"  | 1981-01-10    | 2017-11-17 | "Itchy"    |
    | "Jack Anderson"  | 1981-01-10    | 2017-10-02 | "Dizzy"    |
    | "Jack Anderson"  | 1981-01-10    | 2019-11-01 | "Red"      |
    | "Mary Jackson"   | 1983-05-24    | 2018-03-30 | "Scratchy" |
    | "Mary Jackson"   | 1983-05-24    | 2018-03-08 | "Pale"     |
    | "Mary Jackson"   | 1983-05-24    | 2019-05-03 | "Dizzy"    |
    | "Mary Jackson"   | 1983-05-24    | 2019-08-16 | "Red"      |
    | "Mary Jackson"   | 1983-05-24    | 2018-07-07 | "Inflamed" |
    | "Mary Jackson"   | 1983-05-24    | 2018-07-07 | "Inflamed" |
    | "Sally Svensson" | 2011-04-03    | 2018-02-12 | "Sore"     |
    | "Sally Svensson" | 2011-04-03    | 2019-07-23 | "Pale"     |
    | "Sally Svensson" | 2011-04-03    | 2019-04-17 | "Sad"      |
    | "Sally Svensson" | 2011-04-03    | 2017-09-25 | "Red"      |
    | "Sally Svensson" | 2011-04-03    | 2017-08-14 | "Swollen"  |
    | "Sally Svensson" | 2011-04-03    | 2017-08-14 | "Swollen"  |
    | "Mark Smith"     | 1998-08-26    | 2018-08-25 | "Inflamed" |
    | "Mark Smith"     | 1998-08-26    | 2018-08-25 | "Inflamed" |
    | "Mark Smith"     | 1998-08-26    | 2018-05-14 | "Itchy"    |
    | "Mark Smith"     | 1998-08-26    | 2019-07-02 | "Dizzy"    |
    | "Mark Smith"     | 1998-08-26    | 2018-02-27 | "Sad"      |
    | "Mark Smith"     | 1998-08-26    | 2018-10-07 | "Swollen"  |
    | "Joe Stone"      | 1972-10-20    | 2019-05-16 | "Red"      |
    | "Joe Stone"      | 1972-10-20    | 2018-08-31 | "Inflamed" |
    | "Joe Stone"      | 1972-10-20    | 2018-08-31 | "Inflamed" |
    | "Joe Stone"      | 1972-10-20    | 2017-07-21 | "Sore"     |
    | "Joe Stone"      | 1972-10-20    | 2018-08-31 | "Inflamed" |
    | "Joe Stone"      | 1972-10-20    | 2017-10-21 | "Itchy"    |
    | "Jane Anderson"  | 2001-10-18    | 2018-07-04 | "Scratchy" |
    | "Jane Anderson"  | 2001-10-18    | 2019-02-09 | "Dizzy"    |
    | "Jane Anderson"  | 2001-10-18    | 2018-05-03 | "Pale"     |
    | "Jane Anderson"  | 2001-10-18    | 2019-08-13 | "Angry"    |
    | "Jane Anderson"  | 2001-10-18    | 2018-05-03 | "Pale"     |
    | "Jane Anderson"  | 2001-10-18    | 2019-11-12 | "Swollen"  |
    | "Bob Jackson"    | 1997-08-20    | 2019-05-03 | "Sad"      |
    | "Bob Jackson"    | 1997-08-20    | 2019-03-14 | "Red"      |
    | "Bob Jackson"    | 1997-08-20    | 2019-03-01 | "Angry"    |
    | "Bob Jackson"    | 1997-08-20    | 2018-03-10 | "Sore"     |
    | "Bob Jackson"    | 1997-08-20    | 2018-03-10 | "Sore"     |
    | "Bob Jackson"    | 1997-08-20    | 2019-05-03 | "Sad"      |
    | "Ally Svensson"  | 2008-05-25    | 2019-06-06 | "Sore"     |
    | "Ally Svensson"  | 2008-05-25    | 2019-11-04 | "Sad"      |
    | "Ally Svensson"  | 2008-05-25    | 2018-10-04 | "Scratchy" |
    | "Ally Svensson"  | 2008-05-25    | 2017-11-28 | "Inflamed" |
    | "Ally Svensson"  | 2008-05-25    | 2018-10-29 | "Itchy"    |
    | "Ally Svensson"  | 2008-05-25    | 2019-08-08 | "Angry"    |
    | "Jack Smith"     | 1974-07-02    | 2018-01-15 | "Itchy"    |
    | "Jack Smith"     | 1974-07-02    | 2019-02-12 | "Angry"    |
    | "Jack Smith"     | 1974-07-02    | 2017-10-16 | "Dizzy"    |
    | "Jack Smith"     | 1974-07-02    | 2018-01-03 | "Red"      |
    | "Jack Smith"     | 1974-07-02    | 2018-01-15 | "Itchy"    |
    | "Jack Smith"     | 1974-07-02    | 2017-11-14 | "Pale"     |
    | "Mary Stone"     | 1983-09-27    | 2018-01-14 | "Dizzy"    |
    | "Mary Stone"     | 1983-09-27    | 2019-03-24 | "Swollen"  |
    | "Mary Stone"     | 1983-09-27    | 2018-04-07 | "Angry"    |
    | "Mary Stone"     | 1983-09-27    | 2019-03-24 | "Swollen"  |
    | "Mary Stone"     | 1983-09-27    | 2018-01-14 | "Dizzy"    |
    | "Mary Stone"     | 1983-09-27    | 2017-11-27 | "Sore"     |
    | "Sally Anderson" | 2009-12-14    | 2019-08-21 | "Swollen"  |
    | "Sally Anderson" | 2009-12-14    | 2018-02-23 | "Sore"     |
    | "Sally Anderson" | 2009-12-14    | 2018-06-05 | "Scratchy" |
    | "Sally Anderson" | 2009-12-14    | 2018-02-23 | "Sore"     |
    | "Sally Anderson" | 2009-12-14    | 2017-08-20 | "Pale"     |
    | "Sally Anderson" | 2009-12-14    | 2019-05-25 | "Itchy"    |
    | "Mark Jackson"   | 1970-11-29    | 2018-09-27 | "Sore"     |
    | "Mark Jackson"   | 1970-11-29    | 2017-12-27 | "Angry"    |
    | "Mark Jackson"   | 1970-11-29    | 2017-12-26 | "Swollen"  |
    | "Mark Jackson"   | 1970-11-29    | 2018-09-27 | "Sore"     |
    | "Mark Jackson"   | 1970-11-29    | 2018-02-01 | "Inflamed" |
    | "Mark Jackson"   | 1970-11-29    | 2018-12-19 | "Pale"     |
    | "Joe Svensson"   | 1972-02-12    | 2017-07-27 | "Sad"      |
    | "Joe Svensson"   | 1972-02-12    | 2019-07-27 | "Itchy"    |
    | "Joe Svensson"   | 1972-02-12    | 2019-06-20 | "Sore"     |
    | "Joe Svensson"   | 1972-02-12    | 2019-11-09 | "Inflamed" |
    | "Joe Svensson"   | 1972-02-12    | 2019-07-27 | "Itchy"    |
    | "Joe Svensson"   | 1972-02-12    | 2019-07-27 | "Itchy"    |
    | "Jane Smith"     | 2013-04-09    | 2018-12-13 | "Swollen"  |
    | "Jane Smith"     | 2013-04-09    | 2018-12-13 | "Swollen"  |
    | "Jane Smith"     | 2013-04-09    | 2019-03-13 | "Red"      |
    | "Jane Smith"     | 2013-04-09    | 2019-01-25 | "Dizzy"    |
    | "Jane Smith"     | 2013-04-09    | 2017-07-25 | "Angry"    |
    | "Jane Smith"     | 2013-04-09    | 2018-04-11 | "Inflamed" |
    | "Bob Stone"      | 2012-04-11    | 2018-09-04 | "Inflamed" |
    | "Bob Stone"      | 2012-04-11    | 2017-08-07 | "Red"      |
    | "Bob Stone"      | 2012-04-11    | 2019-07-11 | "Swollen"  |
    | "Bob Stone"      | 2012-04-11    | 2019-07-11 | "Swollen"  |
    | "Bob Stone"      | 2012-04-11    | 2019-07-14 | "Sore"     |
    | "Bob Stone"      | 2012-04-11    | 2017-11-18 | "Itchy"    |
    | "Ally Anderson"  | 2000-05-24    | 2018-11-27 | "Itchy"    |
    | "Ally Anderson"  | 2000-05-24    | 2018-02-10 | "Pale"     |
    | "Ally Anderson"  | 2000-05-24    | 2017-07-25 | "Red"      |
    | "Ally Anderson"  | 2000-05-24    | 2018-03-19 | "Sad"      |
    | "Ally Anderson"  | 2000-05-24    | 2017-07-25 | "Red"      |
    | "Ally Anderson"  | 2000-05-24    | 2017-07-25 | "Red"      |
    | "Jack Jackson"   | 1988-03-13    | 2018-06-29 | "Sad"      |
    | "Jack Jackson"   | 1988-03-13    | 2019-06-25 | "Sore"     |
    | "Jack Jackson"   | 1988-03-13    | 2019-05-27 | "Inflamed" |
    | "Jack Jackson"   | 1988-03-13    | 2018-07-09 | "Angry"    |
    | "Jack Jackson"   | 1988-03-13    | 2018-04-23 | "Pale"     |
    | "Jack Jackson"   | 1988-03-13    | 2019-05-15 | "Dizzy"    |
    | "Mary Svensson"  | 2008-01-19    | 2018-03-16 | "Dizzy"    |
    | "Mary Svensson"  | 2008-01-19    | 2018-04-14 | "Red"      |
    | "Mary Svensson"  | 2008-01-19    | 2018-10-25 | "Pale"     |
    | "Mary Svensson"  | 2008-01-19    | 2019-07-15 | "Swollen"  |
    | "Mary Svensson"  | 2008-01-19    | 2019-07-15 | "Swollen"  |
    | "Mary Svensson"  | 2008-01-19    | 2018-04-14 | "Red"      |
    | "Sally Smith"    | 1977-03-20    | 2019-02-23 | "Dizzy"    |
    | "Sally Smith"    | 1977-03-20    | 2017-11-28 | "Red"      |
    | "Sally Smith"    | 1977-03-20    | 2018-06-23 | "Scratchy" |
    | "Sally Smith"    | 1977-03-20    | 2017-10-28 | "Sad"      |
    | "Sally Smith"    | 1977-03-20    | 2017-11-28 | "Red"      |
    | "Sally Smith"    | 1977-03-20    | 2018-10-05 | "Inflamed" |
    | "Mark Stone"     | 1986-06-15    | 2019-11-24 | "Pale"     |
    | "Mark Stone"     | 1986-06-15    | 2018-07-30 | "Itchy"    |
    | "Mark Stone"     | 1986-06-15    | 2018-07-30 | "Itchy"    |
    | "Mark Stone"     | 1986-06-15    | 2017-09-10 | "Dizzy"    |
    | "Mark Stone"     | 1986-06-15    | 2018-07-18 | "Red"      |
    | "Mark Stone"     | 1986-06-15    | 2019-08-15 | "Sore"     |
    | "Joe Anderson"   | 1980-09-06    | 2019-06-19 | "Dizzy"    |
    | "Joe Anderson"   | 1980-09-06    | 2017-11-28 | "Red"      |
    | "Joe Anderson"   | 1980-09-06    | 2019-08-12 | "Scratchy" |
    | "Joe Anderson"   | 1980-09-06    | 2019-08-12 | "Scratchy" |
    | "Joe Anderson"   | 1980-09-06    | 2019-06-19 | "Dizzy"    |
    | "Joe Anderson"   | 1980-09-06    | 2017-07-16 | "Inflamed" |
    | "Jane Jackson"   | 2016-02-20    | 2018-04-03 | "Swollen"  |
    | "Jane Jackson"   | 2016-02-20    | 2018-02-21 | "Pale"     |
    | "Jane Jackson"   | 2016-02-20    | 2018-07-17 | "Angry"    |
    | "Jane Jackson"   | 2016-02-20    | 2018-01-22 | "Sore"     |
    | "Jane Jackson"   | 2016-02-20    | 2018-01-22 | "Sore"     |
    | "Jane Jackson"   | 2016-02-20    | 2017-09-28 | "Dizzy"    |
    | "Bob Svensson"   | 1983-08-04    | 2019-02-02 | "Pale"     |
    | "Bob Svensson"   | 1983-08-04    | 2018-12-01 | "Dizzy"    |
    | "Bob Svensson"   | 1983-08-04    | 2019-08-07 | "Sad"      |
    | "Bob Svensson"   | 1983-08-04    | 2018-11-18 | "Swollen"  |
    | "Bob Svensson"   | 1983-08-04    | 2018-12-25 | "Scratchy" |
    | "Bob Svensson"   | 1983-08-04    | 2018-04-09 | "Inflamed" |
    | "Ally Smith"     | 2012-03-01    | 2018-03-28 | "Inflamed" |
    | "Ally Smith"     | 2012-03-01    | 2018-03-28 | "Inflamed" |
    | "Ally Smith"     | 2012-03-01    | 2018-06-09 | "Scratchy" |
    | "Ally Smith"     | 2012-03-01    | 2019-01-25 | "Angry"    |
    | "Ally Smith"     | 2012-03-01    | 2018-09-06 | "Pale"     |
    | "Ally Smith"     | 2012-03-01    | 2018-12-04 | "Dizzy"    |
    | "Jack Stone"     | 2009-11-08    | 2019-01-18 | "Pale"     |
    | "Jack Stone"     | 2009-11-08    | 2018-03-29 | "Angry"    |
    | "Jack Stone"     | 2009-11-08    | 2019-10-22 | "Inflamed" |
    | "Jack Stone"     | 2009-11-08    | 2019-01-18 | "Pale"     |
    | "Jack Stone"     | 2009-11-08    | 2017-12-09 | "Itchy"    |
    | "Jack Stone"     | 2009-11-08    | 2018-10-27 | "Red"      |
    | "Mary Anderson"  | 1991-11-25    | 2018-01-02 | "Angry"    |
    | "Mary Anderson"  | 1991-11-25    | 2018-01-02 | "Angry"    |
    | "Mary Anderson"  | 1991-11-25    | 2017-11-01 | "Inflamed" |
    | "Mary Anderson"  | 1991-11-25    | 2017-12-16 | "Sore"     |
    | "Mary Anderson"  | 1991-11-25    | 2018-01-02 | "Angry"    |
    | "Mary Anderson"  | 1991-11-25    | 2018-03-22 | "Red"      |
    | "Sally Jackson"  | 2008-11-09    | 2019-07-02 | "Inflamed" |
    | "Sally Jackson"  | 2008-11-09    | 2018-02-24 | "Red"      |
    | "Sally Jackson"  | 2008-11-09    | 2019-08-07 | "Swollen"  |
    | "Sally Jackson"  | 2008-11-09    | 2019-04-05 | "Sore"     |
    | "Sally Jackson"  | 2008-11-09    | 2019-07-02 | "Inflamed" |
    | "Sally Jackson"  | 2008-11-09    | 2019-02-23 | "Scratchy" |
    | "Mark Svensson"  | 1979-06-22    | 2019-08-09 | "Itchy"    |
    | "Mark Svensson"  | 1979-06-22    | 2019-05-11 | "Swollen"  |
    | "Mark Svensson"  | 1979-06-22    | 2018-08-11 | "Inflamed" |
    | "Mark Svensson"  | 1979-06-22    | 2019-08-09 | "Itchy"    |
    | "Mark Svensson"  | 1979-06-22    | 2017-10-11 | "Sad"      |
    | "Mark Svensson"  | 1979-06-22    | 2019-09-22 | "Scratchy" |
    | "Joe Smith"      | 2008-07-03    | 2017-08-24 | "Sore"     |
    | "Joe Smith"      | 2008-07-03    | 2018-12-03 | "Red"      |
    | "Joe Smith"      | 2008-07-03    | 2018-12-03 | "Red"      |
    | "Joe Smith"      | 2008-07-03    | 2018-08-20 | "Inflamed" |
    | "Joe Smith"      | 2008-07-03    | 2018-12-03 | "Red"      |
    | "Joe Smith"      | 2008-07-03    | 2019-04-17 | "Angry"    |
    | "Jane Stone"     | 1977-11-25    | 2018-03-19 | "Scratchy" |
    | "Jane Stone"     | 1977-11-25    | 2017-08-18 | "Dizzy"    |
    | "Jane Stone"     | 1977-11-25    | 2017-12-09 | "Red"      |
    | "Jane Stone"     | 1977-11-25    | 2018-06-14 | "Swollen"  |
    | "Jane Stone"     | 1977-11-25    | 2018-08-22 | "Pale"     |
    | "Jane Stone"     | 1977-11-25    | 2018-08-22 | "Pale"     |
    | "Bob Anderson"   | 1970-04-27    | 2019-10-17 | "Scratchy" |
    | "Bob Anderson"   | 1970-04-27    | 2018-06-16 | "Red"      |
    | "Bob Anderson"   | 1970-04-27    | 2017-11-07 | "Itchy"    |
    | "Bob Anderson"   | 1970-04-27    | 2018-12-11 | "Pale"     |
    | "Bob Anderson"   | 1970-04-27    | 2017-11-07 | "Itchy"    |
    | "Bob Anderson"   | 1970-04-27    | 2019-02-26 | "Swollen"  |
    | "Ally Jackson"   | 1982-01-12    | 2019-06-15 | "Sad"      |
    | "Ally Jackson"   | 1982-01-12    | 2018-01-12 | "Sore"     |
    | "Ally Jackson"   | 1982-01-12    | 2019-06-15 | "Sad"      |
    | "Ally Jackson"   | 1982-01-12    | 2018-01-12 | "Sore"     |
    | "Ally Jackson"   | 1982-01-12    | 2018-04-19 | "Itchy"    |
    | "Ally Jackson"   | 1982-01-12    | 2019-04-06 | "Red"      |
    | "Jack Svensson"  | 2012-08-22    | 2017-12-10 | "Scratchy" |
    | "Jack Svensson"  | 2012-08-22    | 2018-08-25 | "Pale"     |
    | "Jack Svensson"  | 2012-08-22    | 2017-12-10 | "Scratchy" |
    | "Jack Svensson"  | 2012-08-22    | 2018-12-07 | "Swollen"  |
    | "Jack Svensson"  | 2012-08-22    | 2018-08-25 | "Pale"     |
    | "Jack Svensson"  | 2012-08-22    | 2018-04-30 | "Red"      |
    | "Mary Smith"     | 2002-11-27    | 2018-07-26 | "Red"      |
    | "Mary Smith"     | 2002-11-27    | 2018-04-09 | "Dizzy"    |
    | "Mary Smith"     | 2002-11-27    | 2018-08-08 | "Pale"     |
    | "Mary Smith"     | 2002-11-27    | 2018-08-28 | "Sore"     |
    | "Mary Smith"     | 2002-11-27    | 2018-07-26 | "Red"      |
    | "Mary Smith"     | 2002-11-27    | 2019-09-16 | "Itchy"    |
    | "Sally Stone"    | 2001-04-25    | 2018-02-13 | "Sore"     |
    | "Sally Stone"    | 2001-04-25    | 2019-05-03 | "Itchy"    |
    | "Sally Stone"    | 2001-04-25    | 2019-09-25 | "Dizzy"    |
    | "Sally Stone"    | 2001-04-25    | 2018-05-10 | "Inflamed" |
    | "Sally Stone"    | 2001-04-25    | 2019-09-03 | "Scratchy" |
    | "Sally Stone"    | 2001-04-25    | 2018-05-10 | "Inflamed" |
    | "Mark Anderson"  | 2007-06-19    | 2019-04-22 | "Angry"    |
    | "Mark Anderson"  | 2007-06-19    | 2018-09-23 | "Scratchy" |
    | "Mark Anderson"  | 2007-06-19    | 2019-03-10 | "Pale"     |
    | "Mark Anderson"  | 2007-06-19    | 2019-03-10 | "Pale"     |
    | "Mark Anderson"  | 2007-06-19    | 2018-09-23 | "Scratchy" |
    | "Mark Anderson"  | 2007-06-19    | 2017-11-16 | "Sad"      |
    | "Joe Jackson"    | 1991-10-12    | 2018-06-27 | "Red"      |
    | "Joe Jackson"    | 1991-10-12    | 2018-10-26 | "Pale"     |
    | "Joe Jackson"    | 1991-10-12    | 2018-10-30 | "Sore"     |
    | "Joe Jackson"    | 1991-10-12    | 2018-10-30 | "Sore"     |
    | "Joe Jackson"    | 1991-10-12    | 2018-10-26 | "Pale"     |
    | "Joe Jackson"    | 1991-10-12    | 2019-01-06 | "Swollen"  |
    | "Jane Svensson"  | 1982-07-02    | 2019-11-29 | "Red"      |
    | "Jane Svensson"  | 1982-07-02    | 2017-12-07 | "Angry"    |
    | "Jane Svensson"  | 1982-07-02    | 2019-04-05 | "Swollen"  |
    | "Jane Svensson"  | 1982-07-02    | 2019-04-05 | "Swollen"  |
    | "Jane Svensson"  | 1982-07-02    | 2018-12-10 | "Sad"      |
    | "Jane Svensson"  | 1982-07-02    | 2019-11-09 | "Inflamed" |
    | "Bob Smith"      | 1981-10-29    | 2018-07-21 | "Sad"      |
    | "Bob Smith"      | 1981-10-29    | 2019-09-15 | "Itchy"    |
    | "Bob Smith"      | 1981-10-29    | 2019-04-18 | "Scratchy" |
    | "Bob Smith"      | 1981-10-29    | 2019-05-12 | "Swollen"  |
    | "Bob Smith"      | 1981-10-29    | 2018-07-21 | "Sad"      |
    | "Bob Smith"      | 1981-10-29    | 2019-02-04 | "Pale"     |
    | "Ally Stone"     | 1980-12-13    | 2018-08-02 | "Red"      |
    | "Ally Stone"     | 1980-12-13    | 2017-09-04 | "Dizzy"    |
    | "Ally Stone"     | 1980-12-13    | 2017-09-04 | "Dizzy"    |
    | "Ally Stone"     | 1980-12-13    | 2017-09-13 | "Pale"     |
    | "Ally Stone"     | 1980-12-13    | 2018-01-21 | "Sad"      |
    | "Ally Stone"     | 1980-12-13    | 2017-09-04 | "Dizzy"    |
    | "Jack Anderson"  | 1998-11-09    | 2019-01-22 | "Swollen"  |
    | "Jack Anderson"  | 1998-11-09    | 2019-07-14 | "Red"      |
    | "Jack Anderson"  | 1998-11-09    | 2019-05-21 | "Inflamed" |
    | "Jack Anderson"  | 1998-11-09    | 2019-05-21 | "Inflamed" |
    | "Jack Anderson"  | 1998-11-09    | 2019-06-18 | "Itchy"    |
    | "Jack Anderson"  | 1998-11-09    | 2019-01-22 | "Swollen"  |
    | "Mary Jackson"   | 1974-09-25    | 2018-12-10 | "Itchy"    |
    | "Mary Jackson"   | 1974-09-25    | 2017-10-13 | "Swollen"  |
    | "Mary Jackson"   | 1974-09-25    | 2018-02-26 | "Red"      |
    | "Mary Jackson"   | 1974-09-25    | 2018-01-25 | "Sad"      |
    | "Mary Jackson"   | 1974-09-25    | 2017-08-05 | "Inflamed" |
    | "Mary Jackson"   | 1974-09-25    | 2018-09-22 | "Scratchy" |
    | "Sally Svensson" | 1987-06-05    | 2018-06-23 | "Red"      |
    | "Sally Svensson" | 1987-06-05    | 2017-12-31 | "Sad"      |
    | "Sally Svensson" | 1987-06-05    | 2017-12-25 | "Sore"     |
    | "Sally Svensson" | 1987-06-05    | 2018-08-10 | "Dizzy"    |
    | "Sally Svensson" | 1987-06-05    | 2017-12-31 | "Sad"      |
    | "Sally Svensson" | 1987-06-05    | 2019-10-31 | "Angry"    |
    | "Mark Smith"     | 1991-08-30    | 2019-07-28 | "Swollen"  |
    | "Mark Smith"     | 1991-08-30    | 2019-01-14 | "Itchy"    |
    | "Mark Smith"     | 1991-08-30    | 2018-11-09 | "Sad"      |
    | "Mark Smith"     | 1991-08-30    | 2019-07-28 | "Swollen"  |
    | "Mark Smith"     | 1991-08-30    | 2019-06-09 | "Red"      |
    | "Mark Smith"     | 1991-08-30    | 2017-10-09 | "Scratchy" |
    | "Joe Stone"      | 1999-08-23    | 2017-09-15 | "Itchy"    |
    | "Joe Stone"      | 1999-08-23    | 2019-08-12 | "Dizzy"    |
    | "Joe Stone"      | 1999-08-23    | 2018-12-06 | "Sore"     |
    | "Joe Stone"      | 1999-08-23    | 2018-06-04 | "Swollen"  |
    | "Joe Stone"      | 1999-08-23    | 2019-11-14 | "Inflamed" |
    | "Joe Stone"      | 1999-08-23    | 2019-05-19 | "Scratchy" |
    | "Jane Anderson"  | 1988-07-16    | 2019-08-15 | "Red"      |
    | "Jane Anderson"  | 1988-07-16    | 2018-09-26 | "Sore"     |
    | "Jane Anderson"  | 1988-07-16    | 2018-10-22 | "Pale"     |
    | "Jane Anderson"  | 1988-07-16    | 2018-03-20 | "Inflamed" |
    | "Jane Anderson"  | 1988-07-16    | 2019-05-13 | "Dizzy"    |
    | "Jane Anderson"  | 1988-07-16    | 2019-05-13 | "Dizzy"    |
    | "Bob Jackson"    | 1974-09-23    | 2019-01-07 | "Sore"     |
    | "Bob Jackson"    | 1974-09-23    | 2017-10-13 | "Scratchy" |
    | "Bob Jackson"    | 1974-09-23    | 2019-07-20 | "Swollen"  |
    | "Bob Jackson"    | 1974-09-23    | 2017-11-23 | "Red"      |
    | "Bob Jackson"    | 1974-09-23    | 2019-04-07 | "Sad"      |
    | "Bob Jackson"    | 1974-09-23    | 2019-08-23 | "Itchy"    |
    | "Ally Svensson"  | 2006-11-13    | 2018-07-22 | "Pale"     |
    | "Ally Svensson"  | 2006-11-13    | 2018-10-13 | "Itchy"    |
    | "Ally Svensson"  | 2006-11-13    | 2017-10-07 | "Sad"      |
    | "Ally Svensson"  | 2006-11-13    | 2018-10-13 | "Itchy"    |
    | "Ally Svensson"  | 2006-11-13    | 2018-06-20 | "Dizzy"    |
    | "Ally Svensson"  | 2006-11-13    | 2019-10-08 | "Scratchy" |
    | "Jack Smith"     | 2017-05-17    | 2018-03-20 | "Red"      |
    | "Jack Smith"     | 2017-05-17    | 2019-01-13 | "Swollen"  |
    | "Jack Smith"     | 2017-05-17    | 2018-08-06 | "Itchy"    |
    | "Jack Smith"     | 2017-05-17    | 2018-07-18 | "Scratchy" |
    | "Jack Smith"     | 2017-05-17    | 2018-06-10 | "Sore"     |
    | "Jack Smith"     | 2017-05-17    | 2018-03-20 | "Red"      |
    | "Mary Stone"     | 2011-06-20    | 2019-02-07 | "Pale"     |
    | "Mary Stone"     | 2011-06-20    | 2018-12-07 | "Itchy"    |
    | "Mary Stone"     | 2011-06-20    | 2019-09-17 | "Scratchy" |
    | "Mary Stone"     | 2011-06-20    | 2017-08-02 | "Sore"     |
    | "Mary Stone"     | 2011-06-20    | 2019-09-17 | "Scratchy" |
    | "Mary Stone"     | 2011-06-20    | 2019-02-07 | "Pale"     |
    | "Sally Anderson" | 1970-12-02    | 2018-10-20 | "Swollen"  |
    | "Sally Anderson" | 1970-12-02    | 2019-02-05 | "Scratchy" |
    | "Sally Anderson" | 1970-12-02    | 2019-11-12 | "Pale"     |
    | "Sally Anderson" | 1970-12-02    | 2018-03-21 | "Angry"    |
    | "Sally Anderson" | 1970-12-02    | 2019-07-21 | "Inflamed" |
    | "Sally Anderson" | 1970-12-02    | 2019-07-21 | "Inflamed" |
    | "Mark Jackson"   | 2003-07-09    | 2018-12-20 | "Sore"     |
    | "Mark Jackson"   | 2003-07-09    | 2018-04-13 | "Itchy"    |
    | "Mark Jackson"   | 2003-07-09    | 2018-11-08 | "Inflamed" |
    | "Mark Jackson"   | 2003-07-09    | 2019-09-17 | "Swollen"  |
    | "Mark Jackson"   | 2003-07-09    | 2018-04-11 | "Dizzy"    |
    | "Mark Jackson"   | 2003-07-09    | 2018-12-20 | "Sore"     |
    | "Joe Svensson"   | 2000-03-07    | 2019-01-31 | "Angry"    |
    | "Joe Svensson"   | 2000-03-07    | 2018-03-29 | "Sore"     |
    | "Joe Svensson"   | 2000-03-07    | 2019-10-26 | "Pale"     |
    | "Joe Svensson"   | 2000-03-07    | 2019-01-31 | "Angry"    |
    | "Joe Svensson"   | 2000-03-07    | 2018-01-01 | "Scratchy" |
    | "Joe Svensson"   | 2000-03-07    | 2018-03-29 | "Sore"     |
    | "Jane Smith"     | 2012-05-14    | 2019-03-18 | "Pale"     |
    | "Jane Smith"     | 2012-05-14    | 2018-08-15 | "Swollen"  |
    | "Jane Smith"     | 2012-05-14    | 2018-01-16 | "Sore"     |
    | "Jane Smith"     | 2012-05-14    | 2018-03-14 | "Scratchy" |
    | "Jane Smith"     | 2012-05-14    | 2018-05-23 | "Inflamed" |
    | "Jane Smith"     | 2012-05-14    | 2019-07-06 | "Red"      |
    | "Bob Stone"      | 2011-06-07    | 2018-03-12 | "Itchy"    |
    | "Bob Stone"      | 2011-06-07    | 2018-05-20 | "Sad"      |
    | "Bob Stone"      | 2011-06-07    | 2017-08-12 | "Red"      |
    | "Bob Stone"      | 2011-06-07    | 2018-01-13 | "Swollen"  |
    | "Bob Stone"      | 2011-06-07    | 2019-01-13 | "Angry"    |
    | "Bob Stone"      | 2011-06-07    | 2018-03-12 | "Itchy"    |
    | "Ally Anderson"  | 1972-05-20    | 2018-09-27 | "Pale"     |
    | "Ally Anderson"  | 1972-05-20    | 2017-08-11 | "Inflamed" |
    | "Ally Anderson"  | 1972-05-20    | 2017-08-23 | "Sad"      |
    | "Ally Anderson"  | 1972-05-20    | 2019-06-09 | "Dizzy"    |
    | "Ally Anderson"  | 1972-05-20    | 2018-10-08 | "Scratchy" |
    | "Ally Anderson"  | 1972-05-20    | 2018-06-13 | "Swollen"  |
    | "Jack Jackson"   | 1985-09-11    | 2019-01-06 | "Red"      |
    | "Jack Jackson"   | 1985-09-11    | 2018-02-05 | "Sore"     |
    | "Jack Jackson"   | 1985-09-11    | 2018-09-10 | "Scratchy" |
    | "Jack Jackson"   | 1985-09-11    | 2019-10-17 | "Dizzy"    |
    | "Jack Jackson"   | 1985-09-11    | 2018-07-07 | "Angry"    |
    | "Jack Jackson"   | 1985-09-11    | 2018-02-05 | "Sore"     |
    | "Mary Svensson"  | 1987-09-18    | 2018-08-06 | "Red"      |
    | "Mary Svensson"  | 1987-09-18    | 2018-03-03 | "Scratchy" |
    | "Mary Svensson"  | 1987-09-18    | 2018-10-13 | "Sad"      |
    | "Mary Svensson"  | 1987-09-18    | 2019-02-03 | "Sore"     |
    | "Mary Svensson"  | 1987-09-18    | 2018-08-06 | "Red"      |
    | "Mary Svensson"  | 1987-09-18    | 2018-08-06 | "Red"      |
    | "Sally Smith"    | 2005-07-05    | 2018-05-26 | "Dizzy"    |
    | "Sally Smith"    | 2005-07-05    | 2018-11-02 | "Sad"      |
    | "Sally Smith"    | 2005-07-05    | 2018-05-26 | "Dizzy"    |
    | "Sally Smith"    | 2005-07-05    | 2017-10-26 | "Inflamed" |
    | "Sally Smith"    | 2005-07-05    | 2018-07-24 | "Angry"    |
    | "Sally Smith"    | 2005-07-05    | 2018-05-26 | "Dizzy"    |
    | "Mark Stone"     | 2011-01-01    | 2019-01-24 | "Red"      |
    | "Mark Stone"     | 2011-01-01    | 2018-02-26 | "Scratchy" |
    | "Mark Stone"     | 2011-01-01    | 2018-11-11 | "Swollen"  |
    | "Mark Stone"     | 2011-01-01    | 2017-12-16 | "Sore"     |
    | "Mark Stone"     | 2011-01-01    | 2018-02-26 | "Scratchy" |
    | "Mark Stone"     | 2011-01-01    | 2019-09-13 | "Sad"      |
    | "Joe Anderson"   | 1981-12-16    | 2017-11-29 | "Pale"     |
    | "Joe Anderson"   | 1981-12-16    | 2018-12-13 | "Dizzy"    |
    | "Joe Anderson"   | 1981-12-16    | 2018-06-05 | "Swollen"  |
    | "Joe Anderson"   | 1981-12-16    | 2018-09-27 | "Sad"      |
    | "Joe Anderson"   | 1981-12-16    | 2017-09-12 | "Inflamed" |
    | "Joe Anderson"   | 1981-12-16    | 2019-10-10 | "Sore"     |
    | "Jane Jackson"   | 1989-10-16    | 2019-04-22 | "Dizzy"    |
    | "Jane Jackson"   | 1989-10-16    | 2019-04-30 | "Swollen"  |
    | "Jane Jackson"   | 1989-10-16    | 2018-04-19 | "Red"      |
    | "Jane Jackson"   | 1989-10-16    | 2018-09-28 | "Inflamed" |
    | "Jane Jackson"   | 1989-10-16    | 2019-07-19 | "Scratchy" |
    | "Jane Jackson"   | 1989-10-16    | 2018-05-19 | "Sad"      |
    | "Bob Svensson"   | 2003-05-06    | 2019-11-05 | "Sore"     |
    | "Bob Svensson"   | 2003-05-06    | 2018-08-09 | "Scratchy" |
    | "Bob Svensson"   | 2003-05-06    | 2018-11-22 | "Inflamed" |
    | "Bob Svensson"   | 2003-05-06    | 2018-02-14 | "Angry"    |
    | "Bob Svensson"   | 2003-05-06    | 2018-11-22 | "Inflamed" |
    | "Bob Svensson"   | 2003-05-06    | 2018-02-25 | "Itchy"    |
    | "Ally Smith"     | 1979-08-06    | 2019-10-25 | "Pale"     |
    | "Ally Smith"     | 1979-08-06    | 2019-11-25 | "Sore"     |
    | "Ally Smith"     | 1979-08-06    | 2019-10-19 | "Dizzy"    |
    | "Ally Smith"     | 1979-08-06    | 2018-01-06 | "Sad"      |
    | "Ally Smith"     | 1979-08-06    | 2019-03-12 | "Red"      |
    | "Ally Smith"     | 1979-08-06    | 2019-05-25 | "Itchy"    |
    | "Jack Stone"     | 2003-12-08    | 2019-04-29 | "Swollen"  |
    | "Jack Stone"     | 2003-12-08    | 2018-09-02 | "Scratchy" |
    | "Jack Stone"     | 2003-12-08    | 2019-07-06 | "Itchy"    |
    | "Jack Stone"     | 2003-12-08    | 2019-07-06 | "Itchy"    |
    | "Jack Stone"     | 2003-12-08    | 2018-04-16 | "Pale"     |
    | "Jack Stone"     | 2003-12-08    | 2018-02-10 | "Sore"     |
    | "Mary Anderson"  | 1974-07-22    | 2018-06-08 | "Dizzy"    |
    | "Mary Anderson"  | 1974-07-22    | 2018-06-08 | "Dizzy"    |
    | "Mary Anderson"  | 1974-07-22    | 2019-12-02 | "Pale"     |
    | "Mary Anderson"  | 1974-07-22    | 2018-09-08 | "Angry"    |
    | "Mary Anderson"  | 1974-07-22    | 2018-07-05 | "Swollen"  |
    | "Mary Anderson"  | 1974-07-22    | 2018-03-08 | "Itchy"    |
    | "Sally Jackson"  | 1994-02-20    | 2019-07-19 | "Dizzy"    |
    | "Sally Jackson"  | 1994-02-20    | 2019-06-29 | "Pale"     |
    | "Sally Jackson"  | 1994-02-20    | 2019-06-14 | "Angry"    |
    | "Sally Jackson"  | 1994-02-20    | 2018-07-27 | "Red"      |
    | "Sally Jackson"  | 1994-02-20    | 2019-01-21 | "Sad"      |
    | "Sally Jackson"  | 1994-02-20    | 2018-10-25 | "Swollen"  |
    | "Mark Svensson"  | 1985-09-07    | 2018-01-06 | "Inflamed" |
    | "Mark Svensson"  | 1985-09-07    | 2018-01-06 | "Inflamed" |
    | "Mark Svensson"  | 1985-09-07    | 2019-04-04 | "Red"      |
    | "Mark Svensson"  | 1985-09-07    | 2018-04-02 | "Angry"    |
    | "Mark Svensson"  | 1985-09-07    | 2018-11-12 | "Itchy"    |
    | "Mark Svensson"  | 1985-09-07    | 2018-11-12 | "Itchy"    |
    | "Joe Smith"      | 1980-06-17    | 2018-10-23 | "Sore"     |
    | "Joe Smith"      | 1980-06-17    | 2018-03-19 | "Angry"    |
    | "Joe Smith"      | 1980-06-17    | 2018-03-19 | "Angry"    |
    | "Joe Smith"      | 1980-06-17    | 2019-02-12 | "Itchy"    |
    | "Joe Smith"      | 1980-06-17    | 2019-02-12 | "Itchy"    |
    | "Joe Smith"      | 1980-06-17    | 2019-09-17 | "Pale"     |
    | "Jane Stone"     | 2015-11-26    | 2019-04-27 | "Scratchy" |
    | "Jane Stone"     | 2015-11-26    | 2017-09-21 | "Itchy"    |
    | "Jane Stone"     | 2015-11-26    | 2017-07-18 | "Inflamed" |
    | "Jane Stone"     | 2015-11-26    | 2018-04-05 | "Pale"     |
    | "Jane Stone"     | 2015-11-26    | 2017-07-18 | "Inflamed" |
    | "Jane Stone"     | 2015-11-26    | 2019-01-12 | "Swollen"  |
    | "Bob Anderson"   | 2007-02-06    | 2018-08-16 | "Itchy"    |
    | "Bob Anderson"   | 2007-02-06    | 2019-08-23 | "Inflamed" |
    | "Bob Anderson"   | 2007-02-06    | 2018-08-31 | "Dizzy"    |
    | "Bob Anderson"   | 2007-02-06    | 2019-01-16 | "Sore"     |
    | "Bob Anderson"   | 2007-02-06    | 2018-08-31 | "Dizzy"    |
    | "Bob Anderson"   | 2007-02-06    | 2018-02-14 | "Angry"    |
    | "Ally Jackson"   | 1997-12-29    | 2018-03-10 | "Pale"     |
    | "Ally Jackson"   | 1997-12-29    | 2019-11-21 | "Red"      |
    | "Ally Jackson"   | 1997-12-29    | 2018-03-10 | "Pale"     |
    | "Ally Jackson"   | 1997-12-29    | 2019-11-21 | "Red"      |
    | "Ally Jackson"   | 1997-12-29    | 2018-09-20 | "Dizzy"    |
    | "Ally Jackson"   | 1997-12-29    | 2018-03-12 | "Itchy"    |
    | "Jack Svensson"  | 1974-04-26    | 2018-07-04 | "Sore"     |
    | "Jack Svensson"  | 1974-04-26    | 2019-06-15 | "Angry"    |
    | "Jack Svensson"  | 1974-04-26    | 2019-09-04 | "Inflamed" |
    | "Jack Svensson"  | 1974-04-26    | 2017-08-12 | "Swollen"  |
    | "Jack Svensson"  | 1974-04-26    | 2018-07-04 | "Sore"     |
    | "Jack Svensson"  | 1974-04-26    | 2019-11-06 | "Itchy"    |
    | "Mary Smith"     | 2007-06-30    | 2018-06-13 | "Sad"      |
    | "Mary Smith"     | 2007-06-30    | 2019-06-21 | "Itchy"    |
    | "Mary Smith"     | 2007-06-30    | 2019-02-04 | "Dizzy"    |
    | "Mary Smith"     | 2007-06-30    | 2018-03-15 | "Angry"    |
    | "Mary Smith"     | 2007-06-30    | 2018-03-15 | "Angry"    |
    | "Mary Smith"     | 2007-06-30    | 2018-12-07 | "Sore"     |
    | "Sally Stone"    | 1999-06-21    | 2018-01-05 | "Sore"     |
    | "Sally Stone"    | 1999-06-21    | 2018-02-19 | "Angry"    |
    | "Sally Stone"    | 1999-06-21    | 2018-01-05 | "Sore"     |
    | "Sally Stone"    | 1999-06-21    | 2018-01-05 | "Sore"     |
    | "Sally Stone"    | 1999-06-21    | 2018-04-08 | "Scratchy" |
    | "Sally Stone"    | 1999-06-21    | 2018-01-18 | "Dizzy"    |
    | "Mark Anderson"  | 1995-09-26    | 2018-03-04 | "Scratchy" |
    | "Mark Anderson"  | 1995-09-26    | 2018-10-14 | "Sad"      |
    | "Mark Anderson"  | 1995-09-26    | 2019-05-16 | "Pale"     |
    | "Mark Anderson"  | 1995-09-26    | 2017-12-09 | "Swollen"  |
    | "Mark Anderson"  | 1995-09-26    | 2019-04-17 | "Inflamed" |
    | "Mark Anderson"  | 1995-09-26    | 2019-05-16 | "Pale"     |
    | "Joe Jackson"    | 1973-06-05    | 2019-01-03 | "Scratchy" |
    | "Joe Jackson"    | 1973-06-05    | 2018-08-29 | "Itchy"    |
    | "Joe Jackson"    | 1973-06-05    | 2019-07-06 | "Angry"    |
    | "Joe Jackson"    | 1973-06-05    | 2018-08-29 | "Itchy"    |
    | "Joe Jackson"    | 1973-06-05    | 2018-04-21 | "Dizzy"    |
    | "Joe Jackson"    | 1973-06-05    | 2018-06-21 | "Sore"     |
    | "Jane Svensson"  | 1970-05-24    | 2018-05-03 | "Sore"     |
    | "Jane Svensson"  | 1970-05-24    | 2019-02-12 | "Inflamed" |
    | "Jane Svensson"  | 1970-05-24    | 2018-04-18 | "Angry"    |
    | "Jane Svensson"  | 1970-05-24    | 2019-04-12 | "Swollen"  |
    | "Jane Svensson"  | 1970-05-24    | 2018-12-08 | "Red"      |
    | "Jane Svensson"  | 1970-05-24    | 2017-11-17 | "Itchy"    |
    | "Bob Smith"      | 2014-07-07    | 2018-04-05 | "Dizzy"    |
    | "Bob Smith"      | 2014-07-07    | 2018-01-21 | "Red"      |
    | "Bob Smith"      | 2014-07-07    | 2018-04-05 | "Dizzy"    |
    | "Bob Smith"      | 2014-07-07    | 2018-04-05 | "Dizzy"    |
    | "Bob Smith"      | 2014-07-07    | 2018-02-04 | "Sad"      |
    | "Bob Smith"      | 2014-07-07    | 2019-05-01 | "Pale"     |
    | "Ally Stone"     | 1994-08-11    | 2017-10-17 | "Inflamed" |
    | "Ally Stone"     | 1994-08-11    | 2017-08-20 | "Red"      |
    | "Ally Stone"     | 1994-08-11    | 2017-10-17 | "Inflamed" |
    | "Ally Stone"     | 1994-08-11    | 2019-03-15 | "Angry"    |
    | "Ally Stone"     | 1994-08-11    | 2019-03-15 | "Angry"    |
    | "Ally Stone"     | 1994-08-11    | 2018-08-26 | "Swollen"  |
    | "Jack Anderson"  | 1994-08-22    | 2017-09-25 | "Inflamed" |
    | "Jack Anderson"  | 1994-08-22    | 2019-10-18 | "Sad"      |
    | "Jack Anderson"  | 1994-08-22    | 2018-11-12 | "Swollen"  |
    | "Jack Anderson"  | 1994-08-22    | 2019-10-18 | "Sad"      |
    | "Jack Anderson"  | 1994-08-22    | 2018-11-12 | "Swollen"  |
    | "Jack Anderson"  | 1994-08-22    | 2018-09-29 | "Sore"     |
    | "Mary Jackson"   | 1993-02-17    | 2017-07-18 | "Scratchy" |
    | "Mary Jackson"   | 1993-02-17    | 2019-09-15 | "Red"      |
    | "Mary Jackson"   | 1993-02-17    | 2018-05-28 | "Itchy"    |
    | "Mary Jackson"   | 1993-02-17    | 2018-05-28 | "Itchy"    |
    | "Mary Jackson"   | 1993-02-17    | 2018-09-28 | "Inflamed" |
    | "Mary Jackson"   | 1993-02-17    | 2017-08-19 | "Sad"      |
    | "Sally Svensson" | 2015-04-19    | 2017-11-15 | "Sad"      |
    | "Sally Svensson" | 2015-04-19    | 2018-07-30 | "Sore"     |
    | "Sally Svensson" | 2015-04-19    | 2017-11-15 | "Sad"      |
    | "Sally Svensson" | 2015-04-19    | 2018-10-05 | "Pale"     |
    | "Sally Svensson" | 2015-04-19    | 2019-06-14 | "Dizzy"    |
    | "Sally Svensson" | 2015-04-19    | 2018-03-09 | "Scratchy" |
    | "Mark Smith"     | 2012-08-01    | 2018-09-27 | "Swollen"  |
    | "Mark Smith"     | 2012-08-01    | 2018-06-25 | "Angry"    |
    | "Mark Smith"     | 2012-08-01    | 2019-01-08 | "Sore"     |
    | "Mark Smith"     | 2012-08-01    | 2018-09-20 | "Pale"     |
    | "Mark Smith"     | 2012-08-01    | 2019-09-30 | "Scratchy" |
    | "Mark Smith"     | 2012-08-01    | 2018-09-20 | "Pale"     |
    | "Joe Stone"      | 2003-12-31    | 2018-01-29 | "Sore"     |
    | "Joe Stone"      | 2003-12-31    | 2017-10-01 | "Angry"    |
    | "Joe Stone"      | 2003-12-31    | 2019-07-16 | "Scratchy" |
    | "Joe Stone"      | 2003-12-31    | 2018-03-03 | "Red"      |
    | "Joe Stone"      | 2003-12-31    | 2017-10-14 | "Dizzy"    |
    | "Joe Stone"      | 2003-12-31    | 2017-08-18 | "Pale"     |
    | "Jane Anderson"  | 2010-06-04    | 2019-12-02 | "Sore"     |
    | "Jane Anderson"  | 2010-06-04    | 2018-03-24 | "Scratchy" |
    | "Jane Anderson"  | 2010-06-04    | 2018-07-20 | "Sad"      |
    | "Jane Anderson"  | 2010-06-04    | 2019-06-17 | "Swollen"  |
    | "Jane Anderson"  | 2010-06-04    | 2018-12-21 | "Red"      |
    | "Jane Anderson"  | 2010-06-04    | 2019-12-02 | "Sore"     |
    | "Bob Jackson"    | 1979-11-07    | 2018-05-03 | "Sore"     |
    | "Bob Jackson"    | 1979-11-07    | 2018-04-20 | "Angry"    |
    | "Bob Jackson"    | 1979-11-07    | 2018-05-10 | "Pale"     |
    | "Bob Jackson"    | 1979-11-07    | 2018-02-09 | "Swollen"  |
    | "Bob Jackson"    | 1979-11-07    | 2019-10-14 | "Scratchy" |
    | "Bob Jackson"    | 1979-11-07    | 2018-04-23 | "Dizzy"    |
    | "Ally Svensson"  | 2004-12-14    | 2019-03-13 | "Scratchy" |
    | "Ally Svensson"  | 2004-12-14    | 2019-03-13 | "Scratchy" |
    | "Ally Svensson"  | 2004-12-14    | 2018-02-22 | "Inflamed" |
    | "Ally Svensson"  | 2004-12-14    | 2018-05-16 | "Dizzy"    |
    | "Ally Svensson"  | 2004-12-14    | 2018-07-09 | "Pale"     |
    | "Ally Svensson"  | 2004-12-14    | 2019-04-30 | "Itchy"    |
    | "Jack Smith"     | 2010-09-23    | 2018-11-27 | "Angry"    |
    | "Jack Smith"     | 2010-09-23    | 2018-04-18 | "Pale"     |
    | "Jack Smith"     | 2010-09-23    | 2019-03-05 | "Itchy"    |
    | "Jack Smith"     | 2010-09-23    | 2018-09-29 | "Sore"     |
    | "Jack Smith"     | 2010-09-23    | 2019-02-08 | "Red"      |
    | "Jack Smith"     | 2010-09-23    | 2019-02-22 | "Sad"      |
    | "Mary Stone"     | 2009-07-14    | 2017-11-22 | "Pale"     |
    | "Mary Stone"     | 2009-07-14    | 2018-09-21 | "Scratchy" |
    | "Mary Stone"     | 2009-07-14    | 2018-09-30 | "Angry"    |
    | "Mary Stone"     | 2009-07-14    | 2019-06-17 | "Itchy"    |
    | "Mary Stone"     | 2009-07-14    | 2017-11-22 | "Pale"     |
    | "Mary Stone"     | 2009-07-14    | 2019-08-14 | "Sore"     |
    | "Sally Anderson" | 1972-01-23    | 2017-09-13 | "Dizzy"    |
    | "Sally Anderson" | 1972-01-23    | 2018-09-09 | "Itchy"    |
    | "Sally Anderson" | 1972-01-23    | 2018-06-23 | "Sad"      |
    | "Sally Anderson" | 1972-01-23    | 2018-06-23 | "Sad"      |
    | "Sally Anderson" | 1972-01-23    | 2019-12-03 | "Sore"     |
    | "Sally Anderson" | 1972-01-23    | 2019-12-03 | "Sore"     |
    | "Mark Jackson"   | 2006-12-17    | 2018-08-02 | "Scratchy" |
    | "Mark Jackson"   | 2006-12-17    | 2018-01-28 | "Sore"     |
    | "Mark Jackson"   | 2006-12-17    | 2018-08-02 | "Scratchy" |
    | "Mark Jackson"   | 2006-12-17    | 2018-05-26 | "Itchy"    |
    | "Mark Jackson"   | 2006-12-17    | 2017-11-27 | "Sad"      |
    | "Mark Jackson"   | 2006-12-17    | 2017-07-17 | "Red"      |
    | "Joe Svensson"   | 2001-01-14    | 2019-02-20 | "Dizzy"    |
    | "Joe Svensson"   | 2001-01-14    | 2018-07-12 | "Angry"    |
    | "Joe Svensson"   | 2001-01-14    | 2018-08-08 | "Itchy"    |
    | "Joe Svensson"   | 2001-01-14    | 2018-03-30 | "Pale"     |
    | "Joe Svensson"   | 2001-01-14    | 2019-02-20 | "Dizzy"    |
    | "Joe Svensson"   | 2001-01-14    | 2018-03-30 | "Pale"     |
    | "Jane Smith"     | 1992-03-12    | 2017-10-07 | "Dizzy"    |
    | "Jane Smith"     | 1992-03-12    | 2019-03-07 | "Inflamed" |
    | "Jane Smith"     | 1992-03-12    | 2019-05-30 | "Red"      |
    | "Jane Smith"     | 1992-03-12    | 2017-07-15 | "Pale"     |
    | "Jane Smith"     | 1992-03-12    | 2019-04-14 | "Sore"     |
    | "Jane Smith"     | 1992-03-12    | 2019-09-30 | "Angry"    |
    | "Bob Stone"      | 2015-09-07    | 2018-09-11 | "Sore"     |
    | "Bob Stone"      | 2015-09-07    | 2018-03-19 | "Dizzy"    |
    | "Bob Stone"      | 2015-09-07    | 2019-01-01 | "Scratchy" |
    | "Bob Stone"      | 2015-09-07    | 2019-01-01 | "Scratchy" |
    | "Bob Stone"      | 2015-09-07    | 2017-12-27 | "Sad"      |
    | "Bob Stone"      | 2015-09-07    | 2019-01-01 | "Scratchy" |
    | "Ally Anderson"  | 1978-12-20    | 2018-08-20 | "Inflamed" |
    | "Ally Anderson"  | 1978-12-20    | 2018-03-23 | "Sad"      |
    | "Ally Anderson"  | 1978-12-20    | 2017-09-05 | "Itchy"    |
    | "Ally Anderson"  | 1978-12-20    | 2018-01-07 | "Angry"    |
    | "Ally Anderson"  | 1978-12-20    | 2018-02-08 | "Pale"     |
    | "Ally Anderson"  | 1978-12-20    | 2018-02-08 | "Pale"     |
    | "Jack Jackson"   | 1975-06-08    | 2018-10-10 | "Red"      |
    | "Jack Jackson"   | 1975-06-08    | 2019-09-16 | "Pale"     |
    | "Jack Jackson"   | 1975-06-08    | 2019-09-16 | "Pale"     |
    | "Jack Jackson"   | 1975-06-08    | 2019-09-16 | "Pale"     |
    | "Jack Jackson"   | 1975-06-08    | 2019-01-06 | "Angry"    |
    | "Jack Jackson"   | 1975-06-08    | 2018-02-21 | "Scratchy" |
    | "Mary Svensson"  | 2002-01-09    | 2018-09-24 | "Pale"     |
    | "Mary Svensson"  | 2002-01-09    | 2018-03-03 | "Itchy"    |
    | "Mary Svensson"  | 2002-01-09    | 2017-12-29 | "Swollen"  |
    | "Mary Svensson"  | 2002-01-09    | 2019-11-01 | "Sad"      |
    | "Mary Svensson"  | 2002-01-09    | 2018-03-03 | "Itchy"    |
    | "Mary Svensson"  | 2002-01-09    | 2018-03-03 | "Itchy"    |
    | "Sally Smith"    | 1973-12-03    | 2018-01-06 | "Itchy"    |
    | "Sally Smith"    | 1973-12-03    | 2018-01-06 | "Itchy"    |
    | "Sally Smith"    | 1973-12-03    | 2019-02-13 | "Dizzy"    |
    | "Sally Smith"    | 1973-12-03    | 2019-10-21 | "Pale"     |
    | "Sally Smith"    | 1973-12-03    | 2017-10-26 | "Scratchy" |
    | "Sally Smith"    | 1973-12-03    | 2017-12-21 | "Red"      |
    | "Mark Stone"     | 1988-06-07    | 2018-06-07 | "Swollen"  |
    | "Mark Stone"     | 1988-06-07    | 2019-09-06 | "Scratchy" |
    | "Mark Stone"     | 1988-06-07    | 2018-08-09 | "Itchy"    |
    | "Mark Stone"     | 1988-06-07    | 2019-09-06 | "Scratchy" |
    | "Mark Stone"     | 1988-06-07    | 2019-06-12 | "Dizzy"    |
    | "Mark Stone"     | 1988-06-07    | 2019-09-06 | "Scratchy" |
    | "Joe Anderson"   | 2010-10-05    | 2018-01-05 | "Pale"     |
    | "Joe Anderson"   | 2010-10-05    | 2017-12-26 | "Scratchy" |
    | "Joe Anderson"   | 2010-10-05    | 2018-01-05 | "Pale"     |
    | "Joe Anderson"   | 2010-10-05    | 2019-04-11 | "Inflamed" |
    | "Joe Anderson"   | 2010-10-05    | 2019-01-02 | "Sore"     |
    | "Joe Anderson"   | 2010-10-05    | 2019-02-28 | "Dizzy"    |
    +------------------------------------------------------------+
    
    606 rows
    ready to start consuming query after 91 ms, results consumed after another 60 ms
    Created 491 relationships, Set 491 properties

管理授权和访问控制

与通常要求在应用程序本身内建模用户的应用程序不同,数据库提供用户管理资源,如角色和权限。这允许完全在数据库安全模型中创建用户,这种策略允许数据访问与数据本身的分离。有关更多信息,请参阅认证与授权

在本教程中,考虑 healthcare 数据库的五位用户:

  • Alice,医生。

  • Daniel,护士。

  • Bob,接待员。

  • Charlie,研究人员。

  • Tina,IT 管理员。

您可以使用 CREATE USER 命令(从 system 数据库)创建这些用户:

CREATE USER charlie SET PASSWORD 'secretpassword1' CHANGE NOT REQUIRED;
CREATE USER alice SET PASSWORD 'secretpassword2' CHANGE NOT REQUIRED;
CREATE USER daniel SET PASSWORD 'secretpassword3' CHANGE NOT REQUIRED;
CREATE USER bob SET PASSWORD 'secretpassword4' CHANGE NOT REQUIRED;
CREATE USER tina SET PASSWORD 'secretpassword5' CHANGE NOT REQUIRED;

此时,用户无法与数据库交互,因此需要通过角色授予这些能力。有两种不同的方法可以做到这一点:使用内置角色和权限,或者使用具有细粒度权限的更高级资源进行子图访问控制

使用内置角色进行访问控制

Neo4j 附带内置角色,涵盖了许多常见需求:

  • PUBLIC - 所有用户都拥有此角色。他们默认可以访问主数据库、加载数据以及运行所有过程和用户定义函数。

  • reader - 可以从所有数据库读取数据。

  • editor - 可以读取和更新所有数据库,但不能通过新的标签、关系类型或属性名称扩展模式。

  • publisher - 可以读取和编辑,以及添加新的标签、关系类型和属性名称。

  • architect - 拥有出版者的所有能力,以及管理索引和约束的能力。

  • admin - 可以执行架构师操作,以及加载数据和管理数据库、用户、角色和权限。

考虑用户示例中的 Charlie。作为研究人员,他们不需要数据库的写入访问权限,因此分配给他们 reader 角色。

另一方面,Alice(医生)、Daniel(护士)和 Bob(接待员)都需要使用新的患者信息更新数据库,但不需要通过新的标签、关系类型、属性名称或索引来扩展模式。因此,他们都被分配了 editor 角色。

Tina,负责安装和管理数据库的 IT 管理员,需要被分配 admin 角色。

以下是如何向用户授予角色(从 system 数据库):

GRANT ROLE reader TO charlie;
GRANT ROLE editor TO alice;
GRANT ROLE editor TO daniel;
GRANT ROLE editor TO bob;
GRANT ROLE admin TO tina;

使用权限进行子图访问控制

上述方法的局限性在于它允许所有用户查看数据库上的所有数据。然而,在许多实际场景中,最好建立一些访问限制。

例如,您可能希望限制研究人员访问患者的个人信息,或者限制接待员在数据库上写入新标签。虽然这些限制可以编码到应用程序层中,但通过创建自定义角色并为其分配特定权限,直接在 Neo4j 安全模型中强制实施细粒度限制是可能且**更安全**的。

由于将创建新的自定义角色,因此首先撤销已分配给用户的当前角色非常重要。针对 system 数据库运行以下命令:

REVOKE ROLE reader FROM charlie;
REVOKE ROLE editor FROM alice;
REVOKE ROLE editor FROM daniel;
REVOKE ROLE editor FROM bob;
REVOKE ROLE admin FROM tina;

现在,您可以根据*权限*概念创建自定义角色,这允许更精细地控制每个用户可以执行的操作。为了正确分配这些权限,首先确定每种类型的用户:

医生

应该能够读取和写入大部分图,但应阻止其读取患者的地址。拥有将*诊断*保存到数据库的权限,但不能通过新概念扩展模式。

接待员

应该能够读取和写入所有患者数据,但不能查看症状、疾病或诊断。

研究员

应该能够对所有数据进行统计分析,除了患者的个人信息,对此他们应该有受限访问。为了说明设置相同有效权限的两种不同方式,创建了两个角色进行比较。

护士

应该能够执行医生和接待员都能做的所有任务。将两个角色(医生和接待员)都授予护士并不会按预期工作。这将在专门介绍创建 nurse 角色的部分中解释。

初级护士

虽然高级护士可以像医生一样保存诊断,但一些(初级)护士可能不被允许这样做。从头开始创建另一个角色是一个选项,但通过将 nurse 角色与明确限制该活动的新 disableDiagnoses 角色结合,可以达到相同的效果。

IT 管理员

此角色与内置 admin 角色非常相似,不同之处在于它不应允许访问患者的 SSN,也不能保存诊断,该权限仅限于医疗专业人员。为了实现这一点,可以复制内置 admin 角色并进行相应修改。

用户经理

此用户应与 IT 管理员具有相似的访问权限,但限制更多。为了实现这一点,可以从头开始创建一个新角色,并只为其分配特定的管理能力。

在创建新角色并将其分配给 Alice、Bob、Daniel、Charlie 和 Tina 之前,重要的是要定义每个角色应具有的权限。由于所有用户都需要对 healthcare 数据库的 ACCESS 权限,因此可以通过 PUBLIC 角色而不是所有单个角色来设置此权限:

针对 system 数据库运行以下命令:

GRANT ACCESS ON DATABASE healthcare TO PUBLIC;

itadmin 的权限

此角色可以作为内置 admin 角色的副本创建:

CREATE ROLE itadmin AS COPY OF admin;

然后您需要**拒绝**此角色不应执行的两个特定操作:

  • 读取任何患者的社会安全号码(SSN)。

  • 提交医疗诊断。

以及 itadmin 修改自身权限的能力。

DENY READ {ssn} ON GRAPH healthcare NODES Patient TO itadmin;
DENY CREATE ON GRAPH healthcare RELATIONSHIPS DIAGNOSIS TO itadmin;
DENY ROLE MANAGEMENT ON DBMS TO itadmin;
DENY PRIVILEGE MANAGEMENT ON DBMS TO itadmin;

分配给 itadmin 角色的用户可用的完整权限集可以使用以下命令查看:

SHOW ROLE itadmin PRIVILEGES AS COMMANDS;
结果:
+-------------------------------------------------------------------------+
| command                                                                 |
+-------------------------------------------------------------------------+
| "DENY CREATE ON GRAPH `healthcare` RELATIONSHIP DIAGNOSIS TO `itadmin`" |
| "DENY PRIVILEGE MANAGEMENT ON DBMS TO `itadmin`"                        |
| "DENY READ {ssn} ON GRAPH `healthcare` NODE Patient TO `itadmin`"       |
| "DENY ROLE MANAGEMENT ON DBMS TO `itadmin`"                             |
| "GRANT ACCESS ON DATABASE * TO `itadmin`"                               |
| "GRANT ALL DBMS PRIVILEGES ON DBMS TO `itadmin`"                        |
| "GRANT CONSTRAINT MANAGEMENT ON DATABASE * TO `itadmin`"                |
| "GRANT INDEX MANAGEMENT ON DATABASE * TO `itadmin`"                     |
| "GRANT LOAD ON ALL DATA TO `itadmin`"                                   |
| "GRANT MATCH {*} ON GRAPH * NODE * TO `itadmin`"                        |
| "GRANT MATCH {*} ON GRAPH * RELATIONSHIP * TO `itadmin`"                |
| "GRANT NAME MANAGEMENT ON DATABASE * TO `itadmin`"                      |
| "GRANT SHOW CONSTRAINT ON DATABASE * TO `itadmin`"                      |
| "GRANT SHOW INDEX ON DATABASE * TO `itadmin`"                           |
| "GRANT START ON DATABASE * TO `itadmin`"                                |
| "GRANT STOP ON DATABASE * TO `itadmin`"                                 |
| "GRANT TRANSACTION MANAGEMENT (*) ON DATABASE * TO `itadmin`"           |
| "GRANT WRITE ON GRAPH * TO `itadmin`"                                   |
+-------------------------------------------------------------------------+
18 rows
ready to start consuming query after 29 ms, results consumed after another 1 ms

之前授予或拒绝的权限可以使用REVOKE 命令撤销。

要为 IT 管理员 tina 提供这些权限,必须为他们分配新角色 itadmin。针对 system 数据库运行以下命令:

GRANT ROLE itadmin TO tina;

为了演示 Tina 无法查看患者的 SSN,您可以以 tina 身份登录 Cypher Shell,并针对 healthcare 数据库运行以下查询:

MATCH (n:Patient)
 WHERE n.dateOfBirth < date('1972-06-12')
RETURN n.name, n.ssn, n.address, n.dateOfBirth;
结果:
+---------------------------------------------------------------------+
| n.name           | n.ssn | n.address                | n.dateOfBirth |
+---------------------------------------------------------------------+
| "Mark Jackson"   | NULL  | "1 secret way, downtown" | 1970-11-29    |
| "Joe Svensson"   | NULL  | "1 secret way, downtown" | 1972-02-12    |
| "Bob Anderson"   | NULL  | "1 secret way, downtown" | 1970-04-27    |
| "Sally Anderson" | NULL  | "1 secret way, downtown" | 1970-12-02    |
| "Ally Anderson"  | NULL  | "1 secret way, downtown" | 1972-05-20    |
| "Jane Svensson"  | NULL  | "1 secret way, downtown" | 1970-05-24    |
| "Sally Anderson" | NULL  | "1 secret way, downtown" | 1972-01-23    |
+---------------------------------------------------------------------+

7 rows
ready to start consuming query after 49 ms, results consumed after another 2 ms

结果看起来这些节点甚至没有 SSN 字段。这是安全模型的一个关键特性:用户无法区分不存在的数据和使用细粒度读取权限隐藏的数据。

现在回想一下,itadmin 角色被拒绝了保存诊断的能力(因为这是一项仅限于医生和高级医务人员的关键医疗功能),您可以通过尝试创建 DIAGNOSIS 关系来测试这一点:

MATCH (n:Patient), (d:Disease)
CREATE (n)-[:DIAGNOSIS]->(d);
结果:
Create relationship with type 'DIAGNOSIS' on database 'healthcare' is not allowed for user 'tina' with roles [PUBLIC, itadmin].

对读取数据的限制不会导致错误,它们只会让数据看起来不存在。然而,对更新图的限制会在用户尝试执行不允许的操作时输出适当的错误。

researcher 的权限

研究人员 Charlie 之前是一个只读用户。要分配他们所需的权限,您可以做与 itadmin 角色类似的事情,这次是复制和修改 reader 角色。

另一种方法是,从头开始创建一个新角色,然后授予或拒绝一系列权限:

  • 拒绝权限:

    您可以授予角色 researcher 查找所有节点和读取所有属性的能力(很像 reader 角色),但拒绝读取 Patient 属性的权限。这样,研究人员就无法看到患者的信息,如 nameSSNaddress。但是,这种方法存在一个问题:如果*在*将限制分配给 researcher 角色之后向 Patient 节点添加更多属性,这些新属性将自动对研究人员可见——这可能是不希望的结果。

    为了避免这种情况,您可以拒绝*特定*权限,方法是针对 system 数据库运行以下命令。您必须以具有 admin 角色的用户身份登录才能执行这些命令:

    // First create the role
    CREATE ROLE researcherB;
    // Then grant access to everything
    GRANT MATCH {*}
        ON GRAPH healthcare
        TO researcherB;
    // And deny read on specific node properties
    DENY READ {name, address, ssn}
        ON GRAPH healthcare
        NODES Patient
        TO researcherB;
    // And finally deny traversal of the doctors diagnosis
    DENY TRAVERSE
        ON GRAPH healthcare
        RELATIONSHIPS DIAGNOSIS
        TO researcherB;
  • 授予权限:

    另一种选择是只提供研究人员被允许查看的属性的特定访问权限。这样,添加新属性(例如,到 Patient 节点)不会自动使它们对分配了此角色的用户可见。但是,如果您希望它们可见,则需要明确授予读取访问权限。针对 system 数据库运行以下命令。您必须以具有 admin 角色的用户身份登录才能执行这些命令:

    // Create the role first
    CREATE ROLE researcherW
    // Allow the researcher to find all nodes
    GRANT TRAVERSE
        ON GRAPH healthcare
        NODES *
        TO researcherW;
    // Now only allow the researcher to traverse specific relationships
    GRANT TRAVERSE
        ON GRAPH healthcare
        RELATIONSHIPS HAS, OF
        TO researcherW;
    // Allow reading of all properties of medical metadata
    GRANT READ {*}
        ON GRAPH healthcare
        NODES Symptom, Disease
        TO researcherW;
    // Allow reading of all properties of the disease-symptom relationship
    GRANT READ {*}
        ON GRAPH healthcare
        RELATIONSHIPS OF
        TO researcherW;
    // Only allow reading dateOfBirth for research purposes
    GRANT READ {dateOfBirth}
        ON GRAPH healthcare
        NODES Patient
        TO researcherW;

    为了测试研究人员 Charlie 现在拥有指定的权限,为他们分配 researcherB 角色(具有明确拒绝的权限):

    GRANT ROLE researcherB TO charlie;

    您还可以使用 SHOW PRIVILEGES 命令的一个版本来查看 Charlie 的访问权限,这些权限是分配给 researcherBPUBLIC 角色的组合:

    SHOW USER charlie PRIVILEGES AS COMMANDS;
    结果:
    +-----------------------------------------------------------------------+
    | command                                                               |
    +-----------------------------------------------------------------------+
    | "DENY READ {address} ON GRAPH `healthcare` NODE Patient TO $role"     |
    | "DENY READ {name} ON GRAPH `healthcare` NODE Patient TO $role"        |
    | "DENY READ {ssn} ON GRAPH `healthcare` NODE Patient TO $role"         |
    | "DENY TRAVERSE ON GRAPH `healthcare` RELATIONSHIP DIAGNOSIS TO $role" |
    | "GRANT ACCESS ON DATABASE `healthcare` TO $role"                      |
    | "GRANT ACCESS ON HOME DATABASE TO $role"                              |
    | "GRANT EXECUTE FUNCTION * ON DBMS TO $role"                           |
    | "GRANT EXECUTE PROCEDURE * ON DBMS TO $role"                          |
    | "GRANT LOAD ON ALL DATA TO $role"                                     |
    | "GRANT MATCH {*} ON GRAPH `healthcare` NODE * TO $role"               |
    | "GRANT MATCH {*} ON GRAPH `healthcare` RELATIONSHIP * TO $role"       |
    +-----------------------------------------------------------------------+
    
    11 rows
    ready to start consuming query after 17 ms, results consumed after another 2 ms

    现在,当 Charlie 登录到 Cypher Shell 并尝试针对 healthcare 数据库执行以下命令时,即使该命令与之前由 itadmin 使用的命令相似,他们也会看到不同的结果:

    MATCH (n:Patient)
     WHERE n.dateOfBirth < date('1972-06-12')
    RETURN n.name, n.ssn, n.address, n.dateOfBirth;
    结果:
    +--------------------------------------------+
    | n.name | n.ssn | n.address | n.dateOfBirth |
    +--------------------------------------------+
    | NULL   | NULL  | NULL      | 1970-11-29    |
    | NULL   | NULL  | NULL      | 1972-02-12    |
    | NULL   | NULL  | NULL      | 1970-04-27    |
    | NULL   | NULL  | NULL      | 1970-12-02    |
    | NULL   | NULL  | NULL      | 1972-05-20    |
    | NULL   | NULL  | NULL      | 1970-05-24    |
    | NULL   | NULL  | NULL      | 1972-01-23    |
    +--------------------------------------------+
    
    7 rows
    ready to start consuming query after 5 ms, results consumed after another 4 ms

    只有出生日期可用,以便研究人员 Charlie 可以进行统计分析,例如。Charlie 可以尝试的另一个查询是查找 25 岁以下患者最有可能被诊断出的十种疾病,按概率列出:

    WITH datetime() - duration({years:25}) AS timeLimit
    MATCH (n:Patient)
    WHERE n.dateOfBirth > date(timeLimit)
    MATCH (n)-[h:HAS]->(s:Symptom)-[o:OF]->(d:Disease)
    WITH d.name AS disease, o.probability AS prob
    RETURN disease, sum(prob) AS score ORDER BY score DESC LIMIT 10;
    结果:
    +-------------------------------------------+
    | disease               | score             |
    +-------------------------------------------+
    | "Acute Placeboitis"   | 98.08269474672981 |
    | "Chronic Whatitis"    | 92.7601237335886  |
    | "Acute Otheritis"     | 87.61578906815608 |
    | "Chronic Someitis"    | 81.68350008637253 |
    | "Chronic Placeboitis" | 81.18800771016768 |
    | "Acute Argitis"       | 80.94323685188083 |
    | "Chronic Argitis"     | 80.06685163653665 |
    | "Chronic Otheritis"   | 76.06538667789484 |
    | "Acute Yellowitis"    | 70.74589062185173 |
    | "Acute Someitis"      | 70.3238679154795  |
    +-------------------------------------------+
    
    10 rows
    ready to start consuming query after 171 ms, results consumed after another 23 ms

    如果 Charlie 的 researcherB 角色被撤销,但 researcherW 角色被授予,重新运行这些查询时将获得相同的结果。

    之前授予或拒绝的权限可以使用REVOKE 命令撤销。

doctor 的权限

医生应该被授予读取和写入几乎所有内容的权限,除了患者的 address 属性。这个角色可以从头开始构建,通过分配完全的读取和写入访问权限,然后明确拒绝访问 address 属性。切换到 system 数据库并运行以下命令:

CREATE ROLE doctor;
GRANT TRAVERSE ON GRAPH healthcare TO doctor;
GRANT READ {*} ON GRAPH healthcare TO doctor;
GRANT WRITE ON GRAPH healthcare TO doctor;
DENY READ {address} ON GRAPH healthcare NODES Patient TO doctor;
DENY SET PROPERTY {address} ON GRAPH healthcare NODES Patient TO doctor;

为了让医生 Alice 拥有这些权限,授予用户 alice 这个新角色:

GRANT ROLE doctor TO alice;

为了演示 Alice 无法查看患者地址,以 alice 身份登录并针对 healthcare 数据库运行以下查询:

MATCH (n:Patient)
 WHERE n.dateOfBirth < date('1972-06-12')
RETURN n.name, n.ssn, n.address, n.dateOfBirth;
结果:
+--------------------------------------------------------+
| n.name           | n.ssn   | n.address | n.dateOfBirth |
+--------------------------------------------------------+
| "Mark Jackson"   | 1234578 | NULL      | 1970-11-29    |
| "Joe Svensson"   | 1234579 | NULL      | 1972-02-12    |
| "Bob Anderson"   | 1234597 | NULL      | 1970-04-27    |
| "Sally Anderson" | 1234617 | NULL      | 1970-12-02    |
| "Ally Anderson"  | 1234622 | NULL      | 1972-05-20    |
| "Jane Svensson"  | 1234644 | NULL      | 1970-05-24    |
| "Sally Anderson" | 1234657 | NULL      | 1972-01-23    |
+--------------------------------------------------------+

7 rows
ready to start consuming query after 5 ms, results consumed after another 3 ms

结果是,医生拥有预期的权限,包括能够查看患者的 SSN,但不能查看他们的地址。

医生也能够查看所有其他节点类型:

MATCH (n) WITH labels(n) AS labels
RETURN labels, count(*);
结果:
+------------------------+
| labels      | count(*) |
+------------------------+
| ["Symptom"] | 10       |
| ["Disease"] | 12       |
| ["Patient"] | 101      |
+------------------------+

3 rows
ready to start consuming query after 29 ms, results consumed after another 1 ms

此外,医生可以遍历图,查找与患者相关的症状和疾病:

MATCH (n:Patient)-[:HAS]->(s:Symptom)-[:OF]->(d:Disease)
  WHERE n.ssn = 1234657
RETURN n.name, d.name, count(s) AS score ORDER BY score DESC;

结果表显示了根据症状最可能的诊断。医生可以使用此表来促进对患者的进一步询问和测试,以便决定最终诊断。

结果:
+--------------------------------------------------+
| n.name           | d.name                | score |
+--------------------------------------------------+
| "Sally Anderson" | "Acute Placeboitis"   | 4     |
| "Sally Anderson" | "Chronic Argitis"     | 2     |
| "Sally Anderson" | "Acute Argitis"       | 2     |
| "Sally Anderson" | "Acute Otheritis"     | 2     |
| "Sally Anderson" | "Chronic Placeboitis" | 2     |
| "Sally Anderson" | "Acute Yellowitis"    | 2     |
| "Sally Anderson" | "Chronic Whatitis"    | 2     |
| "Sally Anderson" | "Chronic Yellowitis"  | 2     |
| "Sally Anderson" | "Acute Whatitis"      | 1     |
| "Sally Anderson" | "Acute Someitis"      | 1     |
| "Sally Anderson" | "Chronic Someitis"    | 1     |
| "Sally Anderson" | "Chronic Otheritis"   | 1     |
+--------------------------------------------------+

12 rows
ready to start consuming query after 48 ms, results consumed after another 2 ms

一旦医生进一步调查,他们将能够决定诊断并将结果保存到数据库中:

WITH datetime({epochmillis:timestamp()}) AS now
WITH now, date(now) as today
MATCH (p:Patient)
  WHERE p.ssn = 1234657
MATCH (d:Disease)
  WHERE d.name = "Chronic Placeboitis"
MERGE (p)-[i:DIAGNOSIS {by: 'Alice'}]->(d)
  ON CREATE SET i.created_at = now, i.updated_at = now, i.date = today
  ON MATCH SET i.updated_at = now
RETURN p.name, d.name, i.by, i.date, duration.between(i.created_at, i.updated_at) AS updated;

这允许医生记录他们的诊断并记下以前的诊断:

结果:
+---------------------------------------------------------------------------+
| p.name           | d.name                | i.by    | i.date     | updated |
+---------------------------------------------------------------------------+
| "Sally Anderson" | "Chronic Placeboitis" | "Alice" | 2025-02-14 | PT0S    |
+---------------------------------------------------------------------------+

1 row
ready to start consuming query after 73 ms, results consumed after another 6 ms
Created 1 relationships, Set 4 properties

首次创建 DIAGNOSIS 关系需要创建新类型的权限。属性名 doctorcreated_atupdated_at 也是如此。可以通过授予医生 NAME MANAGEMENT 权限或预先创建缺失类型来解决。后者会更精确,并且可以通过以管理员身份运行 db.createRelationshipTypedb.createProperty 过程并带上适当的参数来实现。

receptionist 的权限

接待员应该只能够管理患者信息。他们不被允许查找或读取图的任何其他部分。此外,他们应该能够创建和删除患者,但不能删除任何其他节点。切换到 system 数据库并运行以下命令:

CREATE ROLE receptionist;
GRANT MATCH {*} ON GRAPH healthcare NODES Patient TO receptionist;
GRANT CREATE ON GRAPH healthcare NODES Patient TO receptionist;
GRANT DELETE ON GRAPH healthcare NODES Patient TO receptionist;
GRANT SET PROPERTY {*} ON GRAPH healthcare NODES Patient TO receptionist;

如果授予接待员 Bob 全局 WRITE 权限会更简单。然而,这会带来不幸的副作用,即允许他们创建其他节点,例如新的 Symptom 节点,尽管他们随后无法查找或读取这些相同的节点。虽然存在角色可以创建数据但无法读取的用例,但此模型并非如此。

考虑到这一点,授予接待员 Bob 新的 receptionist 角色:

GRANT ROLE receptionist TO bob;

有了这些权限,如果 Bob 尝试读取整个数据库,他仍然只能看到患者:

MATCH (n) WITH labels(n) AS labels
RETURN labels, count(*);
结果:
+------------------------+
| labels      | count(*) |
+------------------------+
| ["Patient"] | 101      |
+------------------------+

1 row
ready to start consuming query after 2 ms, results consumed after another 3 ms

然而,Bob 能够查看患者记录的所有字段:

MATCH (n:Patient)
 WHERE n.dateOfBirth < date('1972-06-12')
RETURN n.name, n.ssn, n.address, n.dateOfBirth;
结果:
+-----------------------------------------------------------------------+
| n.name           | n.ssn   | n.address                | n.dateOfBirth |
+-----------------------------------------------------------------------+
| "Mark Jackson"   | 1234578 | "1 secret way, downtown" | 1970-11-29    |
| "Joe Svensson"   | 1234579 | "1 secret way, downtown" | 1972-02-12    |
| "Bob Anderson"   | 1234597 | "1 secret way, downtown" | 1970-04-27    |
| "Sally Anderson" | 1234617 | "1 secret way, downtown" | 1970-12-02    |
| "Ally Anderson"  | 1234622 | "1 secret way, downtown" | 1972-05-20    |
| "Jane Svensson"  | 1234644 | "1 secret way, downtown" | 1970-05-24    |
| "Sally Anderson" | 1234657 | "1 secret way, downtown" | 1972-01-23    |
+-----------------------------------------------------------------------+

7 rows
ready to start consuming query after 2 ms, results consumed after another 1 ms

使用 receptionist 角色,Bob 可以删除他们刚刚创建的任何新患者节点,但他们无法删除已经收到诊断的患者,因为这些患者连接到 Bob 无法看到的图的部分。以下是两种情况的演示:

CREATE (n:Patient {
  ssn:87654321,
  name: 'Another Patient',
  email: 'another@example.com',
  address: '1 secret way, downtown',
  dateOfBirth: date('2001-01-20')
})
RETURN n.name, n.dateOfBirth;
结果:
+-----------------------------------+
| n.name            | n.dateOfBirth |
+-----------------------------------+
| "Another Patient" | 2001-01-20    |
+-----------------------------------+

1 row
ready to start consuming query after 36 ms, results consumed after another 1 ms
Added 1 nodes, Set 5 properties, Added 1 labels

接待员能够修改任何患者记录:

MATCH (n:Patient)
WHERE n.ssn = 87654321
SET n.address = '2 streets down, uptown'
RETURN n.name, n.dateOfBirth, n.address;
结果:
+--------------------------------------------------------------+
| n.name            | n.dateOfBirth | n.address                |
+--------------------------------------------------------------+
| "Another Patient" | 2001-01-20    | "2 streets down, uptown" |
+--------------------------------------------------------------+

1 row
ready to start consuming query after 22 ms, results consumed after another 3 ms
Set 1 properties

接待员也能够删除最近创建的这个患者,因为它没有连接到任何其他记录:

MATCH (n:Patient)
 WHERE n.ssn = 87654321
DETACH DELETE n;
结果:
0 rows
ready to start consuming query after 17 ms, results consumed after another 0 ms
Deleted 1 nodes

然而,如果接待员尝试删除具有现有诊断的患者,这将失败:

MATCH (n:Patient)
 WHERE n.ssn = 1234610
DETACH DELETE n;
结果:
Cannot delete node<65>, because it still has relationships. To delete this node, you must first delete its relationships.

此查询失败的原因是,虽然 Bob 可以找到 (:Patient) 节点,但他没有足够的遍历权限来查找,也没有删除其传出关系的权限。

他们要么需要向 IT 管理员 Tina 寻求帮助,要么可以向 receptionist 角色添加更多权限。切换到 system 数据库并运行以下命令:

GRANT TRAVERSE ON GRAPH healthcare NODES Symptom, Disease TO receptionist;
GRANT TRAVERSE ON GRAPH healthcare RELATIONSHIPS HAS, DIAGNOSIS TO receptionist;
GRANT DELETE ON GRAPH healthcare RELATIONSHIPS HAS, DIAGNOSIS TO receptionist;

之前授予或拒绝的权限可以使用REVOKE 命令撤销。

nurse 的权限

护士应该拥有医生和接待员的能力,但同时分配给他们 doctorreceptionist 角色可能不会产生预期的效果。如果这两个角色只用 GRANT 权限创建,那么它们的组合将只是累加的。但如果 doctor 角色包含一些 DENY 权限,这些权限总是优先于 GRANT。这意味着护士仍将受到与医生相同的限制,这不是此处的意图。

为了证明这一点,您可以将 doctor 角色分配给护士 Daniel。切换到 system 数据库并运行以下命令:

GRANT ROLE doctor, receptionist TO daniel;

Daniel 现在应该拥有一组组合权限:

SHOW USER daniel PRIVILEGES AS COMMANDS;
结果:
+---------------------------------------------------------------------------+
| command                                                                   |
+---------------------------------------------------------------------------+
| "DENY READ {address} ON GRAPH `healthcare` NODE Patient TO $role"         |
| "DENY SET PROPERTY {address} ON GRAPH `healthcare` NODE Patient TO $role" |
| "GRANT ACCESS ON DATABASE `healthcare` TO $role"                          |
| "GRANT ACCESS ON HOME DATABASE TO $role"                                  |
| "GRANT CREATE ON GRAPH `healthcare` NODE Patient TO $role"                |
| "GRANT DELETE ON GRAPH `healthcare` NODE Patient TO $role"                |
| "GRANT DELETE ON GRAPH `healthcare` RELATIONSHIP DIAGNOSIS TO $role"      |
| "GRANT DELETE ON GRAPH `healthcare` RELATIONSHIP HAS TO $role"            |
| "GRANT EXECUTE FUNCTION * ON DBMS TO $role"                               |
| "GRANT EXECUTE PROCEDURE * ON DBMS TO $role"                              |
| "GRANT LOAD ON ALL DATA TO $role"                                         |
| "GRANT MATCH {*} ON GRAPH `healthcare` NODE Patient TO $role"             |
| "GRANT READ {*} ON GRAPH `healthcare` NODE * TO $role"                    |
| "GRANT READ {*} ON GRAPH `healthcare` RELATIONSHIP * TO $role"            |
| "GRANT SET PROPERTY {*} ON GRAPH `healthcare` NODE Patient TO $role"      |
| "GRANT TRAVERSE ON GRAPH `healthcare` NODE * TO $role"                    |
| "GRANT TRAVERSE ON GRAPH `healthcare` NODE Disease TO $role"              |
| "GRANT TRAVERSE ON GRAPH `healthcare` NODE Symptom TO $role"              |
| "GRANT TRAVERSE ON GRAPH `healthcare` RELATIONSHIP * TO $role"            |
| "GRANT TRAVERSE ON GRAPH `healthcare` RELATIONSHIP DIAGNOSIS TO $role"    |
| "GRANT TRAVERSE ON GRAPH `healthcare` RELATIONSHIP HAS TO $role"          |
| "GRANT WRITE ON GRAPH `healthcare` TO $role"                              |
+---------------------------------------------------------------------------+

22 rows
ready to start consuming query after 10 ms, results consumed after another 1 ms

之前授予或拒绝的权限可以使用REVOKE 命令撤销。

现在,意图是护士可以执行接待员的操作,这意味着他们应该能够读取和写入 Patient 节点的 address 字段。以 daniel 身份登录并针对 healthcare 数据库运行以下查询:

MATCH (n:Patient)
 WHERE n.dateOfBirth < date('1972-06-12')
RETURN n.name, n.ssn, n.address, n.dateOfBirth;
结果:
+--------------------------------------------------------+
| n.name           | n.ssn   | n.address | n.dateOfBirth |
+--------------------------------------------------------+
| "Mark Jackson"   | 1234578 | NULL      | 1970-11-29    |
| "Joe Svensson"   | 1234579 | NULL      | 1972-02-12    |
| "Bob Anderson"   | 1234597 | NULL      | 1970-04-27    |
| "Sally Anderson" | 1234617 | NULL      | 1970-12-02    |
| "Ally Anderson"  | 1234622 | NULL      | 1972-05-20    |
| "Jane Svensson"  | 1234644 | NULL      | 1970-05-24    |
| "Sally Anderson" | 1234657 | NULL      | 1972-01-23    |
+--------------------------------------------------------+

7 rows
ready to start consuming query after 4 ms, results consumed after another 2 ms

正如预期的那样,address 字段对护士是不可见的。这是因为,如前所述,DENY 权限*总是*优先于 GRANT。由于 doctorreceptionist 两个角色都分配给了护士,doctor 角色的 DENIED 权限正在覆盖 receptionistGRANTED 权限。即使护士尝试写入地址字段,他们也会收到错误,这不是这里所期望的。为了纠正这一点,您可以:

  • 只用授予权限重新定义 doctor 角色,并定义医生应该能够读取的每个 Patient 属性。

  • 用实际预期的行为重新定义 nurse 角色。

如果您认为护士本质上是除了 address 限制之外的医生,那么第二种选择更简单。在这种情况下,您需要从头开始创建 nurse 角色。切换到 system 数据库并运行以下命令:

CREATE ROLE nurse;
GRANT TRAVERSE ON GRAPH healthcare TO nurse;
GRANT READ {*} ON GRAPH healthcare TO nurse;
GRANT WRITE ON GRAPH healthcare TO nurse;

现在您将 nurse 角色分配给护士 Daniel,但请记住撤销 doctorreceptionist 角色,以免有权限被覆盖:

REVOKE ROLE doctor FROM daniel;
REVOKE ROLE receptionist FROM daniel;
GRANT ROLE nurse TO daniel;

这次,当护士 Daniel 登录并针对 healthcare 数据库运行以下查询时,他们将看到 address 字段:

MATCH (n:Patient)
 WHERE n.dateOfBirth < date('1972-06-12')
RETURN n.name, n.ssn, n.address, n.dateOfBirth;
结果:
+-----------------------------------------------------------------------+
| n.name           | n.ssn   | n.address                | n.dateOfBirth |
+-----------------------------------------------------------------------+
| "Mark Jackson"   | 1234578 | "1 secret way, downtown" | 1970-11-29    |
| "Joe Svensson"   | 1234579 | "1 secret way, downtown" | 1972-02-12    |
| "Bob Anderson"   | 1234597 | "1 secret way, downtown" | 1970-04-27    |
| "Sally Anderson" | 1234617 | "1 secret way, downtown" | 1970-12-02    |
| "Ally Anderson"  | 1234622 | "1 secret way, downtown" | 1972-05-20    |
| "Jane Svensson"  | 1234644 | "1 secret way, downtown" | 1970-05-24    |
| "Sally Anderson" | 1234657 | "1 secret way, downtown" | 1972-01-23    |
+-----------------------------------------------------------------------+

7 rows
ready to start consuming query after 4 ms, results consumed after another 2 ms

nurse 角色应该能够执行的另一个主要操作是保存诊断到数据库的医生主要操作:

WITH date(datetime({epochmillis:timestamp()})) AS today
MATCH (p:Patient)
  WHERE p.ssn = 1234657
MATCH (d:Disease)
  WHERE d.name = "Chronic Placeboitis"
MERGE (p)-[i:DIAGNOSIS {by: 'Daniel'}]->(d)
  ON CREATE SET i.date = today
RETURN p.name, d.name, i.by, i.date;
结果:
+------------------------------------------------------------------+
| p.name           | d.name                | i.by     | i.date     |
+------------------------------------------------------------------+
| "Sally Anderson" | "Chronic Placeboitis" | "Daniel" | 2025-02-14 |
+------------------------------------------------------------------+

1 row
ready to start consuming query after 49 ms, results consumed after another 2 ms
Created 1 relationships, Set 2 properties

执行此操作(否则保留给 doctor 角色)意味着护士需要承担更多责任。有些护士可能不应该被赋予此选项,这就是为什么您可以将 nurse 角色划分为*高级*和*初级*护士,例如。目前,Daniel 是一名高级护士。

*初级* nurse 的权限

此前,通过结合 doctorreceptionist 角色创建 nurse 角色导致了不希望的场景,因为 doctor 角色的 DENIED 权限覆盖了 receptionistGRANTED 权限。在这种情况下,目标是增强*高级*护士的权限,但对于*初级*护士,他们应该能够执行与*高级*护士相同的操作,除了将诊断添加到数据库。

为了实现这一点,您可以创建一个包含额外限制的特殊角色。切换到 system 数据库并运行以下命令:

CREATE ROLE disableDiagnoses;
DENY CREATE ON GRAPH healthcare RELATIONSHIPS DIAGNOSIS TO disableDiagnoses;

然后将此新角色分配给护士 Daniel,以便您可以测试行为:

GRANT ROLE disableDiagnoses TO daniel;

如果您检查 Daniel 现在拥有哪些权限,它是 nursedisableDiagnoses 两个角色的组合:

SHOW USER daniel PRIVILEGES AS COMMANDS;
结果:
+---------------------------------------------------------------------+
| command                                                             |
+---------------------------------------------------------------------+
| "DENY CREATE ON GRAPH `healthcare` RELATIONSHIP DIAGNOSIS TO $role" |
| "GRANT ACCESS ON DATABASE `healthcare` TO $role"                    |
| "GRANT ACCESS ON HOME DATABASE TO $role"                            |
| "GRANT EXECUTE FUNCTION * ON DBMS TO $role"                         |
| "GRANT EXECUTE PROCEDURE * ON DBMS TO $role"                        |
| "GRANT LOAD ON ALL DATA TO $role"                                   |
| "GRANT READ {*} ON GRAPH `healthcare` NODE * TO $role"              |
| "GRANT READ {*} ON GRAPH `healthcare` RELATIONSHIP * TO $role"      |
| "GRANT TRAVERSE ON GRAPH `healthcare` NODE * TO $role"              |
| "GRANT TRAVERSE ON GRAPH `healthcare` RELATIONSHIP * TO $role"      |
| "GRANT WRITE ON GRAPH `healthcare` TO $role"                        |
+---------------------------------------------------------------------+

11 rows
ready to start consuming query after 4 ms, results consumed after another 1 ms

Daniel 仍然可以看到地址字段,甚至可以执行 doctor 可以执行的诊断调查:

MATCH (n:Patient)-[:HAS]->(s:Symptom)-[:OF]->(d:Disease)
WHERE n.ssn = 1234650
RETURN n.ssn, n.name, d.name, count(s) AS score ORDER BY score DESC;
结果:
+--------------------------------------------------------+
| n.ssn   | n.name       | d.name                | score |
+--------------------------------------------------------+
| 1234650 | "Mark Smith" | "Chronic Argitis"     | 3     |
| 1234650 | "Mark Smith" | "Chronic Otheritis"   | 3     |
| 1234650 | "Mark Smith" | "Acute Placeboitis"   | 3     |
| 1234650 | "Mark Smith" | "Chronic Yellowitis"  | 3     |
| 1234650 | "Mark Smith" | "Chronic Someitis"    | 3     |
| 1234650 | "Mark Smith" | "Chronic Whatitis"    | 2     |
| 1234650 | "Mark Smith" | "Acute Otheritis"     | 2     |
| 1234650 | "Mark Smith" | "Chronic Placeboitis" | 2     |
| 1234650 | "Mark Smith" | "Acute Argitis"       | 2     |
| 1234650 | "Mark Smith" | "Acute Someitis"      | 2     |
| 1234650 | "Mark Smith" | "Acute Whatitis"      | 1     |
| 1234650 | "Mark Smith" | "Acute Yellowitis"    | 1     |
+--------------------------------------------------------+

12 rows
ready to start consuming query after 50 ms, results consumed after another 1 ms

但是当他们试图将诊断保存到数据库时,该操作将被拒绝:

WITH date(datetime({epochmillis:timestamp()})) AS today
MATCH (p:Patient)
  WHERE p.ssn = 1234650
MATCH (d:Disease)
  WHERE d.name = "Chronic Placeboitis"
MERGE (p)-[i:DIAGNOSIS {by: 'Daniel'}]->(d)
  ON CREATE SET i.date = today
RETURN p.name, d.name, i.by, i.date;
结果:
+---------------------------------+
| p.name | d.name | i.by | i.date |
+---------------------------------+
Create relationship with type 'DIAGNOSIS' on database 'healthcare' is not allowed for user 'daniel' with roles [PUBLIC, disableDiagnoses, nurse].

要将 Daniel 提升回高级护士,请撤销引入限制的角色:

REVOKE ROLE disableDiagnoses FROM daniel;

构建自定义管理员角色

itadmin 角色最初是通过复制内置 admin 角色并添加限制来创建的。但是,在某些情况下,拥有 DENY 权限可能不如只拥有 GRANT 权限方便。相反,您可以从头开始构建管理员角色。

IT 管理员 Tina 能够创建新用户并将其分配给产品角色,作为 itadmin,但您可以创建一个更受限制的角色,名为 userManager,并仅授予其适当的权限。切换到 system 数据库并运行以下命令:

CREATE ROLE userManager;
GRANT USER MANAGEMENT ON DBMS TO userManager;
GRANT ROLE MANAGEMENT ON DBMS TO userManager;
GRANT SHOW PRIVILEGE ON DBMS TO userManager;

通过撤销 Tina 的 itadmin 角色并改为授予他们 userManager 角色来测试新行为:

REVOKE ROLE itadmin FROM tina;
GRANT ROLE userManager TO tina;

这些是授予 userManager 的权限:

  • USER MANAGEMENT 允许创建、更新和删除用户。

  • ROLE MANAGEMENT 允许创建、更新和删除角色以及将角色分配给用户。

  • SHOW PRIVILEGE 允许列出用户的权限。

现在列出 Tina 的新权限应该显示比他们作为具有 itadmin 角色更强大的管理员时短得多的列表:

SHOW USER tina PRIVILEGES AS COMMANDS;
结果:
+--------------------------------------------------+
| command                                          |
+--------------------------------------------------+
| "GRANT ACCESS ON DATABASE `healthcare` TO $role" |
| "GRANT ACCESS ON HOME DATABASE TO $role"         |
| "GRANT EXECUTE FUNCTION * ON DBMS TO $role"      |
| "GRANT EXECUTE PROCEDURE * ON DBMS TO $role"     |
| "GRANT LOAD ON ALL DATA TO $role"                |
| "GRANT ROLE MANAGEMENT ON DBMS TO $role"         |
| "GRANT SHOW PRIVILEGE ON DBMS TO $role"          |
| "GRANT USER MANAGEMENT ON DBMS TO $role"         |
+--------------------------------------------------+

8 rows
ready to start consuming query after 24 ms, results consumed after another 1 ms

这里没有授予其他权限管理权限。此角色应拥有多少权力取决于系统的要求。有关要考虑的权限的完整列表,请参阅admin 角色部分。

现在 Tina 应该能够创建新用户并将其分配给角色(从 system 数据库):

CREATE USER sally SET PASSWORD 'secretpassword' CHANGE REQUIRED;
GRANT ROLE receptionist TO sally;
SHOW USER sally PRIVILEGES AS COMMANDS;
结果:
0 rows
ready to start consuming query after 45 ms, results consumed after another 0 ms
0 rows
ready to start consuming query after 4 ms, results consumed after another 0 ms
+------------------------------------------------------------------------+
| command                                                                |
+------------------------------------------------------------------------+
| "GRANT ACCESS ON DATABASE `healthcare` TO $role"                       |
| "GRANT ACCESS ON HOME DATABASE TO $role"                               |
| "GRANT CREATE ON GRAPH `healthcare` NODE Patient TO $role"             |
| "GRANT DELETE ON GRAPH `healthcare` NODE Patient TO $role"             |
| "GRANT DELETE ON GRAPH `healthcare` RELATIONSHIP DIAGNOSIS TO $role"   |
| "GRANT DELETE ON GRAPH `healthcare` RELATIONSHIP HAS TO $role"         |
| "GRANT EXECUTE FUNCTION * ON DBMS TO $role"                            |
| "GRANT EXECUTE PROCEDURE * ON DBMS TO $role"                           |
| "GRANT LOAD ON ALL DATA TO $role"                                      |
| "GRANT MATCH {*} ON GRAPH `healthcare` NODE Patient TO $role"          |
| "GRANT SET PROPERTY {*} ON GRAPH `healthcare` NODE Patient TO $role"   |
| "GRANT TRAVERSE ON GRAPH `healthcare` NODE Disease TO $role"           |
| "GRANT TRAVERSE ON GRAPH `healthcare` NODE Symptom TO $role"           |
| "GRANT TRAVERSE ON GRAPH `healthcare` RELATIONSHIP DIAGNOSIS TO $role" |
| "GRANT TRAVERSE ON GRAPH `healthcare` RELATIONSHIP HAS TO $role"       |
+------------------------------------------------------------------------+

15 rows
ready to start consuming query after 3 ms, results consumed after another 0 ms
© . All rights reserved.