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命令的最后一个参数,将指定生成密钥的位数,如果没有指定,默认5122.生成公钥 openssl req -new -x509 -sha256 -key server.key -out server.pem -days 3650openssl req:生成自签名证书,-new指生成证书请求、-sha256指使用sha256加密、-key指定私钥文件、-x509指输出证书、-days 3650为有效期此后则输入证书拥有者信息Country Name (2 letter code) [AU]:CNState or Province Name (full name) [Some-State]:XxXxLocality Name (eg, city) []:XxXxOrganization Name (eg, company) [Internet Widgits Pty Ltd]:XX Co. LtdOrganizational Unit Name (eg, section) []:DevCommon Name (e.g. server FQDN or YOUR name) []:go-grpc-exampleEmail Address []:xxx@xxx.com
2.client端
package mainimport ("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 mainimport ("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 mainimport ("google.golang.org/grpc""gRPCTokenCode/message""context""google.golang.org/grpc/grpclog""fmt""google.golang.org/grpc/credentials")//token认证type TokenAuthentication struct {AppKey stringAppSecret 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 mainimport ("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) {//通过metadatamd, exist := metadata.FromIncomingContext(ctx)if !exist {return nil, status.Errorf(codes.Unauthenticated, "无Token认证信息")}var appKey stringvar appSecret stringif 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)}
