关于Git鉴权你不得不知道的知识点

解决各种git操作需要频繁输入密码的问题

Posted by Jeremy Song on 2021-08-26
Estimated Reading Time 9 Minutes
Words 2.3k In Total
Viewed Times

Git 作为一款目前广为流行的版本控制系统,想必大家都很熟悉了,这里不再过多的介绍,如果想系统的了解 Git 可以去 这里 在线阅读,或者 下载PDF 学习。

背景

用过 Git 的朋友都知道,不管我们使用的是 GitHubGitLabGitee还是其他公司自建的基于 Git 做版本控制的系统。当我们 clone 了一个仓库之后,配置完仓库密钥,后面在自己本地不管什么操作都会一路畅通无阻,再也不用每次都输入密码了。

是的!我也是这么一直使用了很多年,但这次真的不行了。不管我怎么配置密钥还是逃不脱每次都要输入密码的情况。于是分析之~

不一样的Git鉴权策略

经过查阅资料和验证,最终发现原来这一次使用的代码 clone 协议是 http!。这是怎么回事?

不知道大家在 clone 代码时有没有注意,类似 GitHub、Gitee、Gitlab 的代码仓库的地址有类似下面这个选项:

下面来分别说说这两种方式的差异。

非SSH方式连接

非SSH方式一般为 HTTP 或者 HTTPS,我们暂且认为它们是同一个,下面以 HTTP 为例来说明。

这与我们所熟悉的 SSH 方式连接远端不同,HTTP 的每一次连接都是需要用户名和密码的。这在使用双重认证的情况下会很麻烦,因为我们需要输入一个随机生成并且毫无规律的 token 作为密码。

这里,Git 拥有一个凭证系统来处理这个事情。下面有一些 Git 选项:

  • 默认所有都不缓存。每一次连接都会询问用户名和密码。
  • cache 模式会将凭证存放在内存中一段时间。密码永远不会被存储在磁盘中,并且在15分钟后从内存中清除。
  • stote 模式会将凭证用明文的形式存放在磁盘中,并且永不过期。这意味着除非我们修改了在 Git 服务器上的密码,否则我们永远不需要再次输入我们的凭证信息。这种方式的缺点是我们的密码是用明文的方式存在 home 目录下的。
  • 如果你使用的是 Mac,Git 还有一种 “osxkeychain” 模式,它会将凭证缓存到你系统用户的钥匙串中。 这种方式将凭证存放在磁盘中,并且永不过期,但是是被加密的,这种加密方式与存放 HTTPS 凭证以及 Safari 的自动填写是相同的。
  • 如果你使用的是 Windows,你可以安装一个叫做 “Git Credential Manager for Windows” 的辅助工具。 这和上面说的 “osxkeychain” 十分类似,但是是使用 Windows Credential Store 来控制敏感信息。可以 点此 下载。

所以我上面遇到的问题就是因为我系统中的 Git 管理凭证使用的是默认的设置,所以无论如何我怎么去设置密钥都不起作用的原因。这个和 SSH 的密钥一点关系都没有。简单的使用如下命令即可解决:

1
git config --global credential.helper store

根据我们自己的需要上面命令中 --global 不是必须的,另外 store 可以根据自己的需要修改为上面提到的四种之一,当然默认情况是不需要配置的。

设置参数和多工具配置

store 模式可以接受一个 --file <path> 参数,可以自定义存放密码的文件路径(默认是 ~/.git-credentials )。 cache 模式有 --timeout <seconds> 参数,可以设置后台进程的存活时间(默认是 “900”,也就是 15 分钟)。 下面是一个配置 store 模式自定义路径的例子:

1
git config --global credential.helper 'store --file ~/.my-credentials'

Git 允许我们配置多个辅助工具。当查找特定服务器的凭证时,Git 会按顺序查询,并且在找到第一个应答时停止查询。 当保存凭证时,Git 会将用户名和密码发送给所有配置列表中的辅助工具,它们会按自己的方式处理用户名和密码。 如果你在闪存上有一个凭证文件,但又希望在该闪存被拔出的情况下使用内存缓存来保存用户名密码,.gitconfig 配置文件如下:

1
2
3
[credential]
helper = store --file /mnt/thumbdrive/.git-credentials
helper = cache --timeout 30000

这样的好处是,你可以把你的密码放在自己的U盘里。你自己用的时候插入U盘就可以不用输入密码,走的时候U盘带走就必须要输入密码才行,另外超过了过期时间缓存的密码也就自动删除了。

SSH方式连接

SSH 方式连接是我们最常见的连接方式,简单操作方法如下:

首先生成公私钥(sshkey)对。

1
ssh-keygen -t rsa -C "xxxx@xxx.com"

注意:这里的 xxxx@xxx.com 只是生成 sshkey 的名称,并不约束或要求具体命名为某个邮箱。

按照提示完成三次回车,即可生成 sshkey。生成文件在默认目录 ~/.ssh 中后缀为 .pub 的为公钥,另一个同名的文件是私钥。

