美文网首页
grpc的token认证

grpc的token认证

作者: 呦丶耍脾气 | 来源:发表于2024-06-01 23:57 被阅读0次

1. 介绍

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
}

2.步骤梳理

  • 步骤一: 编写proto文件。
  • 步骤二: 生成go 代码。
  • 步骤三: 实现grpc.PerRPCCredentials接口。
  • 步骤四: 编写验证token方法。
  • 步骤五: 实现被调用的方法Test
  • 步骤六: 编写服务端代码
  • 步骤七: 编写客户端代码
  • 步骤八: 启动服务 & 发起请求

3. 代码实现

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=. token.proto

3.3 实现grpc.PerRPCCredentials

文件: ./server/tokenservice/token_grpc.pb.go

/**
 * @Description: 返回token信息
 * @Receiver x
 * @Param ctx
 * @Param uri
 * @Return map[string]string
 * @Return error
 */
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
 * @Receiver x
 * @Return bool
 */
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 (
    "studyGrpc.com/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 (
    "studyGrpc.com/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>

相关文章

网友评论

      本文标题:grpc的token认证

      本文链接:https://www.haomeiwen.com/subject/iawcqjtx.html