type PerRPCCredentials
传token需要实现这个接口
type PerRPCCredentials interface {
// GetRequestMetadata gets the current request metadata, refreshing
// tokens if required. This should be called by the transport layer on
// each request, and the data should be populated in headers or other
// context. If a status code is returned, it will be used as the status
// for the RPC. uri is the URI of the entry point for the request.
// When supported by the underlying implementation, ctx can be used for
// timeout and cancellation. Additionally, RequestInfo data will be
// available via ctx to this call.
// TODO(zhaoq): Define the set of the qualified keys instead of leaving
// it as an arbitrary string.
GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)
// RequireTransportSecurity indicates whether the credentials requires
// transport security.
RequireTransportSecurity() bool
}
type TransportCredentials
type TransportCredentials interface {
// ClientHandshake does the authentication handshake specified by the
// corresponding authentication protocol on rawConn for clients. It returns
// the authenticated connection and the corresponding auth information
// about the connection. The auth information should embed CommonAuthInfo
// to return additional information about the credentials. Implementations
// must use the provided context to implement timely cancellation. gRPC
// will try to reconnect if the error returned is a temporary error
// (io.EOF, context.DeadlineExceeded or err.Temporary() == true). If the
// returned error is a wrapper error, implementations should make sure that
// the error implements Temporary() to have the correct retry behaviors.
// Additionally, ClientHandshakeInfo data will be available via the context
// passed to this call.
//
// If the returned net.Conn is closed, it MUST close the net.Conn provided.
ClientHandshake(context.Context, string, net.Conn) (net.Conn, AuthInfo, error)
// ServerHandshake does the authentication handshake for servers. It returns
// the authenticated connection and the corresponding auth information about
// the connection. The auth information should embed CommonAuthInfo to return additional information
// about the credentials.
//
// If the returned net.Conn is closed, it MUST close the net.Conn provided.
ServerHandshake(net.Conn) (net.Conn, AuthInfo, error)
// Info provides the ProtocolInfo of this TransportCredentials.
Info() ProtocolInfo
// Clone makes a copy of this TransportCredentials.
Clone() TransportCredentials
// OverrideServerName overrides the server name used to verify the hostname on the returned certificates from the server.
// gRPC internals also use it to override the virtual hosting name if it is set.
// It must be called before dialing. Currently, this is only used by grpclb.
OverrideServerName(string) error
}
func NewClientTLSFromFile(certFile, serverNameOverride string) (TransportCredentials, error)
- NewClientTLSFromFile从客户机的输入证书文件构造TLS凭据。serverNameOverride仅用于测试。如果设置为非空字符串,它将覆盖请求中权限的虚拟主机名(例如:权限头字段)。
func NewServerTLSFromFile(certFile, keyFile string) (TransportCredentials, error)
- NewServerTLSFromFile从服务器的输入证书文件和密钥文件构造TLS凭据
使用tls加密传输
1.安装openssl,使用openssl生成公钥与私钥
1.生成RSA私钥:openssl genrsa -out server.key 2048
命令的最后一个参数,将指定生成密钥的位数,如果没有指定,默认512
2.生成公钥 openssl req -new -x509 -sha256 -key server.key -out server.pem -days 3650
openssl req:生成自签名证书,
-new指生成证书请求、
-sha256指使用sha256加密、
-key指定私钥文件、
-x509指输出证书、
-days 3650为有效期
此后则输入证书拥有者信息
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:XxXx
Locality Name (eg, city) []:XxXx
Organization Name (eg, company) [Internet Widgits Pty Ltd]:XX Co. Ltd
Organizational Unit Name (eg, section) []:Dev
Common Name (e.g. server FQDN or YOUR name) []:go-grpc-example
Email Address []:xxx@xxx.com
2.client端
package main
import (
"google.golang.org/grpc"
"grpcSSLCode/message"
"context"
"google.golang.org/grpc/grpclog"
"fmt"
"google.golang.org/grpc/credentials"
)
func main() {
//TLS连接
creds, err := credentials.NewClientTLSFromFile("./keys/server.pem", "go-grpc-example")
if err != nil {
panic(err.Error())
}
//1、Dail连接
conn, err := grpc.Dial("localhost:8092", grpc.WithTransportCredentials(creds))
if err != nil {
panic(err.Error())
}
defer conn.Close()
.....
}
3.服务端
package main
import (
"context"
"grpcSSLCode/message"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/grpclog"
"net"
)
type MathManager struct {
}
func (mm *MathManager) AddMethod(ctx context.Context, request *message.RequestArgs) (response *message.Response, err error) {
....
return response, nil
}
func main() {
grpc.WithPerRPCCredentials()
//TLS认证
creds, err := credentials.NewServerTLSFromFile("./keys/server.pem", "./keys/server.key")
if err != nil {
grpclog.Fatal("加载在证书文件失败", err)
}
//实例化grpc server, 开启TLS认证
server := grpc.NewServer(grpc.Creds(creds))
message.RegisterMathServiceServer(server, new(MathManager))
lis, err := net.Listen("tcp", ":8092")
if err != nil {
panic(err.Error())
}
server.Serve(lis)
}
使用Token+tls
1.client端
package main
import (
"google.golang.org/grpc"
"gRPCTokenCode/message"
"context"
"google.golang.org/grpc/grpclog"
"fmt"
"google.golang.org/grpc/credentials"
)
//token认证
type TokenAuthentication struct {
AppKey string
AppSecret string
}
//组织token认证的metadata信息
func (ta *TokenAuthentication) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"appid": ta.AppKey,
"appkey": ta.AppSecret,
}, nil
}
//是否基于TLS认证进行安全传输
func (a *TokenAuthentication) RequireTransportSecurity() bool {
return true
}
func main() {
//TLS连接
creds, err := credentials.NewClientTLSFromFile("./keys/server.pem", "go-grpc-example")
if err != nil {
panic(err.Error())
}
auth := TokenAuthentication{
AppKey: "hello1",
AppSecret: "20190812",
}
//1、Dail连接
conn, err := grpc.Dial("localhost:8093", grpc.WithTransportCredentials(creds), grpc.WithPerRPCCredentials(&auth))
if err != nil {
panic(err.Error())
}
defer conn.Close()
...
}
2.server端
package main
import (
"context"
"gRPCTokenCode/message"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/grpclog"
"net"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/grpc/metadata"
)
type MathManager struct {
}
func (mm *MathManager) AddMethod(ctx context.Context, request *message.RequestArgs) (response *message.Response, err error) {
//通过metadata
md, exist := metadata.FromIncomingContext(ctx)
if !exist {
return nil, status.Errorf(codes.Unauthenticated, "无Token认证信息")
}
var appKey string
var appSecret string
if key, ok := md["appid"]; ok {
appKey = key[0]
}
if secret, ok := md["appkey"]; ok {
appSecret = secret[0]
}
if appKey != "hello" || appSecret != "20190812" {
return nil, status.Errorf(codes.Unauthenticated, "Token 不合法")
}
....
return response, nil
}
func main() {
//TLS认证
creds, err := credentials.NewServerTLSFromFile("./keys/server.pem", "./keys/server.key")
if err != nil {
grpclog.Fatal("加载在证书文件失败", err)
}
//实例化grpc server, 开启TLS认证
server := grpc.NewServer(grpc.Creds(creds),grpc.UnaryInterceptor())
message.RegisterMathServiceServer(server, new(MathManager))
lis, err := net.Listen("tcp", ":8093")
if err != nil {
panic(err.Error())
}
.....
server.Serve(lis)
}