补充grpc认证
This commit is contained in:
parent
afa7743e82
commit
4a0ed93617
56
skills/rpc/protobuf/hello_service/client_auther.go
Normal file
56
skills/rpc/protobuf/hello_service/client_auther.go
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
package hello_service
|
||||||
|
|
||||||
|
import context "context"
|
||||||
|
|
||||||
|
// PerRPCCredentials defines the common interface for the credentials which need to
|
||||||
|
// attach security information to every RPC (e.g., oauth2).
|
||||||
|
// type PerRPCCredentials interface {
|
||||||
|
// // GetRequestMetadata gets the current request metadata, refreshing tokens
|
||||||
|
// // if required. This should be called by the transport layer on each
|
||||||
|
// // request, and the data should be populated in headers or other
|
||||||
|
// // context. If a status code is returned, it will be used as the status for
|
||||||
|
// // the RPC (restricted to an allowable set of codes as defined by gRFC
|
||||||
|
// // A54). uri is the URI of the entry point for the request. When supported
|
||||||
|
// // by the underlying implementation, ctx can be used for timeout and
|
||||||
|
// // cancellation. Additionally, RequestInfo data will be available via ctx
|
||||||
|
// // to this call. TODO(zhaoq): Define the set of the qualified keys instead
|
||||||
|
// // of leaving it as an arbitrary string.
|
||||||
|
// GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)
|
||||||
|
// // RequireTransportSecurity indicates whether the credentials requires
|
||||||
|
// // transport security.
|
||||||
|
// RequireTransportSecurity() bool
|
||||||
|
// }
|
||||||
|
|
||||||
|
func NewClientAuthentication(clientId, clientSecret string) *Authentication {
|
||||||
|
return &Authentication{
|
||||||
|
clientID: clientId,
|
||||||
|
clientSecret: clientSecret,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authentication todo
|
||||||
|
type Authentication struct {
|
||||||
|
clientID string
|
||||||
|
clientSecret string
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithClientCredentials todo
|
||||||
|
func (a *Authentication) WithClientCredentials(clientID, clientSecret string) {
|
||||||
|
a.clientID = clientID
|
||||||
|
a.clientSecret = clientSecret
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRequestMetadata todo
|
||||||
|
func (a *Authentication) GetRequestMetadata(context.Context, ...string) (
|
||||||
|
map[string]string, error,
|
||||||
|
) {
|
||||||
|
return map[string]string{
|
||||||
|
ClientHeaderKey: a.clientID,
|
||||||
|
ClientSecretKey: a.clientSecret,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequireTransportSecurity todo
|
||||||
|
func (a *Authentication) RequireTransportSecurity() bool {
|
||||||
|
return false
|
||||||
|
}
|
90
skills/rpc/protobuf/hello_service/middleware.go
Normal file
90
skills/rpc/protobuf/hello_service/middleware.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package hello_service
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/infraboard/mcube/v2/ioc/config/log"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/metadata"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ClientHeaderKey = "client-id"
|
||||||
|
ClientSecretKey = "client-secret"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GrpcAuthUnaryServerInterceptor returns a new unary server interceptor for auth.
|
||||||
|
func GrpcAuthUnaryServerInterceptor() grpc.UnaryServerInterceptor {
|
||||||
|
return newGrpcAuther().Auth
|
||||||
|
}
|
||||||
|
|
||||||
|
func newGrpcAuther() *grpcAuther {
|
||||||
|
return &grpcAuther{
|
||||||
|
log: log.Sub("Grpc Auther"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnaryServerInterceptor provides a hook to intercept the execution of a unary RPC on the server. info
|
||||||
|
// contains all the information of this RPC the interceptor can operate on. And handler is the wrapper
|
||||||
|
// of the service method implementation. It is the responsibility of the interceptor to invoke handler
|
||||||
|
// to complete the RPC.
|
||||||
|
// type UnaryServerInterceptor func(ctx context.Context, req any, info *UnaryServerInfo, handler UnaryHandler) (resp any, err error)
|
||||||
|
// internal todo
|
||||||
|
type grpcAuther struct {
|
||||||
|
log *zerolog.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *grpcAuther) Auth(
|
||||||
|
ctx context.Context, req any,
|
||||||
|
info *grpc.UnaryServerInfo,
|
||||||
|
handler grpc.UnaryHandler,
|
||||||
|
) (resp any, err error) {
|
||||||
|
// http2 header -> metadata
|
||||||
|
// 重上下文中获取认证信息
|
||||||
|
md, ok := metadata.FromIncomingContext(ctx)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("ctx is not an grpc incoming context")
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("gprc header info: ", md)
|
||||||
|
|
||||||
|
clientId, clientSecret := a.GetClientCredentialsFromMeta(md)
|
||||||
|
|
||||||
|
// 校验调用的客户端凭证是否有效
|
||||||
|
if err := a.validateServiceCredential(clientId, clientSecret); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 把请求交给后续的Handler处理
|
||||||
|
resp, err = handler(ctx, req)
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *grpcAuther) GetClientCredentialsFromMeta(md metadata.MD) (
|
||||||
|
clientId, clientSecret string) {
|
||||||
|
cids := md.Get(ClientHeaderKey)
|
||||||
|
sids := md.Get(ClientSecretKey)
|
||||||
|
if len(cids) > 0 {
|
||||||
|
clientId = cids[0]
|
||||||
|
}
|
||||||
|
if len(sids) > 0 {
|
||||||
|
clientSecret = sids[0]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *grpcAuther) validateServiceCredential(clientId, clientSecret string) error {
|
||||||
|
if clientId == "" && clientSecret == "" {
|
||||||
|
return status.Errorf(codes.Unauthenticated, "client_id or client_secret is \"\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !(clientId == "admin" && clientSecret == "123456") {
|
||||||
|
return status.Errorf(codes.Unauthenticated, "client_id or client_secret invalidate")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
@ -12,7 +12,8 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// 首先是通过grpc.NewServer()构造一个gRPC服务对象
|
// 首先是通过grpc.NewServer()构造一个gRPC服务对象
|
||||||
grpcServer := grpc.NewServer()
|
// 补充了全局的认证中间件
|
||||||
|
grpcServer := grpc.NewServer(grpc.ChainUnaryInterceptor(hello_service.GrpcAuthUnaryServerInterceptor()))
|
||||||
|
|
||||||
// SDK 提供 服务实现对象的注册
|
// SDK 提供 服务实现对象的注册
|
||||||
hello_service.RegisterHelloServiceServer(grpcServer, &HelloService{})
|
hello_service.RegisterHelloServiceServer(grpcServer, &HelloService{})
|
||||||
|
@ -14,7 +14,12 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// grpc.Dial负责和gRPC服务建立链接
|
// grpc.Dial负责和gRPC服务建立链接
|
||||||
conn, err := grpc.NewClient("localhost:1234", grpc.WithTransportCredentials(insecure.NewCredentials()))
|
conn, err := grpc.NewClient("localhost:1234",
|
||||||
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||||
|
grpc.WithPerRPCCredentials(hello_service.NewClientAuthentication(
|
||||||
|
"admin",
|
||||||
|
"123456",
|
||||||
|
)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user