gRPC Token认证
2021-03-30 本文已影响0人
Feng_Sir
服务端
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// Package main implements a server for Greeter service.
package main
import (
"context"
"fmt"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
"log"
"net"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
port = ":50051"
)
// server is used to implement helloworld.GreeterServer.
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func (s *server) SayHelloAgain(ctx context.Context, in *pb.HelloRequestList) (*pb.HelloReplyList, error) {
log.Printf("Received Hello again: %v", in.GetName())
result := []string{}
for i, v := range in.Name {
result = append(result, "Hello again "+fmt.Sprint(i)+v)
}
return &pb.HelloReplyList{Message: result}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
//普通方法:一元拦截器(grpc.UnaryInterceptor)
var interceptor grpc.UnaryServerInterceptor
interceptor = func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
//拦截普通方法请求,验证Token
err = Check(ctx)
if err != nil {
return
}
// 继续处理请求
return handler(ctx, req)
}
s := grpc.NewServer(grpc.UnaryInterceptor(interceptor))
pb.RegisterGreeterServer(s, &server{})
log.Println("server start:", port)
if err := s.Serve(lis); err != nil {
log.Fatalf("failed to serve: %v", err)
}
}
// Check 验证token
func Check(ctx context.Context) error {
//从上下文中获取元数据
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return status.Errorf(codes.Unauthenticated, "获取Token失败")
}
var (
appID string
appSecret string
)
if value, ok := md["app_id"]; ok {
appID = value[0]
}
if value, ok := md["app_secret"]; ok {
appSecret = value[0]
}
if appID != "grpc_token" || appSecret != "123456" {
return status.Errorf(codes.Unauthenticated, "Token无效: app_id=%s, app_secret=%s", appID, appSecret)
}
return nil
}
grpc.UnaryServerInterceptor
:为一元拦截器,只会拦截简单RPC方法。流式RPC方法需要使用流式拦截器grpc.StreamInterceptor
进行拦截。
客户端
/*
*
* Copyright 2015 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// Package main implements a client for Greeter service.
package main
import (
"context"
"log"
"os"
"time"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
address = "localhost:50051"
defaultName = "world"
)
//grpc Token认证
/*gRPC 中默认定义了 PerRPCCredentials,是提供用于自定义认证的接口,它的作用是将所需的安全认证信息添加到每个RPC方法的上下文中。其包含 2 个方法:
GetRequestMetadata:获取当前请求认证所需的元数据
RequireTransportSecurity:是否需要基于 TLS 认证进行安全传输
*/
type methodTestCreds struct {
AppId string
AppSecret string
}
//GetRequestMetadata:获取当前请求认证所需的元数据
func (m *methodTestCreds) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{"app_id": m.AppId, "app_secret": m.AppSecret}, nil
}
//RequireTransportSecurity:是否需要基于 TLS 认证进行安全传输
func (m *methodTestCreds) RequireTransportSecurity() bool { return false }
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithPerRPCCredentials(&methodTestCreds{
// "grpc_token",
// "123456",
}),
grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
// Contact the server and print out its response.
name := defaultName
if len(os.Args) > 1 {
name = os.Args[1]
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
rs, err := c.SayHelloAgain(ctx, &pb.HelloRequestList{Name: []string{"xiaoming", "xiaowang"}})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
for i, v := range rs.GetMessage() {
log.Println(i, v)
}
}