1.客户端认证凭证实现
Go
package auth
import "context"
type Authentication struct {
clientId string
clientSecret string
}
// 构造凭证
func NewClientAuthentication(clientId, clientSecret string) *Authentication {
return &Authentication{
clientId: clientId,
clientSecret: clientSecret,
}
}
// 初始化凭证
func (a *Authentication) InitClientCredentials(clientId, clientSecret string) {
a.clientId = clientId
a.clientSecret = clientSecret
}
// 获取凭证
func (a *Authentication) GetRequestMetadata(context.Context, ...string) (map[string]string, error) {
return map[string]string{
"clientId": a.clientId,
"clientSecret": a.clientSecret,
}, nil
}
// 凭证是否需要安全传输
func (a *Authentication) RequireTransportSecurity() bool {
return false
}
客户端连接设置
Go
conn, err := grpc.NewClient(addr,
grpc.WithTransportCredentials(insecure.NewCredentials()),
grpc.WithPerRPCCredentials(auth.NewClientAuthentication("admin", "123456")))
2.服务端认证实现
Go
package auth
import (
"context"
"fmt"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
const (
ClientHeaderKey = "clientId"
ClientSecretKey = "clientSecret"
)
type GrpcAuthor struct {
}
// 构造并初始化
func NewGrpcAuthor() *GrpcAuthor {
return &GrpcAuthor{}
}
// 从客户端发来的请求中获取凭证信息
func (a *GrpcAuthor) 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 *GrpcAuthor) 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
}
// 拦截器
func (a *GrpcAuthor) Auth(
ctx context.Context,
req interface{},
info *grpc.UnaryServerInfo,
handler grpc.UnaryHandler,
) (resp interface{}, err error) {
// 从上下文中获取认证信息
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
return nil, fmt.Errorf("ctx is not an grpc incoming context!")
}
fmt.Println("grpc header info :", md)
// 获取客户端凭证信息
clientId, clientSecret := a.GetClientCredentialsFromMeta(md)
// 校验调用的客户端携带的凭证是否有效
if err := a.validateServiceCredential(clientId, clientSecret); err != nil {
return nil, err
}
resp, err = handler(ctx, req)
return resp, err
}
func GrpcAuthUnaryServerInterceptor() grpc.UnaryServerInterceptor {
return NewGrpcAuthor().Auth
}
服务端提供设置
Go
s := grpc.NewServer(
grpc.UnaryInterceptor(auth.GrpcAuthUnaryServerInterceptor()), // 添加认证插件
)
若账号密码错误返回:

具体的案例实现,修改其中部分即可验证。