源码 grpc 认证 鸭子模型 函数返回值为接口 传输压缩 自定义令牌身份认证

源码 grpc  认证 鸭子模型 

Authentication | gRPC https://www.grpc.io/docs/guides/auth/#authenticate-with-google

将谷歌的认证实现,改成定义的认证实现

perRPC, _ := oauth.NewServiceAccountFromFile("service-account.json", scope)

 

google.golang.org/grpc@v1.43.0/credentials/oauth/oauth.go:192

// NewServiceAccountFromFile constructs the PerRPCCredentials using the JSON key file
// of a Google Developers service account.
func NewServiceAccountFromFile(keyFile string, scope ...string) (credentials.PerRPCCredentials, error) {
jsonKey, err := ioutil.ReadFile(keyFile)
if err != nil {
return nil, fmt.Errorf("credentials: failed to read the service account key file: %v", err)
}
return NewServiceAccountFromKey(jsonKey, scope...)
}

关注返回值

google.golang.org/grpc@v1.43.0/credentials/credentials.go:38

// 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. 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
}

其中原返回值为Google的逻辑

// NewServiceAccountFromKey constructs the PerRPCCredentials using the JSON key slice
// from a Google Developers service account.
func NewServiceAccountFromKey(jsonKey []byte, scope ...string) (credentials.PerRPCCredentials, error) {
config, err := google.JWTConfigFromJSON(jsonKey, scope...)
if err != nil {
return nil, err
}
return &serviceAccount{config: config}, nil
}

实现方法


type T struct {
}

func NewCustomerPerRPCCredentials() (PerRPCCredentials, error) {
return &T{}, nil
}
func (t *T) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
return nil, nil
}

func (t *T) RequireTransportSecurity() bool {
return true
}
perRPC, err := NewCustomerPerRPCCredentials()

 鸭子能走路,能走路的就是鸭子。

 google.golang.org/grpc@v1.43.0/credentials/oauth/oauth.go:151


// serviceAccount represents PerRPCCredentials via JWT signing key.
type serviceAccount struct {
mu sync.Mutex
config *jwt.Config
t *oauth2.Token
}

func (s *serviceAccount) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
s.mu.Lock()
defer s.mu.Unlock()
if !s.t.Valid() {
var err error
s.t, err = s.config.TokenSource(ctx).Token()
if err != nil {
return nil, err
}
}
ri, _ := credentials.RequestInfoFromContext(ctx)
if err := credentials.CheckSecurityLevel(ri.AuthInfo, credentials.PrivacyAndIntegrity); err != nil {
return nil, fmt.Errorf("unable to transfer serviceAccount PerRPCCredentials: %v", err)
}
return map[string]string{
"authorization": s.t.Type() + " " + s.t.AccessToken,
}, nil
}

func (s *serviceAccount) RequireTransportSecurity() bool {
return true
}
google.golang.org/grpc v1.43.0
google.golang.org/protobuf v1.27.1
package grpc

import (
"context"
"crypto/tls"
"crypto/x509"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/encoding/gzip"
"io/ioutil"
"time"
)

type T struct {
AccessToken string
}

func NewCustomerPerRPCCredentials(AccessToken string) (credentials.PerRPCCredentials, error) {
return &T{AccessToken: AccessToken}, nil
}
func (t *T) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
m := map[string]string{}
m["AccessToken"] = t.AccessToken
return m, nil
}

func (t *T) RequireTransportSecurity() bool {
return true
}

func NewConn() (conn *grpc.ClientConn) {
certFile := "../cert/server1_cert.pem"
//creds, err := credentials.NewClientTLSFromFile(certFile, "")
b, err := ioutil.ReadFile(certFile)
if err != nil {
panic(err)
}
creds_cp := x509.NewCertPool()
if !creds_cp.AppendCertsFromPEM(b) {
panic("credentials: failed to append certificates")
}
creds, err := credentials.NewTLS(&tls.Config{ServerName: "", RootCAs: creds_cp, InsecureSkipVerify: true}), nil
if err != nil {
panic(err)
}
perRPC, err := NewCustomerPerRPCCredentials("Val-ak123")
if err != nil {
panic(err)
}

bytes := 1024 * 1024 * 4 * 4
cp := grpc.ConnectParams{}
cp.MinConnectTimeout = 16 * time.Second

co := []grpc.CallOption{grpc.UseCompressor(gzip.Name)}

opts := []grpc.DialOption{
grpc.WithTransportCredentials(creds),
grpc.WithBlock(),
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(bytes)),
grpc.WithConnectParams(cp),
grpc.WithDefaultCallOptions(co...),
grpc.WithPerRPCCredentials(perRPC),
}
grpc.UseCompressor(gzip.Name)
conn, err = grpc.Dial("1.24.14.14:12345", opts...)
if err != nil {
panic(err)
}
return conn
}




证书不被信任

InsecureSkipVerify: true,         // test server certificate is not trusted.

Go/src/crypto/tls/example_test.go:99

client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
KeyLogWriter: w,

Rand: zeroSource{}, // for reproducible output; don't do this.
InsecureSkipVerify: true, // test server certificate is not trusted.
},
},
}
// InsecureSkipVerify controls whether a client verifies the server's
// certificate chain and host name. If InsecureSkipVerify is true, crypto/tls
// accepts any certificate presented by the server and any host name in that
// certificate. In this mode, TLS is susceptible to machine-in-the-middle
// attacks unless custom verification is used. This should be used only for
// testing or in combination with VerifyConnection or VerifyPeerCertificate.
InsecureSkipVerify bool

Go/src/crypto/tls/common.go:646

Go当中TLS/SSL 证书的实践 - 知乎 https://zhuanlan.zhihu.com/p/338688506

