1
0
mirror of https://github.com/chai2010/advanced-go-programming-book.git synced 2025-05-24 20:52:22 +00:00

Merge branch 'master' of github.com:chai2010/advanced-go-programming-book

This commit is contained in:
Xargin 2018-08-07 16:07:31 +08:00
commit fe6577d150
2 changed files with 15 additions and 15 deletions

View File

@ -20,7 +20,7 @@ $ openssl req -new -x509 -days 3650 \
-key client.key -out client.crt
```
以上命令将生成server.key、server.crt、client.key和client.crt四个文件。其中以.key为后缀名的是私钥文件需要妥善保管。以.crt为后缀名是证书文件也可以简单理解为公钥文件并不需要秘密保存。在subj参数中的`/CN=server.grpc.io`表示服务的名字为`server.grpc.io`,在验证服务器的证书时需要用到该信息。
以上命令将生成server.key、server.crt、client.key和client.crt四个文件。其中以.key为后缀名的是私钥文件需要妥善保管。以.crt为后缀名是证书文件也可以简单理解为公钥文件并不需要秘密保存。在subj参数中的`/CN=server.grpc.io`表示服务的名字为`server.grpc.io`,在验证服务器的证书时需要用到该信息。
有了证书之后我们就可以在启动GRPC服务时传入证书选项参数
@ -62,11 +62,11 @@ func main() {
}
```
其中redentials.NewClientTLSFromFile是构造客户端用的证书对象第一个参数是服务器的证书文件第二个参数是签发服务器证书时的名字。然后通过grpc.WithTransportCredentials(creds)将证书对象转为参数选项传人grpc.Dial函数。
其中redentials.NewClientTLSFromFile是构造客户端用的证书对象第一个参数是服务器的证书文件第二个参数是签发证书的服务器的名字。然后通过grpc.WithTransportCredentials(creds)将证书对象转为参数选项传人grpc.Dial函数。
以上这种方式,需要提前将服务器的证书告知客户端,这样客户端在链接服务器时才能进行对服务器证书认证。在复杂的网络环境中,服务器证书的传输本身也是一个非常危险的问题。如果在中间某个环节,服务器证书被监听或替换那么对服务器的认证也将不再可靠。
为了避免证书的传递过程中被改,可以通过一个安全可靠的根证书分别对服务器和客户端的证书进行签名。这样客户端或服务器在收到对方的证书后可以通过根证书进行验证证书的有效性。
为了避免证书的传递过程中被改,可以通过一个安全可靠的根证书分别对服务器和客户端的证书进行签名。这样客户端或服务器在收到对方的证书后可以通过根证书进行验证证书的有效性。
根证书的生成方式和签名的自签名证书的生成方式类似:
@ -170,13 +170,13 @@ func main() {
}
```
服务器端同样改用credentials.NewTLS函数生成证书通过ClientCAs选CA根证书并通过ClientAuth选项启用对客户端进行验证。
服务器端同样改用credentials.NewTLS函数生成证书通过ClientCAs选CA根证书并通过ClientAuth选项启用对客户端进行验证。
到此我们就实现了一个服务器和客户端进行双向证书验证的通信可靠的GRPC系统。
## 4.5.2 Token认证
前面讲述的基于证书的认证是针对每个GRPC链接的认证。GRPC还为每个GRPC方法调用提供了认证支持这样就基于基于用户Token对不同对方法访问进行权限管理。
前面讲述的基于证书的认证是针对每个GRPC链接的认证。GRPC还为每个GRPC方法调用提供了认证支持这样就基于用户Token对不同的方法访问进行权限管理。
要实现对每个GRPC方法进行认证需要实现grpc.PerRPCCredentials接口
@ -196,13 +196,13 @@ type PerRPCCredentials interface {
)
// RequireTransportSecurity indicates whether the credentials requires
// transport security.
RequireTransportSecurity() bool
RequireTransportSecurity() bool
}
```
在GetRequestMetadata方法中返回认证需要对必要信息。RequireTransportSecurity方法表示是否求底层使用安全链接。在真实对环境中建议底层必须要求启用安全对链接否则认证信息有泄露和被串改的风险。
在GetRequestMetadata方法中返回认证需要的必要信息。RequireTransportSecurity方法表示是否要求底层使用安全链接。在真实的环境中建议必须要求底层启用安全的链接否则认证信息有泄露和被篡改的风险。
我们可以创建一个Authentication类型用于实现用户名和密码认证:
我们可以创建一个Authentication类型用于实现用户名和密码认证:
```go
type Authentication struct {
@ -306,7 +306,7 @@ server := grpc.NewServer(grpc.UnaryInterceptor(filter))
如果截取器函数返回了错误那么该次GRPC方法调用将被视作失败处理。因此我们可以在截取器中对输入的参数做一些简单的验证工作。同样也可以对handler返回的结果做一些验证工作。截取器也非常适合前面对Token认证工作。
下面是截取器增加了对GRPC方法异常捕获:
下面是截取器增加了对GRPC方法异常捕获:
```go
func filter(
@ -349,7 +349,7 @@ myServer := grpc.NewServer(
GRPC构建在HTTP/2协议之上因此我们可以将GRPC服务和普通的Web服务架设在同一个端口之上。因为目前Go语言版本的GRPC实现还不够完善只有启用了TLS协议之后才能将GRPC和Web服务运行在同一个端口。
服务器证书的生成过程前文已经讲过,这不再赘述。启用普通的https服务器非常简单
服务器证书的生成过程前文已经讲过,这不再赘述。启用普通的https服务器非常简单
```go
func main() {
@ -382,9 +382,9 @@ func main() {
}
```
因为GRPC服务已经实现了ServeHTTP方法可以直接作为Web路由处理对象。如果将Grpc和Web服务放在一起会导致GRPC和Web路径的冲突在处理时我们需要区分两类服务。
因为GRPC服务已经实现了ServeHTTP方法可以直接作为Web路由处理对象。如果将GRPC和Web服务放在一起会导致GRPC和Web路径的冲突在处理时我们需要区分两类服务。
我们可以通过以下方式生成同时支持Web和Grpc协议的路由处理函数:
我们可以通过以下方式生成同时支持Web和GRPC协议的路由处理函数:
```go
func main() {
@ -408,7 +408,7 @@ func main() {
}
```
首先GRPC是建立在HTTP/2版本之上如果HTTP不是HTTP/2协议则必然无法提供GRPC支持。同时如果每个GRPC调用请求的Content-Type类型会被标注为"application/grpc"类型。
首先GRPC是建立在HTTP/2版本之上如果HTTP不是HTTP/2协议则必然无法提供GRPC支持。同时每个GRPC调用请求的Content-Type类型会被标注为"application/grpc"类型。
这样我们就可以在GRPC端口上同时提供Web服务了。

View File

@ -31,7 +31,7 @@ message HttpRule {
pbgo.proto文件是pbgo框架的一个部分需要被其他的proto文件导入。Protobuf本身自有一套完整的包体系在这里包的路径就是pbgo。Go语言也有自己的一套包体系我们需要通过go_package的扩展语法定义Protobuf和Go语言之间包的映射关系。定义Protobuf和Go语言之间包的映射关系之后其他导入pbgo.ptoto包的Protobuf文件在生成Go语言时会生成pbgo.proto映射的Go语言包路径。
Protobuf扩展语法有五种类型分别是针对文件的扩展信息、针对message的扩展信息、对message成员的扩展信息、针对service的扩展信息和针对service方法的扩展信息。在使用扩展前首先需要通过extend关键字定义扩展的类型和可以用于扩展的成员。扩展成员可以基础类型也可以是一个结构体类型。pbgo中只定义了service的方法的扩展只定义了一个名为rest_api的扩展成员类型是HttpRule结构体。
Protobuf扩展语法有五种类型分别是针对文件的扩展信息、针对message的扩展信息、对message成员的扩展信息、针对service的扩展信息和针对service方法的扩展信息。在使用扩展前首先需要通过extend关键字定义扩展的类型和可以用于扩展的成员。扩展成员可以基础类型也可以是一个结构体类型。pbgo中只定义了service的方法的扩展只定义了一个名为rest_api的扩展成员类型是HttpRule结构体。
定义好扩展之后我们就可以从其他的Protobuf文件中使用pbgo的扩展。创建一个hello.proto文件
@ -79,7 +79,7 @@ type Plugin interface {
我们需要在Generate和GenerateImports函数中分别生成相关的代码。而Protobuf文件的全部信息都在*generator.FileDescriptor类型函数参数中描述因此我们需要从函数参数中提前扩展定义的元数据。
pbgo框架中的插件对象是pbgoPlugin在Generate方法中首先需要遍历Protobuf文件中定义的全部服务对应,然后再遍历每个服务对的的每个方法。在得到方法结构之后再通过自定义的getServiceMethodOption方法提取rest扩展信息
pbgo框架中的插件对象是pbgoPlugin在Generate方法中首先需要遍历Protobuf文件中定义的全部服务然后再遍历每个服务的每个方法。在得到方法结构之后再通过自定义的getServiceMethodOption方法提取rest扩展信息
```go
func (p *pbgoPlugin) Generate(file *generator.FileDescriptor) {