在前面 grpc之golang的简单使用 增加一个请求权限验证
- 在proto下面新建token目录,添加token.proto文件
syntax = "proto3";
//option java_package = "com.colobu.rpctest";
package token;
option go_package = "/";
// The greeting service definition.
service Token {
// Sends a greeting
rpc GetToken (UserRequest) returns (TokenData) {}
rpc TestToken (TokenData) returns (TestTokenResponse){}
}
message UserRequest {
string userName = 1;
string passWord = 2;
}
message TokenData {
string accessToken = 1;
}
message TestTokenResponse {
bool ispass = 1;
string message = 2;
}
然后在当前目录生成文件
protoc --go_out=. --go-grpc_out=. token.proto
- 在server目录下面新建token.go
package server
import (
"context"
"encoding/json"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
token "rpc/proto/token"
"rpc/tool"
)
type Token struct {
token.UnimplementedTokenServer
}
// 生成token
func (s *Token) GetToken(ctx context.Context, in *token.UserRequest) (*token.TokenData, error) {
md, _ := metadata.FromIncomingContext(ctx)
var name, passwrod string
if value, ok := md["username"]; ok {
name = value[0]
}
if value, ok := md["password"]; ok {
passwrod = value[0]
}
var usrInfo token.UserRequest
usrInfo.UserName = name
usrInfo.PassWord = passwrod
userjson, _ := json.Marshal(usrInfo)
tokenStr := tool.TokenEnCode(string(userjson))
return &token.TokenData{AccessToken: tokenStr}, nil
}
// 验证token
func (t *Token) Check(ctx context.Context) error {
// 从上下文章获取元数据
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return status.Errorf(codes.Unauthenticated, "获取token失败")
}
var str string
if value, ok := md["accesstoken"]; ok {
str = value[0]
}
tokenStr := tool.TokenDeCode(str)
var user token.UserRequest
json.Unmarshal([]byte(tokenStr), &user)
if user.UserName != "wms" || user.PassWord != "123456" {
return status.Errorf(codes.Unauthenticated, "Token无效")
}
return nil
}
方法中的用户名密码没有保存到数据库,只是做简单测试。 3. 根目录下面建立tool文件夹,放加密方法 加密库用的是github.com/golang-module/dongle
go get github.com/golang-module/dongle
package tool
import "github.com/golang-module/dongle"
func TokenEnCode(str string) string {
return dongle.Encode.FromString(dongle.Encode.FromString(string(str)).ByBase64().ToString()).ByHex().ToString()
}
func TokenDeCode(str string) string {
return dongle.Decode.FromString(dongle.Decode.FromString(str).ByHex().ToString()).ByBase64().ToString()
}
- 在server文件夹下面的carrier文件中的rpc方法增加token验证
func (carrier *Carrier) GetCarrier(ctx context.Context, in *rca.CarrierRequest) (*rca.CarrierMsg, error) {
// 检测Token是否有效
if err := tToken.Check(ctx); err != nil {
return nil, err
}
return &rca.CarrierMsg{Id:1,Name:"test"}, nil
}
func (carrier *Carrier) GetCarriers(ctx context.Context, in *rca.CarriersRequest) (*rca.CarriersReply, error) {
// 检测Token是否有效
if err := tToken.Check(ctx); err != nil {
return nil, err
}
return &rca.CarriersReply{Page:1,PageSize:10,CarrierInfo:nil}, nil
}
- 然后启动server
go run server.go
- 客户端请求metadata增加 accessToken 字段
package main
import (
"context"
"flag"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"log"
rca "rpc/proto/carrier"
"time"
)
type CAuth struct {
}
func (c CAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
//TODO implement me
return map[string]string{
"accessToken": "65794a3163325679546d46745a534936496e647463794973496e426863334e5862334a6b496a6f694d54497a4e445532496e303d",
}, nil
}
func (c CAuth) RequireTransportSecurity() bool {
return false
}
func main() {
var addr = flag.String("addr", "ip:50051", "the address to connect to")
flag.Parse()
var opts []grpc.DialOption
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
opts = append(opts, grpc.WithPerRPCCredentials(new(CAuth)))
conn, err := grpc.Dial(*addr, opts...)
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := rca.NewCarrierClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
r1, err := c.GetCarrier(ctx, &rca.CarrierRequest{Name: "sdfsdfsdf"})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Carrier: %s", r1.GetName())
}
- 或者用postman请求在metadata添加 accessToken 如果没有带token会拦截请求