mirror of
https://github.com/linka-cloud/grpc.git
synced 2024-11-18 00:46:25 +00:00
100 lines
2.4 KiB
Go
100 lines
2.4 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"crypto/subtle"
|
|
"strings"
|
|
|
|
grpc_auth "github.com/grpc-ecosystem/go-grpc-middleware/auth"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
|
|
"go.linka.cloud/grpc/interceptors"
|
|
)
|
|
|
|
func ChainedAuthFuncs(fn ...grpc_auth.AuthFunc) grpc_auth.AuthFunc {
|
|
return func(ctx context.Context) (context.Context, error) {
|
|
code := codes.Unauthenticated
|
|
for _, v := range fn {
|
|
ctx2, err := v(ctx)
|
|
if err == nil {
|
|
return ctx2, nil
|
|
}
|
|
s, ok := status.FromError(err)
|
|
if !ok {
|
|
return ctx2, err
|
|
}
|
|
if s.Code() == codes.PermissionDenied {
|
|
code = codes.PermissionDenied
|
|
}
|
|
}
|
|
return ctx, status.Error(code, code.String())
|
|
}
|
|
}
|
|
|
|
func NewServerInterceptors(opts ...Option) interceptors.ServerInterceptors {
|
|
o := options{}
|
|
for _, v := range opts {
|
|
v(&o)
|
|
}
|
|
return &interceptor{o: o, authFn: ChainedAuthFuncs(o.authFns...)}
|
|
}
|
|
|
|
type interceptor struct {
|
|
o options
|
|
authFn grpc_auth.AuthFunc
|
|
}
|
|
|
|
func (i *interceptor) UnaryServerInterceptor() grpc.UnaryServerInterceptor {
|
|
a := grpc_auth.UnaryServerInterceptor(i.authFn)
|
|
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
|
|
if i.isNotProtected(info.FullMethod) {
|
|
return handler(ctx, req)
|
|
}
|
|
return a(ctx, req, info, handler)
|
|
}
|
|
}
|
|
|
|
func (i *interceptor) StreamServerInterceptor() grpc.StreamServerInterceptor {
|
|
a := grpc_auth.StreamServerInterceptor(i.authFn)
|
|
return func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
|
if i.isNotProtected(info.FullMethod) {
|
|
return handler(srv, ss)
|
|
}
|
|
return a(srv, ss, info, handler)
|
|
}
|
|
}
|
|
|
|
func (i *interceptor) isNotProtected(endpoint string) bool {
|
|
// default to not ignored
|
|
if len(i.o.ignoredMethods) == 0 && len(i.o.methods) == 0 {
|
|
return false
|
|
}
|
|
// endpoint is like /helloworld.Greeter/SayHello
|
|
parts := strings.Split(strings.TrimPrefix(endpoint, "/"), "/")
|
|
// invalid endpoint format
|
|
if len(parts) != 2 {
|
|
return false
|
|
}
|
|
method := parts[1]
|
|
for _, v := range i.o.ignoredMethods {
|
|
if v == method {
|
|
return true
|
|
}
|
|
}
|
|
if len(i.o.methods) == 0 {
|
|
return false
|
|
}
|
|
for _, v := range i.o.methods {
|
|
if v == method {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func Equals(s1, s2 string) bool {
|
|
return subtle.ConstantTimeCompare([]byte(s1), []byte(s2)) == 1
|
|
}
|