| 创建时间: | 2019/9/6 13:54 |
|---|---|
| 作者: | sunpengwei1992@aliyun.com |
gRPC安全认证介绍
- gRPC被设计成可以利用插件的形式支持多种授权认证机制,你可以采用自己喜欢的,简单的,认为方便的一种方式,选择权在用户手里
- 支持的授权认证机制如下
- SSL/TLS认证
- 自定义Token认证
- SSL/TLS的概念可以参考下面的文章
https://www.techug.com/post/https-ssl-tls.html
SSL/TLS认证方式
首先通过openssl生成证书和私钥,命令如下
//生成私钥openssl genrsa -out server.key 2048//生成证书openssl req -new -x509 -sha256 -key server.key -out server.crt -days 36500//按照提示输入如下信息国家名称Country Name (2 letter code) [AU]://省名称State or Province Name (full name) [Some-State]://城市名称Locality Name (eg, city) []://理解为公司名称Organization Name (eg, company) [Internet Widgits Pty Ltd]://理解为你所在部门的名称Organizational Unit Name (eg, section) []://你的服务器名称(网站名称)Common Name (e.g. server FQDN or YOUR name) []://联系邮箱Email Address []:
服务端如下
func StartServer() {lis, err := net.Listen("tcp", "127.0.0.1:8090")if err != nil {log.Fatalf("failed to listen: %v", err)}// TLS认证// 两个入参分别是 (certFile, keyFile string)// 自签名证书文件和私钥文件creds, err := credentials.NewServerTLSFromFile("cert", "key")//创建grpcServer传入证书gRpcServer := grpc.NewServer(grpc.Creds(creds))pb.RegisterHelloServiceServer(gRpcServer, &HelloServiceServer{})gRpcServer.Serve(lis)}
客户端如下
func StartClient() {// TLS认证creds, err := credentials.NewClientTLSFromFile("cert", "ServerName")//连接服务器conn, err := grpc.Dial("127.0.0.1:8090",grpc.WithTransportCredentials(creds) )if err != nil{fmt.Println(err)return}c := pb.NewHelloServiceClient(conn)//ctx, cancel := context.WithTimeout(context.Background(), time.Second)defer cancel()r, err := c.HelloWorldClientAndServerStream(ctx, grpc.EmptyCallOption{})if err != nil {log.Fatalf("%v", err)return}r.Send(&pb.HelloRequest{Request: "my is golang gRpc client "})r.CloseSend()}
Token认证
我们先看一个gRPC提供我们的一个接口,这个接口终有两个方法,接口位于credentials
包下,这个接口需要客户端来实现- 第一个方法作用是获取元数据信息,也就是客户端提供的key,value对,context用于控制超时和取消,uri是请求入口处的uri
第二个方法的作用是否需要基于 TLS 认证进行安全传输是,如果返回值是true,则必须加上TLS验证,返回值是false则不用
type PerRPCCredentials interface {GetRequestMetadata(ctx context.Context, uri ...string)(map[string]string, error)RequireTransportSecurity() bool}
客户端端实现接口,代码如下
//自定义token认证type CustomerTokenAuth struct {}//获取元数据func (c CustomerTokenAuth) GetRequestMetadata(ctx context.Context,uri...string) (map[string]string, error) {return map[string]string{"appId": "master","appkey": "1aqfs5g456j",}, nil}//是否开启传输安全 TLSfunc (c CustomerTokenAuth) RequireTransportSecurity() bool {return false}
客户端按照如下方式使用
var opts []grpc.DialOption//grpc.WithInsecure()这个是一定要添加的,代表开启安全的选项opts =append(opts,grpc.WithInsecure())//添加自定义token验证opts = append(opts,grpc.WithPerRPCCredentials(new(CustomerTokenAuth)))//连接服务端conn, err := grpc.Dial("127.0.0.1:8090",opts...)
服务端按照如下方式校验,当然我们也可以使用拦截器的形式对每个方法进行拦截,而不是像如下在每个方法中硬编码是的。
type HelloServiceServer struct {}//这是服务端实现的一个方法func (*HelloServiceServer2) HelloWorld(ctx context.Context,req *pb.HelloRequest) (*pb.HelloResponse, error) {//获取元数据信息md,ok := metadata.FromIncomingContext(ctx)if !ok {return nil,errors.New("未传输token")}var (appId stringappKey string)if val, ok := md["appId"]; ok {appid = val[0]}if val, ok := md["appKey"]; ok {appkey = val[0]}//进行校验的信息是否正确if appid != "123" || appkey != "456" {return nil, errors.New("token传输不正确")}return &pb.HelloResponse{Response: "hello my is gRpcServer"}, nil}
总结
gRPC将各种认证方式浓缩统一到一个凭证(credentials)上,可以单独使用一种凭证,比如只使用TLS凭证或者只使用自定义凭证,也可以多种凭证组合,gRPC提供统一的API验证机制,使研发人员使用方便,这也是gRPC设计的巧妙之处
欢迎大家关注微信公众号:“golang那点事”,更多精彩期待你的到来
