最近考虑将自己的开源项目发布到Maven的中央仓库,中央仓库地址,在网上搜了一把资料,看了其他人总结的文章,有些做的不错,但自己实践起来还是遇到些问题,比如使用gpg生成私钥时会出现一些兼容上的问题,经过一番研究,最终问题还是能解决掉的,这里先做个基本知识的整理:
什么是OSSRH(OSS Repository Hosting),官方资料 --> https://central.sonatype.org/pages/ossrh-guide.html
什么是GPG(The GNU Privacy Guard),是一种加密软件,它是PGP加密软件的满足GPL的替代物。GnuPG依照由IETF订定的OpenPGP技术标准设计[2]。GnuPG用于加密、数字签名及产生非对称钥匙对的软件。(资料)。Sonatype会要求任何一方在deploy时,进行信息验证,做安全验证那么就需要一个可信任的中间机构,所以他会要求你使用gpg的工具生成私钥和公钥,并将公钥传送到这个公钥托管机构中(目前有三个大的公钥托管机构,后面会讲到),然后在你deploy所有的内容之后,开始做验证;
groupId的重要性,当在sonatype提交ticket之后,那边的管理员都会询问:“Do you own the domain eventcenter.io? If not, please read: http://central.sonatype.org/pages/choosing-your-coordinates.html You may also choose a groupId that reflects your project hosting, in this case, something like io.github.usiboy or com.github.usiboy”。如果你的代码托管在oschina或者github,并且没有独立的域名,那么就按照这个io.github.usiboy或者com.github.usiboy格式定义,如果有独立的域名,请设置域名作为groupId。域名建议和软件的内容保持一致,对于开源的项目,尽可能的选用org,io,com这样的域名,对于国内cn的域名不要去使用。
发布前的准备
我使用的环境是Mac,JDK使用的是1.8,Maven的版本是3.3。
代码需要发布到托管中心,例如码云或者Github中等等,Maven的pom的scm后面设置需要用到。
在电脑中安装gpg工具,windows下请到www.gnupg.org 这里下载安装,Mac机器可以使用brew install gpg进行安装。
到https://issues.sonatype.org/ 注册一个账号,已经注册的可以忽略,sonatype的账号中的email, username和password需要牢记,后面的操作中需要使用到。
操作步骤
在Sonatype Issues中创建Ticket
首次在sonatype中发布时,需要在issues系统中申请一个ticket。申请地址如下: https://issues.sonatype.org/secure/CreateIssue.jspa?issuetype=21&pid=10134 加*的是必填的,需要使用英文进行填写,英语不好的没关系,可以使用Google、有道翻译啊,翻译之后,稍微修改下,就能用了。可以参考如下示例: https://issues.sonatype.org/browse/OSSRH-41598?focusedCommentId=501310&page=com.atlassian.jira.plugin.system.issuetabpanels%3Acomment-tabpanel#comment-501310 注意:
- sonatype比较关注groupId,提交ticket之后,审核人员首要问的就是groupId,如果自己有域名的,可以回答他这是你自己的域名,这里也不一定要给他看凭证。如果这个groupId随意定的,项目后期维护会比较麻烦,建议没有域名,还是尽可能的按照他的规范来定义。
- SCM url是指源码的存放地址
- usernames 是指sonatype中的用户,如果有多人参与,则填写其他人的sonatype的username进来,使用','逗号分开,如果只有自己,那么就写自己的username
审核一般都比较快,sonatype在中国也有分公司的,我这个ticket从open到resolve总共耗时也不超过1天。通过之后,Ticket状态变为Resolve,同时,管理员会要求你尽快deploy,并在deploy成功之后回复这个Ticket。
使用gpg生成秘钥
这里为什么需要使用gpg生成秘钥?我们不是有了sonatype的账号和密码了吗?
这个还完全不够,Sonatype的仓库服务每天要处理很多deploy的操作,除了基本的账号校验,还需要使用更为安全的验证方式,通过gpg可以生成RSA的非对称加密,并且需要你将公钥发布到秘钥托管服务中,他们要经过这两层的校验,具体可以参考:https://central.sonatype.org/pages/working-with-pgp-signatures.html
接下来我们开始生成RSA秘钥
# 我机器上使用的是brew安装的,版本号为2.2.9,这个版本比较新,还不能直接使用gpg --gen-key,生成的格式和sonatype所要求的会有所出入,所以直接使用下面的指令进行生成
gpg --full-gen-key
gpg (GnuPG) 2.2.9; Copyright (C) 2018 Free Software Foundation, Inc.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
请选择您要使用的密钥种类:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (仅用于签名)
(4) RSA (仅用于签名)
您的选择? 1
RSA 密钥长度应在 1024 位与 4096 位之间。
您想要用多大的密钥尺寸?(2048)
# 直接回车
您所要求的密钥尺寸是 2048 位
请设定这把密钥的有效期限。
0 = 密钥永不过期
<n> = 密钥在 n 天后过期
<n>w = 密钥在 n 周后过期
<n>m = 密钥在 n 月后过期
<n>y = 密钥在 n 年后过期
密钥的有效期限是?(0) 0
# 为了简单,这个秘钥直接设置为永不过期,但是出于安全来看,最好还是设置一个有效期
密钥永远不会过期
以上正确吗?(y/n)y
You need a user ID to identify your key; the software constructs the user ID
from the Real Name, Comment and Email Address in this form:
"Heinrich Heine (Der Dichter) <heinrichh@duesseldorf.de>"
# 这里填写的是sonatype的账号名字
真实姓名:jueming
# 这里填写的是sonatype的注册邮箱
电子邮件地址:usiboy@163.com
注释:xxxx
您选定了这个用户标识:
“jueming (xxxx) <usiboy@163.com>”
更改姓名(N)、注释(C)、电子邮件地址(E)或确定(O)/退出(Q)?O
我们需要生成大量的随机字节。这个时候您可以多做些琐事(像是敲打键盘、移动
鼠标、读写硬盘之类的),这会让随机数字发生器有更好的机会获得足够的熵数。
# 我在MAC上生成时,不需要敲那么多,它直接就过去了
# 这个密码是给公钥加密的密码,切记,一定要记住,如果你想简单点,那就和sonatype的登录密码一样
请输入密码:*********
# 注意这个33F38C0F7F755D60,这个一定要保存下来,发布key时需要用到,以及在后面做deploy时,需要Maven的settings中进行设置
gpg: 密钥 33F38C0F7F755D60 被标记为绝对信任
gpg: revocation certificate stored as '~/.gnupg/openpgp-revocs.d/407618CE258C725171487B6233F38C0F7F755D60.rev'
公钥和私钥已经生成并经签名。
pub rsa2048 2018-08-02 [SC]
407618CE258C725171487B6233F38C0F7F755D60
uid jueming (xxxx) <usiboy@163.com>
sub rsa2048 2018-08-02 [E]
看到这个信息,恭喜你成功的生成秘钥了
使用gpg 2.9的版本的问题
我这边遇到了一个这样的问题:gpg: signing failed: Inappropriate ioctl for device
由于高版本gpg的目录下的结构和老版本有些不同,在执行mvn的gpg插件时会出现这个问题,google了一把,终于找到解决方案了。
在~/.gnupg目录下增加两个文件 gpg-agent.conf,添加如下内容:
allow-loopback-pinentry
gpg.conf,添加如下内容:
use-agent
pinentry-mode loopback
之后再运行就没报这个错误了,也希望未来maven的gpg的插件也能够跟着升级下,避免出现这个错误,这里可以在issues.sonatype.org中给他们提BUG。
发布公钥到托管服务
gpg使用了RSA加密方式,所以需要将公钥send到秘钥托管服务中,为了提高deploy的成功率,建议一次提交到三个秘钥托管服务中,sonatype会分别去查找三个托管服务,如果都找不到则会报错
gpg --keyserver hkp://pool.sks-keyservers.net --send-keys 33F38C0F7F755D60
gpg --keyserver hkp://keyserver.ubuntu.com --send-keys 33F38C0F7F755D60
gpg --keyserver hkp://pgp.mit.edu --send-keys 33F38C0F7F755D60
send完成之后,可以通过--recv-keys查询服务是否有秘钥
gpg --keyserver hkp://pool.sks-keyservers.net --recv-keys 33F38C0F7F755D60
gpg: 密钥 33F38C0F7F755D60:“jueming (xxxx) <usiboy@163.com>”未改变
gpg: 合计被处理的数量:1
gpg: 未改变:1
配置pom.xml
这里主要说下比较关键的一些信息
<!-- 项目主页,如果没有,请直接使用代码托管的地址 -->
<url>http://eventcenter.io</url>
<!-- 组织信息 -->
<organization>
<name>Jue Ming</name>
<url>http://eventcenter.io</url>
</organization>
<!-- 开源许可证,不知道如何选择,请参考https://github.com/qyxxjd/License -->
<licenses>
<license>
<name>MIT License</name>
<url>http://www.opensource.org/licenses/mit-license.php</url>
<distribution>repo</distribution>
</license>
</licenses>
<!-- 开发者信息 -->
<developers>
<developer>
<name>Jue Ming</name>
<email>usiboy@163.com</email>
</developer>
</developers>
<!-- 开源地址 -->
<scm>
<connection>scm:git:git@github.com:usiboy/event-center.git</connection>
<developerConnection>scm:git:git@github.com:usiboy/event-center.git</developerConnection>
<url>https://github.com/usiboy/event-center</url>
</scm>
<properties>
<project.build.sourceEncoding>utf-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<!-- ...... 这里我省略了一些properties,下面几个是后面配置plugins需要使用到 -->
<version.maven-source-plugin>3.0.1</version.maven-source-plugin>
<version.maven-javadoc-plugin>2.10.4</version.maven-javadoc-plugin>
<version.maven-gpg-plugin>1.6</version.maven-gpg-plugin>
</properties>
<!-- ..... 中间省略掉一些配置,我们直接跳到profile的设置中 ...... -->
<profiles>
<profile>
<id>oss</id>
<build>
<plugins>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<!-- Source -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${version.maven-source-plugin}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Javadoc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${version.maven-javadoc-plugin}</version>
<configuration>
<!-- 这个配置看情况加,因为我的电脑上使用的是JDK1.8,我这个库需要使用1.6编译,不加这个,对于javadoc的编译会存在问题 -->
<additionalparam>-Xdoclint:none</additionalparam>
</configuration>
</plugin>
<!-- GPG -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${version.maven-gpg-plugin}</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6</version>
<extensions>true</extensions>
<configuration>
<!-- 这个id不要乱设置,需要和后面的settings.xml中的server的id保持一致 -->
<serverId>oss</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
</configuration>
<executions>
<execution>
<id>deploy-to-sonatype</id>
<phase>deploy</phase>
<goals>
<goal>deploy</goal>
<goal>release</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<distributionManagement>
<snapshotRepository>
<id>oss</id>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</snapshotRepository>
<repository>
<id>oss</id>
<url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
</repository>
</distributionManagement>
</profile>
</profiles>
设置settings.xml
已经到设置的最后一步了,马上就要成功了,注意settings.xml可以和你现在正在使用的settings.xml分为两个文件管理,比如在~/.m2/目录下再开辟一个目录然后在这里更新:sonatype/settings.xml。
mvn 使用--settings sonatype/settings.xml指令,可以指定具体的配置文件进行操作。
以下是settings.xml的部分内容:
<servers>
<server>
<!-- 这个id不要乱设置,需要和前面的pom.xml中的sonatype的插件中的serverId保持一致 -->
<id>oss</id>
<!-- 这个是sonatype中注册的username -->
<username>jueming</username>
<!-- 这个是sonatype中的登录密码 -->
<password><![CDATA[***********]]></password>
</server>
</servers>
<profiles>
<profile>
<id>oss</id>
<properties>
<!-- 前面pom.xml中配置了gpg的maven插件,最好使用最新版本1.6,这样只需要在settings.xml中配置properties,这个目录就是你本地机器存放gpg秘钥的目录 -->
<gpg.homedir>~/.gnupg</gpg.homedir>
<!-- 这个就是前面我强调需要记录下的key -->
<gpg.keyname>36CB9C06A5883FF4</gpg.keyname>
<!-- 公钥的加密密码 -->
<gpg.passphrase><![CDATA[*********]]></gpg.passphrase>
</properties>
</profile>
</profiles>
<activeProfiles>
<activeProfile>oss</activeProfile>
</activeProfiles>
deploy项目
前面都设置完成之后,可以开始运行如下命令:
mvn clean deploy -Poss --settings sonatype/settings.xml
如果你是直接修改~/.m2/settings.xml的文件:
mvn clean deploy -Poss
需要等待一段时间,首先要经过编译、打包,然后开始加密,有上传文件的过程,全部上传完之后,需要等待服务端的验证响应,这个过程一般比较耗时,需要耐心等待2-5分钟。
一切顺利的话,在控制台中会告诉你发布成功啦。
但是到这里还没完,还需要做几步操作即可。
回复Resolved的Ticket
之前Ticket申请成功之后,管理员还会要求你deploy成功之后,还需要回复下:如下图所示
他们一般会很快回复你的,并告诉你这个库已经激活,你可以随时将staging中的repository发布上线。
之所以有这个阶段,也是为了让你在本地引用这个临时的库,用于测试下deploy的jar是否都是有效的。
Release staging repository
登录https://oss.sonatype.org
按照如上箭头点击,找到自己的repository(不知道这里为什么别人的repository也能看到,但是你点击别人的release又不能发布)。前面我们使用mvn deploy的时候,他会返回一个staging id,截图中是我之前deploy失败的id,失败的是不能release。只有成功deploy的才能Release,所以找到成功发布那个id,点击它之后,工具栏中的Release按钮会被激活,于是,点击Release,没过多久,他就会告诉你成功发布啦。然后再过个大概10分钟,你到中央仓库搜索一把,你的库都出来了,大功告成!