github.com\robfig\cron\v3@v3.0.0\cron.go

// Job is an interface for submitted cron jobs.
type Job interface {
    Run()
}
 
// FuncJob is a wrapper that turns a func() into a cron.Job
type FuncJob func()

func (f FuncJob) Run() { f() }

// AddFunc adds a func to the Cron to be run on the given schedule.
// The spec is parsed using the time zone of this Cron instance as the default.
// An opaque ID is returned that can be used to later remove it.
func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error) {
    return c.AddJob(spec, FuncJob(cmd))
}
 
 
// FuncJob is a wrapper that turns a func() into a cron.Job
type FuncJob func()

func (f FuncJob) Run() { f() }

// AddFunc adds a func to the Cron to be run on the given schedule.
// The spec is parsed using the time zone of this Cron instance as the default.
// An opaque ID is returned that can be used to later remove it.
func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error) {
    return c.AddJob(spec, FuncJob(cmd))
}

// AddJob adds a Job to the Cron to be run on the given schedule.
// The spec is parsed using the time zone of this Cron instance as the default.
// An opaque ID is returned that can be used to later remove it.
func (c *Cron) AddJob(spec string, cmd Job) (EntryID, error) {
    schedule, err := c.parser.Parse(spec)
    if err != nil {
        return 0, err
    }
    return c.Schedule(schedule, cmd), nil
}
 
 
type myJob struct {
    uri string
}

func (j myJob) Run() {
    openBrowser(j.uri)
}
 
 
函数类型 结构体类型 接口类型
 
 
github.com\go-kratos\kratos\v2@v2.1.2\config\config.go
package config

import (
	"context"
	"errors"
	"reflect"
	"sync"
	"time"

	"github.com/go-kratos/kratos/v2/log"

	// init encoding
	_ "github.com/go-kratos/kratos/v2/encoding/json"
	_ "github.com/go-kratos/kratos/v2/encoding/proto"
	_ "github.com/go-kratos/kratos/v2/encoding/xml"
	_ "github.com/go-kratos/kratos/v2/encoding/yaml"
)

var (
	// ErrNotFound is key not found.
	ErrNotFound = errors.New("key not found")
	// ErrTypeAssert is type assert error.
	ErrTypeAssert = errors.New("type assert error")

	_ Config = (*config)(nil)
)

// Observer is config observer.
type Observer func(string, Value)

// Config is a config interface.
type Config interface {
	Load() error
	Scan(v interface{}) error
	Value(key string) Value
	Watch(key string, o Observer) error
	Close() error
}

type config struct {
	opts      options
	reader    Reader
	cached    sync.Map
	observers sync.Map
	watchers  []Watcher
	log       *log.Helper
}

// New new a config with options.
func New(opts ...Option) Config {
	o := options{
		logger:   log.DefaultLogger,
		decoder:  defaultDecoder,
		resolver: defaultResolver,
	}
	for _, opt := range opts {
		opt(&o)
	}
	return &config{
		opts:   o,
		reader: newReader(o),
		log:    log.NewHelper(o.logger),
	}
}

func (c *config) watch(w Watcher) {
	for {
		kvs, err := w.Next()
		if errors.Is(err, context.Canceled) {
			c.log.Infof("watcher's ctx cancel : %v", err)
			return
		}
		if err != nil {
			time.Sleep(time.Second)
			c.log.Errorf("failed to watch next config: %v", err)
			continue
		}
		if err := c.reader.Merge(kvs...); err != nil {
			c.log.Errorf("failed to merge next config: %v", err)
			continue
		}
		if err := c.reader.Resolve(); err != nil {
			c.log.Errorf("failed to resolve next config: %v", err)
			continue
		}
		c.cached.Range(func(key, value interface{}) bool {
			k := key.(string)
			v := value.(Value)
			if n, ok := c.reader.Value(k); ok && !reflect.DeepEqual(n.Load(), v.Load()) {
				v.Store(n.Load())
				if o, ok := c.observers.Load(k); ok {
					o.(Observer)(k, v)
				}
			}
			return true
		})
	}
}

func (c *config) Load() error {
	for _, src := range c.opts.sources {
		kvs, err := src.Load()
		if err != nil {
			return err
		}
		for _, v := range kvs {
			c.log.Infof("config loaded: %s format: %s", v.Key, v.Format)
		}
		if err = c.reader.Merge(kvs...); err != nil {
			c.log.Errorf("failed to merge config source: %v", err)
			return err
		}
		w, err := src.Watch()
		if err != nil {
			c.log.Errorf("failed to watch config source: %v", err)
			return err
		}
		c.watchers = append(c.watchers, w)
		go c.watch(w)
	}
	if err := c.reader.Resolve(); err != nil {
		c.log.Errorf("failed to resolve config source: %v", err)
		return err
	}
	return nil
}

func (c *config) Value(key string) Value {
	if v, ok := c.cached.Load(key); ok {
		return v.(Value)
	}
	if v, ok := c.reader.Value(key); ok {
		c.cached.Store(key, v)
		return v
	}
	return &errValue{err: ErrNotFound}
}

func (c *config) Scan(v interface{}) error {
	data, err := c.reader.Source()
	if err != nil {
		return err
	}
	return unmarshalJSON(data, v)
}

func (c *config) Watch(key string, o Observer) error {
	if v := c.Value(key); v.Load() == nil {
		return ErrNotFound
	}
	c.observers.Store(key, o)
	return nil
}

func (c *config) Close() error {
	for _, w := range c.watchers {
		if err := w.Stop(); err != nil {
			return err
		}
	}
	return nil
}

  

 
 
 
 
 
 
 
原文地址:https://www.cnblogs.com/rsapaper/p/15716337.html