一.背景
PostgreSQL实现基于角色的访问控制机制,通过对角色的权限设置,实现对数据库对象如关系表的操作(如增加、删除、查询等)
二.系统表
pg_authid是角色系统表,pg_roles是基于pg_authid的视图,实习对密码的屏蔽。
1.pg_authid
属性 | 数据类型 | 说明 |
---|---|---|
oid | oid | 唯一标识 |
rolname | name | 角色名称 |
rolsuper | bool | 超级用户权限 |
rolinherit | bool | 自动继承所属组权限 |
rolcreaterole | bool | 创建角色权限 |
rolcreatedb | bool | 创建数据库权限 |
rolcanlogin | bool | 登录权限 |
rolreplication | bool | 复制权限 |
rolbypassrls | bool | 行安全策略 |
rolconnlimit | int4 | 连接限制 |
rolpassword | text | 密码 |
rolvaliduntil | timestamptz | 过期时间,不设置为空 |
2.pg_auth_members
属性 | 数据类型 | 说明 |
---|---|---|
oid | oid | 唯一标识 |
roleid | oid | 父角色标识 |
member | oid | 子角色标识 |
grantor | oid | 建立父子关系的标识 |
admin_option | bool | 如果member可以把roleid角色的成员关系赋予其他角色,则为真 |
三.数据结构
1.声明
typedef struct CreateRoleStmt
{
NodeTag type;
RoleStmtType stmt_type; /* ROLE/USER/GROUP */
char *role; /* role name */
List *options; /* List of DefElem nodes */
} CreateRoleStmt;
2.角色属性
CREATE ROLE user1 WITH PASSWORD ‘12345’; 当前的属性是密码,值为’12345’。以stmt->options链表的形式表达。
typedef struct DefElem
{
NodeTag type;
char *defnamespace; /* NULL if unqualified name */
char *defname;
Node *arg; /* a (Value *) or a (TypeName *) */
DefElemAction defaction; /* unspecified action, or SET/ADD/DROP */
int location; /* token location, or -1 if unknown */
} DefElem;
四.核心代码
1.创建角色的流程
2.backend\commands\user.c
Oid
CreateRole(ParseState *pstate, CreateRoleStmt *stmt)
{
Relation pg_authid_rel;
TupleDesc pg_authid_dsc;
HeapTuple tuple;
Datum new_record[Natts_pg_authid];
bool new_record_nulls[Natts_pg_authid];
Oid roleid;
ListCell *item;
ListCell *option;
char *password = NULL; /* user password */
bool issuper = false; /* Make the user a superuser? */
bool inherit = true; /* Auto inherit privileges? */
bool createrole = false; /* Can this user create roles? */
bool createdb = false; /* Can the user create databases? */
bool canlogin = false; /* Can this user login? */
bool isreplication = false; /* Is this a replication role? */
bool bypassrls = false; /* Is this a row security enabled role? */
int connlimit = -1; /* maximum connections allowed */
List *addroleto = NIL; /* roles to make this a member of */
List *rolemembers = NIL; /* roles to be members of this role */
List *adminmembers = NIL; /* roles to be admins of this role */
char *validUntil = NULL; /* time the login is valid until */
Datum validUntil_datum; /* same, as timestamptz Datum */
bool validUntil_null;
DefElem *dpassword = NULL;
DefElem *dissuper = NULL;
DefElem *dinherit = NULL;
DefElem *dcreaterole = NULL;
DefElem *dcreatedb = NULL;
DefElem *dcanlogin = NULL;
DefElem *disreplication = NULL;
DefElem *dconnlimit = NULL;
DefElem *daddroleto = NULL;
DefElem *drolemembers = NULL;
DefElem *dadminmembers = NULL;
DefElem *dvalidUntil = NULL;
DefElem *dbypassRLS = NULL;
/* The defaults can vary depending on the original statement type */
switch (stmt->stmt_type)
{
case ROLESTMT_ROLE:
break;
case ROLESTMT_USER:
canlogin = true;
/* may eventually want inherit to default to false here */
break;
case ROLESTMT_GROUP:
break;
}
/* Extract options from the statement node tree */
foreach(option, stmt->options)
{
DefElem *defel = (DefElem *) lfirst(option);
if (strcmp(defel->defname, "password") == 0)
{
if (dpassword)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options"),
parser_errposition(pstate, defel->location)));
dpassword = defel;
}
else if (strcmp(defel->defname, "sysid") == 0)
{
ereport(NOTICE,
(errmsg