--在使用pg中登陆数据库是第一步,其代码结构如下: --原始代码在如下文件中 src/backend/libpq/auth.c --其入口函数为ClientAuthentication,其接受一个Port结构体 void ClientAuthentication(Port *port) { --通过此函数解析客户的ip类型,确定其使用的是什么样的方式进行认证,比如能过local还是ip,是md5还是trust认证等 -- hba_getauthmethod 会调用函数 check_hba() hba_getauthmethod(port); CHECK_FOR_INTERRUPTS(); --匹配pg的认证方法,比如我们最常用的md5 switch (port->hba->auth_method) { case uaReject: case uaMD5: if (Db_user_namespace) ereport(FATAL, (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION), errmsg("MD5 authentication is not supported when \"db_user_namespace\" is enabled"))); --提示用户输入密码并对用户输入的密码进行加密 sendAuthRequest(port, AUTH_REQ_MD5); --比较用户输入的密码与数据库中存在的密码是否一致,其会调用md5_crypt_verify函数 status = recv_and_check_password_packet(port, &logdetail); break; } --检查系统中中是否有hook,如果有,则调用 if (ClientAuthentication_hook) (*ClientAuthentication_hook) (port, status); --判断用户认证是否成功 if (status == STATUS_OK) sendAuthRequest(port, AUTH_REQ_OK); else --如果认证失败,则发送失败信息给客户端 auth_failed(port, status, logdetail); } --通过check_hba函数的foreach可知,pg是从上往下匹配pg_hba.conf的文件内容,如果为满足则其返回 --故在pg_hba.conf上面的认证方式如果与下面的认证方式会覆盖下面的认证方式 static void check_hba(hbaPort *port) { Oid roleid; ListCell *line; HbaLine *hba; /* Get the target role's OID. Note we do not error out for bad role. */ roleid = get_role_oid(port->user_name, true); --一行一行的对比pg_hba.conf的内容,直到匹配 foreach(line, parsed_hba_lines) { hba = (HbaLine *) lfirst(line); /* Check connection type */ if (hba->conntype == ctLocal) { if (!IS_AF_UNIX(port->raddr.addr.ss_family)) continue; } else { do something; } /* != ctLocal */ /* Check database and role */ if (!check_db(port->database_name, port->user_name, roleid, hba->databases)) continue; if (!check_role(port->user_name, roleid, hba->roles)) continue; /* Found a record that matched! */ port->hba = hba; return; } /* If no matching entry was found, then implicitly reject. */ hba = palloc0(sizeof(HbaLine)); hba->auth_method = uaImplicitReject; port->hba = hba; } --比较用户输入的密码与数据库中存在的密码是否一致 int md5_crypt_verify(const Port *port, const char *role, char *client_pass, char **logdetail) { --根据用户名,获取系统缓存的数据库密码 datum = SysCacheGetAttr(AUTHNAME, roleTup, Anum_pg_authid_rolpassword, &isnull); if (isnull) { ReleaseSysCache(roleTup); *logdetail = psprintf(_("User \"%s\" has no password assigned."), role); return STATUS_ERROR; /* user has no password */ } shadow_pass = TextDatumGetCString(datum); --比较密码是否相同 if (strcmp(crypt_client_pass, crypt_pwd) == 0) { /* * Password OK, now check to be sure we are not past rolvaliduntil */ if (isnull) retval = STATUS_OK; else if (vuntil < GetCurrentTimestamp()) { *logdetail = psprintf(_("User \"%s\" has an expired password."), role); retval = STATUS_ERROR; } else retval = STATUS_OK; } return retval; }