RPC 編程 -五-gRPC 中的 Token 認證
- 介紹
gRPC
爲每個gRPC
方法調用提供了Token
認證支持,可以基於用戶傳入的Token
判斷用戶是否登陸、以及權限等...,實現Token
認證的前提是,需要定義一個結構體,並實現grpc.PerRPCCredentials
接口。
1.1 grpc.PerRPCCredentials
type PerRPCCredentials interface {
// 返回需要認證的必要信息
GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)
// 是否使用安全鏈接(TLS)
RequireTransportSecurity() bool
}
- 步驟梳理
-
步驟一: 編寫
proto
文件。 -
步驟二: 生成
go
代碼。 -
步驟三: 實現
grpc.PerRPCCredentials
接口。 -
步驟四: 編寫驗證
token
方法。 -
步驟五: 實現被調用的方法
Test
。 -
步驟六: 編寫服務端代碼
-
步驟七: 編寫客戶端代碼
-
步驟八: 啓動服務 & 發起請求
- 代碼實現
3.1 編寫proto
文件
文件: ./proto/token.proto
syntax = "proto3";
package tokenservice;
option go_package = "server/tokenservice";
// 驗證參數
message TokenValidateParam {
string token = 1;
int32 uid = 2;
}
// 請求參數
message Request {
string name = 1;
}
// 請求返回
message Response {
int32 uid = 1;
string name = 2;
}
// 服務
service TokenService{
rpc Test(Request) returns (Response);
}
3.2 生成Go
代碼
$ protoc --go_out=. --go-grpc_out=. proto/*
3.3 實現grpc.PerRPCCredentials
文件: ./server/tokenservice/token_grpc.pb.go
/**
* @Description: 返回token信息
* @Author: LiuQHui
* @Receiver x
* @Param ctx
* @Param uri
* @Return map[string]string
* @Return error
* @Date 2022-02-21 15:40:44
*/
func (x *TokenValidateParam) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return map[string]string{
"uid": strconv.FormatInt(int64(x.GetUid()),10),
"token": x.GetToken(),
}, nil
}
/**
* @Description: 自定義認證是否開啓TLS
* @Author: LiuQHui
* @Receiver x
* @Return bool
* @Date 2022-02-21 15:40:24
*/
func (x *TokenValidateParam) RequireTransportSecurity() bool {
return false
}
3.4 編寫驗證token
方法
文件: ./server/tokenservice/token.go
package tokenservice
import (
"context"
"crypto/md5"
"fmt"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
// 定義token
type TokenAuth struct{}
func (t TokenAuth) CheckToken(ctx context.Context) (*Response, error) {
// 驗證token
md, b := metadata.FromIncomingContext(ctx)
if !b {
return nil, status.Error(codes.InvalidArgument, "token信息不存在")
}
var token, uid string
// 取出token
tokenInfo, ok := md["token"]
if !ok {
return nil, status.Error(codes.InvalidArgument, "token不存在")
}
token = tokenInfo[0]
// 取出uid
uidTmp, ok := md["uid"]
if !ok {
return nil, status.Error(codes.InvalidArgument, "uid不存在")
}
uid = uidTmp[0]
// 驗證
sum := md5.Sum([]byte(uid))
md5Str := fmt.Sprintf("%x", sum)
if md5Str != token {
fmt.Println("md5Str:", md5Str)
fmt.Println("password:", token)
return nil, status.Error(codes.InvalidArgument, "token驗證失敗")
}
return nil, nil
}
3.5 實現被調用的方法Test
文件: ./server/tokenservice/token_grpc.pb.go
// 匿名TokenAuth,可以直接調用驗證token方法
type UnimplementedTokenServiceServer struct {
TokenAuth
}
/**
* @Description: 實現Test方法(生成的代碼,默認不實現具體邏輯)
* @Author: LiuQHui
* @Receiver u
* @Param ctx
* @Param r
* @Return *Response
* @Return error
* @Date 2022-02-21 17:16:03
*/
func (u UnimplementedTokenServiceServer) Test(ctx context.Context, r *Request) (*Response, error) {
// 驗證token
_, err := u.CheckToken(ctx)
if err != nil {
return nil, err
}
return &Response{Name: r.GetName()}, nil
}
3.6 服務端代碼
文件: ./cmd/token/server.go
package main
import (
"52lu/go-rpc/server/tokenservice"
"fmt"
"google.golang.org/grpc"
"net"
)
func main() {
// 創建grpc服務
grpcServer := grpc.NewServer()
// 註冊服務
tokenservice.RegisterTokenServiceServer(grpcServer, new(tokenservice.UnimplementedTokenServiceServer))
// 監聽端口
listen, err := net.Listen("tcp", ":1234")
if err != nil {
fmt.Println("start error:", err)
return
}
fmt.Println("服務啓動成功....")
grpcServer.Serve(listen)
}
3.7 實現客戶端代碼
文件: ./cmd/token/client.go
package main
import "C"
import (
"52lu/go-rpc/server/tokenservice"
"context"
"fmt"
"google.golang.org/grpc"
)
func main() {
// token信息
auth := tokenservice.TokenValidateParam{
Token: "11223",
Uid: 10000,
}
conn, err := grpc.Dial("127.0.0.1:1234", grpc.WithInsecure(), grpc.WithPerRPCCredentials(&auth))
if err != nil {
fmt.Println("grpc.Dial error ", err)
return
}
defer conn.Close()
// 實例化客戶端
client := tokenservice.NewTokenServiceClient(conn)
// 調用具體方法
test, err := client.Test(context.TODO(), &tokenservice.Request{Name: "張三"})
fmt.Println("return err:", err)
fmt.Println("return result:", test)
}
3.8 啓動 & 請求
# 啓動服務
$ go run cmd/token/server.go
服務啓動成功....
# 發起請求
$ go-rpc go run cmd/token/client.go
return err: rpc error: code = InvalidArgument desc = token驗證失敗
return result: <nil>
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/0zTvDXfVVhj-l7HBknJONw