• http-自签证书


    1. 背景

    证书需要向云服务提供商购买,是需要付费,但用在应用开发场景是不合适的,需要开发者自己自签证书进行测试

    2. 工具包

    • Cygwin
    a large collection of GNU and Open Source tools which provide functionality similar to a 
    Linux distribution
     on Windows
     
    a DLL (cygwin1.dll) which provides substantial POSIX API functionality
    
    下载地址: http://www.cygwin.com/
    
    详细安装教程: https://blog.csdn.net/u010356768/article/details/90756742
    

    3. 生成CA证书

    CA -- 根证书,是属于根证书颁发机构(CA)的公钥证书,用以验证他签发的证书(客户端和服务端)

    • 生成CA证书 -- key
    # 创建 cert目录,进入该目录,作为证书保存目录
    # 在目录下启动命令终端
    openssl genrsa -out ca.key 4096
    # 会在 cert目录下生成 ca.key文件,该文件作为生成证书-cert文件基础文件
    
    • 生成CA证书 - crt
    openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
    # -new 生成新的证书
    # -days 证书的有效时间
    # -key 指定ca证书key文件路径
    # -out CA证书保存位置
    # CA证书,这里的Common Name 是CA证书的颁发者 -- beimenchuixue -- 自定义即可
    # 其他可以为空
    
    # 会要求填写下列信息
    # Country Name -- 国名 -- cn
    # State or Province -- 州或省名 -- beijing
    # Locality Name -- 城市或区域名 --beijing
    # Organization Name -- 组织名 -- jtthink
    # Organizational Unit Name -- 组织单位名 -- jt
    # Common Name -- 域名(要求一致) -- localhost --> 这个才是最重要的
    # Email Address -- 邮箱地址 -- 可以不填
    

    4. 生成服务端证书

    • 生成服务端证书 - key
    openssl genrsa -out server.key 4096
    # 服务端证书 key
    
    • 新建 tls.conf 文件,并写入以下内容,该文件作为生成客户端证书与服务端证书根文件
    # 新建 tls.conf文件,写入以下内容
    [ req ]
    default_bits = 4096
    distinguished_name = req_distinguished_name
    req_extensions = v3_req
    prompt = no # 不使用提示符,进入交互界面,因为使用默认会得到一个空主题,所以报错
    
    [req_distinguished_name]
    # countryName = cn
    # stateOrProvinceName = beijing
    # localityName = beijing
    # organizationName = company name
    commonName = beimenchuixue
    
    [ v3_req ] 
    subjectAltName = @alt_names
    
    [ alt_names ]
    DNS.1=localhost #可以使用通配符
    IP.1=127.0.0.1
    
    • 生成服务端 csr 文件
    openssl req -new -key server.key -out server.csr -config tls.conf -sha256
    # 生成服务端 server.csr 文件
    
    • 依据CA证书签发服务端证书
    openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt -extfile tls.conf -extensions v3_req
    # 签发证书 生成服务端 server.crt文件
    

    5. 生成客户端证书

    • 生成客户端证书 - key
    openssl genrsa -out client.key 4096
    # 客户端证书 key
    
    • 生成客户端 csr 文件
    openssl req -new -key client.key -out client.csr -config tls.conf -sha256
    # 生成客户端 client.csr文件
    # 使用的 tls文件与服务使用的一致
    
    • 依据CA证书签发客户端证书
    openssl x509 -req -days 3650 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt -extfile tls.conf -extensions v3_req
    # 生成客户端证书文件 client.crt
    

    6. Grpc服务端带证书验证 -- 双向验证

    package main
    
    import (
       "context"
       "crypto/tls"
       "crypto/x509"
       "fmt"
       "google.golang.org/grpc"
       "google.golang.org/grpc/credentials"
       "io/ioutil"
       "learn-go-project/service"
       "log"
       "net"
    )
    
    // ImplementProductService 定义产品服务实现类
    type ImplementProductService struct {
       
    }
    
    // GetProductStoreNums 实现 proto buffer文件中service 定义的rpc方法 ==> 实现 pb文件中 rpc方法生成的接口
    func (s *ImplementProductService) GetProductStoreNums(ctx context.Context, in *service.ProductRequest) (*service.ProductResponse, error) {
       fmt.Println(in.GetProductId())
       return &service.ProductResponse{ProductStore: 20}, nil
    }
    
    func main() {
    
       // 1. 服务端的证书, 证书文件都保存在项目的cert目录下或其他指定项目目录下
       cert, err := tls.LoadX509KeyPair("cert/server.crt", "cert/server.key")
       if err != nil {
          log.Fatalln(err)
       }
       // 2. ca证书
       ca, err := ioutil.ReadFile("cert/ca.crt")
       if err != nil {
          log.Fatalln(err)
       }
       // 3. 证书池添加CA证书
       certPool := x509.NewCertPool()
       certPool.AppendCertsFromPEM(ca)
    
       // 4. 生成证书对象
       certs := credentials.NewTLS(&tls.Config{
          Certificates: []tls.Certificate{cert},
          ClientAuth: tls.RequireAndVerifyClientCert,
          ClientCAs: certPool,
       })
    
       // 1. 声明一个grpc服务, 配置cert证书
       grpcService := grpc.NewServer(grpc.Creds(certs))
    
       // 2. 将实现类注册到生成的pd文件中
       service.RegisterProductServiceServer(grpcService, &ImplementProductService{})
    
       // 3. 启动tcp服务
       l, err := net.Listen("tcp", ":9988")
       if err != nil {
          log.Fatalln(err)
       }
    
       // 3. 让grp去处理tcp连接
       err = grpcService.Serve(l)
       if err != nil {
          log.Fatalln(err)
       }
    }
    

    6. Grpc客户端带证书验证 -- 双向验证

    package main
    
    import (
       "context"
       "crypto/tls"
       "crypto/x509"
       "fmt"
       "google.golang.org/grpc"
       "google.golang.org/grpc/credentials"
       "io/ioutil"
       "learn-go-project/service"
       "log"
    )
    
    func main() {
       // 1. 服务端的证书
       cert, err := tls.LoadX509KeyPair("cert/client.crt", "cert/client.key")
       if err != nil {
          log.Fatalln(err)
       }
       // 2. ca证书
       ca, err := ioutil.ReadFile("cert/ca.crt")
       if err != nil {
          log.Fatalln(err)
       }
       // 3. 证书池添加CA证书
       certPool := x509.NewCertPool()
       certPool.AppendCertsFromPEM(ca)
    
       // 4. 生成证书对象
       certs := credentials.NewTLS(&tls.Config{
          Certificates: []tls.Certificate{cert},    // 加载客户端证书
          RootCAs: certPool,                   // CA根证书
       })
    
       // 1. 创建grpc客户端连接, 使用cert证书
       conn, err := grpc.Dial("127.0.0.1:9988", grpc.WithTransportCredentials(certs))
       if err != nil {
          log.Fatalln(err)
       }
       defer conn.Close()
    
       // 2. 创建对应服务的连接
       cli := service.NewProductServiceClient(conn)
    
       // 3. 调用方法,获取响应体
       response, err := cli.GetProductStoreNums(context.Background(), &service.ProductRequest{ProductId: 50})
       if err != nil {
          log.Fatalln(err)
       }
    
       fmt.Println(response.ProductStore)
    }
    

    7. Grpc服务端带证书认证 -- 单向认证

    package main
    
    import (
       "context"
       "fmt"
       "google.golang.org/grpc"
       "google.golang.org/grpc/credentials"
       "learn-go-project/service"
       "log"
       "net"
    )
    
    // ImplementProductService 定义产品服务实现类
    type ImplementProductService struct {
       
    }
    
    // GetProductStoreNums 实现 proto buffer文件中service 定义的rpc方法 ==> 实现 pb文件中 rpc方法生成的接口
    func (s *ImplementProductService) GetProductStoreNums(ctx context.Context, in *service.ProductRequest) (*service.ProductResponse, error) {
       fmt.Println(in.GetProductId())
       return &service.ProductResponse{ProductStore: 100}, nil
    }
    
    func main() {
       // 单向认证 客户端与服务端公用同一个crt文件
       cert, err := credentials.NewServerTLSFromFile("cert/server.crt", "cert/server.key")
       if err != nil {
          log.Fatalln(err)
       }
       // 1. 声明一个grpc服务, 配置cert证书
       grpcService := grpc.NewServer(grpc.Creds(cert))
    
       // 2. 将实现类注册到生成的pd文件中
       service.RegisterProductServiceServer(grpcService, &ImplementProductService{})
    
       // 3. 启动tcp服务
       l, err := net.Listen("tcp", ":9988")
       if err != nil {
          log.Fatalln(err)
       }
    
       // 3. 让grp去处理tcp连接
       err = grpcService.Serve(l)
       if err != nil {
          log.Fatalln(err)
       }
    }
    

    8. Grpc客户端带证书认证 -- 单向认证

    package main
    
    import (
       "context"
       "fmt"
       "google.golang.org/grpc"
       "google.golang.org/grpc/credentials"
       "learn-go-project/service"
       "log"
    )
    
    func main() {
       // 服务端和客户端公用同一个由CA证书签发的crt和key文件,客户端只需要服务端的crt文件
       cert, err := credentials.NewClientTLSFromFile("cert/server.crt", "localhost")
       if err != nil {
          log.Fatalln(err)
       }
    
       // 1. 创建grpc客户端连接, 使用cert证书
       conn, err := grpc.Dial("127.0.0.1:9988", grpc.WithTransportCredentials(cert))
       if err != nil {
          log.Fatalln(err)
       }
       defer conn.Close()
    
       // 2. 创建对应服务的连接
       cli := service.NewProductServiceClient(conn)
    
       // 3. 调用方法,获取响应体
       response, err := cli.GetProductStoreNums(context.Background(), &service.ProductRequest{ProductId: 50})
       if err != nil {
          log.Fatalln(err)
       }
    
       fmt.Println(response.ProductStore)
    }
    
  • 相关阅读:
    天下没有不会这么回事!不会就学——北漂18年(28)
    Python Module_sys/random
    Python Module_sys/random
    redis 主从切换
    第一章 数据引用与匿名存储
    第12章 对象上
    zabbix 发送邮件配置
    第10章 包 名字空间,变量和函数
    perl 类 对象 方法
    perl数据结构输出 Data::Dumper
  • 原文地址:https://www.cnblogs.com/2bjiujiu/p/15208144.html
Copyright © 2020-2023  润新知