package main import ( "context" "crypto/tls" "crypto/x509" "fmt" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/credentials" "google.golang.org/grpc/metadata" "google.golang.org/grpc/status" "io/ioutil" "log" "net" "zjtd.com/myproto/service" ) func main() { ////添加单向证书 //creds, err2 := credentials.NewServerTLSFromFile("cert/server.pem", "cert/server.key") //if err2 != nil { // log.Fatal("证书生成错误", err2) //} //添加双向证书 cert, err := tls.LoadX509KeyPair("cert/server.pem", "cert/server.key") if err != nil { log.Fatal("证书读取错误", err) } // 创建一个新的、空的 CertPool certPool := x509.NewCertPool() ca, err := ioutil.ReadFile("cert/ca.crt") if err != nil { log.Fatal("ca证书读取错误", err) } // 尝试解析所传入的 PEM 编码的证书。如果解析成功会将其加到 CertPool 中,便于后面的使用 certPool.AppendCertsFromPEM(ca) // 构建基于 TLS 的 TransportCredentials 选项 creds := credentials.NewTLS(&tls.Config{ // 设置证书链,允许包含一个或多个 Certificates: []tls.Certificate{cert}, // 要求必须校验客户端的证书。可以根据实际情况选用以下参数 ClientAuth: tls.RequireAndVerifyClientCert, // 设置根证书的集合,校验方式使用 ClientAuth 中设定的模式 ClientCAs: certPool, }) //实现token认证,需要合法的用户名和密码 //实现一个拦截器 var AuthInterceptor grpc.UnaryServerInterceptor AuthInterceptor = func( ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { //拦截普通方法请求,验证tokrn err = Auth(ctx) if err != nil { return } return handler(ctx, req) } recServer := grpc.NewServer(grpc.Creds(creds), grpc.UnaryInterceptor(AuthInterceptor)) //new一个服务端 //recServer := grpc.NewServer(grpc.Creds(creds)) //service 是我们自己的包,里面有一个RegisterProServiceServer的方法注册一个服务 //接口实现service.ProductService被注册上了 // service.RegisterProServiceServer(服务端, 实现主体函数的任意实例 interface{}) service.RegisterProServiceServer(recServer, service.ProductService) fmt.Println("认证成功") listener, err := net.Listen("tcp", ":8008") if err != nil { log.Fatalln("启动监听失败", err) } err = recServer.Serve(listener) if err != nil { log.Fatalln("启动服务失败", err) } fmt.Println("启动gRPC服务成功") } func Auth(ctx context.Context) error { //实际上拿到传输的用户名和密码 md, ok := metadata.FromIncomingContext(ctx) if !ok { return fmt.Errorf("missing credentials") } var user string var password string if val, ok := md["user.proto"]; ok { user = val[0] } if val, ok := md["password"]; ok { password = val[0] } if user != "hyh" || password != "123456" { return status.Error(codes.Unauthenticated, "token不合法") } return nil }