最后复制公钥内容填写到自己所使用的 Git 管理系统中即可。这个也是大家所周知的过程。

既然上面这个过程大家都操作过,那么有个问题不知道您思考过没:假如我的密钥目录下有不止一对密钥,又或者我要同时用 GitHub 和 Gitee 应该怎么办呢?

SSH的配置

上面这个问题的答案是,其实到了这个阶段就已经和 Git 没关系了,它只是运行一下 SSH 而已,所以上面的任务就完全交给了 SSH 客户端自己。

和所有绝大多数的命令行程序一样,SSH 客户端在运行时也是有一堆默认参数的,SSH 获取参数配置的顺序如下:

  • 命令行选项
  • 用户的配置文件(~/.ssh/config)
  • 系统范围的配置文件(/etc/ssh/ssh_config

对于相同的配置设置,SSH 将使用第一个获取的值作为有效值。一般系统可能没有 ~/.ssh/config 文件,先来看看 /etc/ssh/ssh_config 文件的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
root@Ubuntu20:~/.ssh# cat /etc/ssh/ssh_config

# This is the ssh client system-wide configuration file. See
# ssh_config(5) for more information. This file provides defaults for
# users, and the values can be changed in per-user configuration files
# or on the command line.

# Configuration data is parsed as follows:
# 1. command line options
# 2. user-specific file
# 3. system-wide file
# Any configuration value is only changed the first time it is set.
# Thus, host-specific definitions should be at the beginning of the
# configuration file, and defaults at the end.

# Site-wide defaults for some commonly used options. For a comprehensive
# list of available options, their meanings and defaults, please see the
# ssh_config(5) man page.

Include /etc/ssh/ssh_config.d/*.conf

Host *
# ForwardAgent no
# ForwardX11 no
# ForwardX11Trusted yes
# PasswordAuthentication yes
# HostbasedAuthentication no
# GSSAPIAuthentication no
# GSSAPIDelegateCredentials no
# GSSAPIKeyExchange no
# GSSAPITrustDNS no
# BatchMode no
# CheckHostIP yes
# AddressFamily any
# ConnectTimeout 0
# StrictHostKeyChecking ask
# IdentityFile ~/.ssh/id_rsa
# IdentityFile ~/.ssh/id_dsa
# IdentityFile ~/.ssh/id_ecdsa
# IdentityFile ~/.ssh/id_ed25519
# Port 22
# Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc
# MACs hmac-md5,hmac-sha1,umac-64@openssh.com
# EscapeChar ~
# Tunnel no
# TunnelDevice any:any
# PermitLocalCommand no
# VisualHostKey no
# ProxyCommand ssh -q -W %h:%p gateway.example.com
# RekeyLimit 1G 1h
SendEnv LANG LC_*
HashKnownHosts yes
GSSAPIAuthentication yes

可以看到里面有很多默认的设置项,至于每一项是什么含义这里就不一一列出了,感兴趣的朋友请移步至 ssh_config(5) - Linux手册 查阅。

我们清楚了 Git 使用 SSH 方式连接仓库是和 SSH 客户端直接相关的,那么修改 SSH 相关参数之后,就应该能解决我们上面的问题。

Git配置多个SSH-Key

我们假设一个场景,我有多个git账号都要使用,比如:

  • 一个 Gitee,用于公司内部的工作开发
  • 一个 GitHub,用于自己进行的一些开发活动
解决方法
  • 生成一个公司用的SSH-Key
1
$ ssh-keygen -t rsa -C 'xxxxx@company.com' -f ~/.ssh/gitee_id_rsa
  • 生成一个GitHub用的SSH-Key
1
$ ssh-keygen -t rsa -C 'xxxxx@126.com' -f ~/.ssh/github_id_rsa
  • ~/.ssh 目录下新建一个 config 文件,添加如下内容(其中 Host 和 HostName 填写 git 服务器的域名,IdentityFile 指定私钥的路径)
1
2
3
4
5
6
7
8
9
10
# gitee
Host gitee.com
HostName gitee.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/gitee_id_rsa
# github
Host github.com
HostName github.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/github_id_rsa

配置文件中的 PreferredAuthentications 是为了指定客户端身份验证方法的顺序,此选项的默认值是: “gssapi-with-mic, hostbased, publickey, keyboard-interactive, password”

  • 用ssh命令分别测试
1
2
$ ssh -T git@gitee.com
$ ssh -T git@github.com

以 Gitee 为例,成功的回显如下:

1
2
root@Ubuntu20:~# ssh -T git@gitee.com
Hi ! You've successfully authenticated, but GITEE.COM does not provide shell access.

上面的关键就在于 ~/.ssh/config 的配置。通过配置我们指定了访问不同 Host 所使用的密钥文件,这样就很方便的对不同的环境做出了区分。上面我们提到的问题也就迎刃而解了。

参考


欢迎关注我的公众号 须弥零一,跟我一起学习IT知识。


如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !