©
This document uses PHP Chinese website manual Release
凭证 API 提供了一种从用户那里收集用户名和密码凭证的抽象方式(即使更广泛的世界中的凭证可以采用多种形式,本文档中的“凭证”一词总是指用户名和密码对)。
本文档描述了两个接口:凭证子系统提供给 Git 其余部分的 C API ,以及 Git 用来与系统特定的“凭证助手”通信的协议。如果您正在编写想要查看或提示输入凭据的 Git 代码,请参阅下面的 “C API” 部分。如果您想编写自己的帮手,请参阅下面的“凭证助手”部分。
+-----------------------+| Git code (C) |--- to server requiring --->| | authentication|.......................|| C credential API |--- prompt ---> User+-----------------------+ ^ | | pipe | | v+-----------------------+| Git credential helper |+-----------------------+
Git 代码(通常是远程帮助程序)将调用 C API 来获取凭证数据,如登录名/密码对( credential_fill )。API 本身会调用一个远程助手(例如 “git credential-cache” 或 “git credential-store” ),它可以从商店中检索凭证数据。如果凭证帮助程序找不到信息,C API 将提示用户。然后,API 的调用者负责联系服务器,并进行实际的身份验证。
凭证 C API 旨在由需要获取或存储凭证的 Git 代码调用。它以代表单个凭证的对象为中心,并提供三种基本操作:填充(通过调用助手和/或提示用户获取凭证),批准(将凭证标记为已成功使用,以便将其存储以供以后使用),并拒绝(将凭证标记为不成功,以便可以从任何持久性存储中将其删除)。
struct credential
该结构表示一个用户名/密码组合以及任何关联的上下文。所有字符串字段应该是堆分配的(如果它们不知道或不适用,则为 NULL )。各个上下文字段的含义与帮助程序协议中的对应字段相同; 请参阅下面的部分,了解每个字段的说明。
该helpers
结构的成员是一个string_list
助手。每个字符串都指定一个外部帮助程序,它将按顺序运行以获取或存储凭证。请参阅下面的凭证助手部分。在查询帮助器之前,该列表由API函数根据相应的配置变量填充,因此通常根本不需要调用者修改帮助器字段。
这个结构应该始终用CREDENTIAL_INIT
或credential_init
来初始化。
credential_init
初始化凭证结构,将所有字段设置为空。
credential_clear
释放与凭证结构关联的任何资源,并将其返回到原始初始化状态。
credential_fill
指示凭证子系统通过首先咨询助手填充传递的凭证结构的用户名和密码字段,然后询问用户。此函数返回后,凭证的用户名和密码字段将保证为非 NULL。如果发生错误,该函数将死()。
credential_reject
通知凭证子系统所提供的凭证已被拒绝。这将导致凭证子系统通知拒绝的任何助手(例如,允许他们清除存储中的无效凭证)。它还将释放()用户名和密码字段的凭证并将它们设置为 NULL(准备另一次呼叫的凭证credential_fill
)。来自助手的任何错误都会被忽略。
credential_approve
通知凭证子系统所提供的凭证已成功用于身份验证。这将导致凭证子系统通知任何助手的批准,以便他们可以存储结果再次使用。来自助手的任何错误都会被忽略。
credential_from_url
将 URL 解析为已破解的凭证字段。
下面的示例显示了凭证 API 的功能如何用于登录到远程主机上虚构的 “foo” 服务:
int foo_login(struct foo_connection *f){ int status; /* * Create a credential with some context; we don't yet know the * username or password. */ struct credential c = CREDENTIAL_INIT; c.protocol = xstrdup("foo"); c.host = xstrdup(f->hostname); /* * Fill in the username and password fields by contacting * helpers and/or asking the user. The function will die if it * fails. */ credential_fill(&c); /* * Otherwise, we have a username and password. Try to use it. */ status = send_foo_login(f, c.username, c.password); switch (status) { case FOO_OK: /* It worked. Store the credential for later use. */ credential_accept(&c); break; case FOO_BAD_LOGIN: /* Erase the credential from storage so we don't try it * again. */ credential_reject(&c); break; default: /* * Some other error occurred. We don't know if the * credential is good or bad, so report nothing to the * credential subsystem. */ } /* Free any associated resources. */ credential_clear(&c); return status;}
凭证助手是由 Git 执行的程序,用于从长期存储中获取或保存凭据(其中“长期”比单个 Git 流程更长;例如,凭证可以存储在内存中几分钟,或者无限期地在磁盘上)。
每个助手都由配置变量中的单个字符串credential.helper
(以及其他字符串,请参阅 git-config [1] )指定。该字符串通过 Git 转换为使用这些规则执行的命令:
1. 如果辅助字符串以“!”开头,则它被认为是一个 shell 代码片段,并且“!”之后的所有内容都成为命令。
2. 否则,如果辅助字符串以绝对路径开始,则逐字帮助字符串变成命令。
3. 否则,字符串“git credential-”被预先添加到助手字符串中,结果变成命令。
然后生成的命令会附加一个“操作”参数(详情参见下文),结果由 shell 执行。
以下是一些示例说明:
# run "git credential-foo"foo # same as above, but pass an argument to the helper foo --bar=baz # the arguments are parsed by the shell, so use shell # quoting if necessary foo --bar="whitespace arg"# you can also use an absolute path, which will not use the git wrapper/path/to/my/helper --with-arguments # or you can specify your own shell snippet!f() { echo "password=`cat $HOME/.secret`"; }; f
一般来说,上面的规则(3)对用户来说是最简单的。凭证助手的作者应该努力通过命名他们的程序 “git-credential- $ NAME” 来帮助他们的用户,并且在安装时将其放在 $ PATH 或 $ GIT_EXEC_PATH 中,这将允许用户使用它和git config credential.helper $NAME
。
当执行帮助程序时,它的命令行中会附加一个“操作”参数,该参数是以下之一:
get
返回匹配的凭证(如果存在)。
store
存储凭证(如果适用于助手)。
erase
从助手的存储中删除匹配的凭据(如果有)。
凭证的详细信息将在助手的 stdin 流中提供。确切的格式与git credential
管道命令的输入/输出格式相同(INPUT/OUTPUT FORMAT
有关详细规范,请参阅 git-credential [1] 中的部分)。
对于get
操作,帮助者应该以相同的格式在 stdout 上产生一个属性列表。辅助者可以自由地产生一个子集,或者如果它没有任何用处可以提供的话,甚至根本没有值。任何提供的属性都会覆盖 Git 已知的那些属性。如果助手输出quit
值为true
或属性1
,则不会再咨询帮助者,也不会提示用户(如果没有提供凭证,则操作将失败)。
对于 store
或erase
操作,帮助器的输出将被忽略。如果它未能执行请求的操作,它可能会向 stderr 投诉以通知用户。如果它不支持请求的操作(例如只读存储),它应该默默地忽略该请求。
如果助手收到任何其他操作,它应该默默地忽略该请求。这为未来的操作留下了余地(较旧的帮助者将忽略新的请求)。