C++ 拦截gRPC C++;服务器和客户端中的调用

C++ 拦截gRPC C++;服务器和客户端中的调用,c++,grpc,C++,Grpc,我想做的基本任务是:在gRPC服务器中提供一个身份验证服务,所有客户端最初调用该服务(并提供用户名和密码)以获取授权令牌(比如JWT)。接下来,当客户端进行其他服务调用时,应该验证令牌 这可以在Java API中使用ServerInterceptor和ClientInterceptor接口轻松实现。在ServerInterceptor中,我可以检查调用了哪个服务,并决定是允许还是拒绝调用。在ClientInterceptor端,我可以将授权令牌作为元数据添加到每个服务调用中 > C++中有这个

我想做的基本任务是:在gRPC服务器中提供一个
身份验证
服务,所有客户端最初调用该服务(并提供用户名和密码)以获取授权令牌(比如JWT)。接下来,当客户端进行其他服务调用时,应该验证令牌

这可以在Java API中使用
ServerInterceptor
ClientInterceptor
接口轻松实现。在
ServerInterceptor
中,我可以检查调用了哪个服务,并决定是允许还是拒绝调用。在
ClientInterceptor
端,我可以将授权令牌作为元数据添加到每个服务调用中


<> > C++中有这个<代码> AuthMeta处理器>代码>抽象类。但不确定如何完成类似于JavaAPI的任务。在C++ API中有类似的方法吗?< /P> < P>是的。您需要子类化
AuthMetadataProcessor
,重写其
Process
方法,并向服务注册派生类型的实例。一旦完成,所有方法调用都将被
进程
截获,并将被提供与请求一起发送的客户机元数据

过程
的实现必须决定拦截的方法是否需要身份验证(即,
身份验证
方法不需要身份验证,但随后调用的各种方法都需要身份验证)。这可以通过检查
:path
元数据密钥来实现,如问题中所述,这是一个指定被拦截方法的可信值

过程的实现必须决定令牌是否在请求中提供且有效。这是一个实现细节,但通常
过程
指的是由
验证
生成的有效令牌的存储。这可能就是您已经在Java中设置它的方式

不幸的是,不能在不安全的凭据上注册AuthMetadataProcessor,这意味着您将不得不使用SSL,或者尝试以不同的方式拦截方法

该框架还提供了方便的功能,允许您使用对等身份属性
Process
可以在身份验证上下文上调用
AddProperty
,提供令牌隐含的标识,后跟
SetPeerIdentityPropertyName
。然后,调用的方法可以使用
GetPeerIdentity
访问信息,并避免将令牌重新映射到标识

AuthMetadataProcessor实现示例

struct Const
{
    static const std::string& TokenKeyName() { static std::string _("token"); return _; }
    static const std::string& PeerIdentityPropertyName() { static std::string _("username"); return _; }    
};

class MyServiceAuthProcessor : public grpc::AuthMetadataProcessor
{

public:

    grpc::Status Process(const InputMetadata& auth_metadata, grpc::AuthContext* context, OutputMetadata* consumed_auth_metadata, OutputMetadata* response_metadata) override
    {
        // determine intercepted method
        std::string dispatch_keyname = ":path";
        auto dispatch_kv = auth_metadata.find(dispatch_keyname);
        if (dispatch_kv == auth_metadata.end())
            return grpc::Status(grpc::StatusCode::INTERNAL, "Internal Error");

        // if token metadata not necessary, return early, avoid token checking
        auto dispatch_value = std::string(dispatch_kv->second.data());
        if (dispatch_value == "/MyPackage.MyService/Authenticate")
            return grpc::Status::OK;

        // determine availability of token metadata
        auto token_kv = auth_metadata.find(Const::TokenKeyName());
        if (token_kv == auth_metadata.end())
            return grpc::Status(grpc::StatusCode::UNAUTHENTICATED, "Missing Token");

        // determine validity of token metadata
        auto token_value = std::string(token_kv->second.data());
        if (tokens.count(token_value) == 0)
            return grpc::Status(grpc::StatusCode::UNAUTHENTICATED, "Invalid Token");

        // once verified, mark as consumed and store user for later retrieval
        consumed_auth_metadata->insert(std::make_pair(Const::TokenKeyName(), token_value));     // required
        context->AddProperty(Const::PeerIdentityPropertyName(), tokens[token_value]);           // optional
        context->SetPeerIdentityPropertyName(Const::PeerIdentityPropertyName());                // optional

        return grpc::Status::OK;
    }

    std::map<std::string, std::string> tokens;
};
class MyServiceImplSecure : public MyPackage::MyService::Service
{

public:

    MyServiceImplSecure(std::string _server_priv, std::string _server_cert, std::string _ca_cert) :
        server_priv(_server_priv), server_cert(_server_cert), ca_cert(_ca_cert) {}

    std::shared_ptr<grpc::ServerCredentials> GetServerCredentials()
    {
        grpc::SslServerCredentialsOptions::PemKeyCertPair pkcp;
        pkcp.private_key = server_priv;
        pkcp.cert_chain = server_cert;

        grpc::SslServerCredentialsOptions ssl_opts;
        ssl_opts.pem_key_cert_pairs.push_back(pkcp);
        ssl_opts.pem_root_certs = ca_cert;

        std::shared_ptr<grpc::ServerCredentials> creds = grpc::SslServerCredentials(ssl_opts);
        creds->SetAuthMetadataProcessor(auth_processor);
        return creds;
    }

    void GetContextUserMapping(::grpc::ServerContext* context, std::string& username)
    {
        username = context->auth_context()->GetPeerIdentity()[0].data();
    }

private:

    std::string server_priv;
    std::string server_cert;
    std::string ca_cert;

    std::shared_ptr<MyServiceAuthProcessor> auth_processor =
        std::shared_ptr<MyServiceAuthProcessor>(new MyServiceAuthProcessor());
};
struct Const
{
static const std::string&TokenKeyName(){static std::string u(“token”);return;}
静态常量std::string&PeerIdentityPropertyName(){static std::string u(“用户名”);return;}
};
类MyServiceAuthProcessor:public grpc::AuthMetadataProcessor
{
公众:
grpc::状态进程(常量输入元数据和身份验证元数据,grpc::身份验证上下文*上下文,输出元数据*已使用身份验证元数据,输出元数据*响应元数据)覆盖
{
//确定截获方法
std::string dispatch_keyname=“:path”;
auto dispatch_kv=auth_metadata.find(dispatch_keyname);
if(dispatch_kv==auth_metadata.end())
返回grpc::Status(grpc::StatusCode::INTERNAL,“内部错误”);
//如果不需要令牌元数据,请提前返回,避免令牌检查
自动分派值=std::string(分派值->秒.data());
if(dispatch_value==“/MyPackage.MyService/Authenticate”)
返回grpc::Status::OK;
//确定令牌元数据的可用性
auto-token_kv=auth_metadata.find(Const::TokenKeyName());
if(token_kv==auth_metadata.end())
返回grpc::Status(grpc::StatusCode::未经验证,“缺少令牌”);
//确定令牌元数据的有效性
auto token_value=std::string(token_kv->second.data());
if(令牌数(令牌值)==0)
返回grpc::Status(grpc::StatusCode::UNAUTHENTICATED,“无效令牌”);
//验证后,标记为已使用,并存储用户以供以后检索
已使用的_auth_元数据->插入(std::make_对(Const::TokenKeyName(),token_值));//必需
context->AddProperty(Const::PeerIdentityPropertyName(),tokens[token_value]);//可选
context->SetPeerIdentityPropertyName(Const::PeerIdentityPropertyName());//可选
返回grpc::Status::OK;
}
std::映射令牌;
};
安全服务中的AuthMetadataProcessor设置

struct Const
{
    static const std::string& TokenKeyName() { static std::string _("token"); return _; }
    static const std::string& PeerIdentityPropertyName() { static std::string _("username"); return _; }    
};

class MyServiceAuthProcessor : public grpc::AuthMetadataProcessor
{

public:

    grpc::Status Process(const InputMetadata& auth_metadata, grpc::AuthContext* context, OutputMetadata* consumed_auth_metadata, OutputMetadata* response_metadata) override
    {
        // determine intercepted method
        std::string dispatch_keyname = ":path";
        auto dispatch_kv = auth_metadata.find(dispatch_keyname);
        if (dispatch_kv == auth_metadata.end())
            return grpc::Status(grpc::StatusCode::INTERNAL, "Internal Error");

        // if token metadata not necessary, return early, avoid token checking
        auto dispatch_value = std::string(dispatch_kv->second.data());
        if (dispatch_value == "/MyPackage.MyService/Authenticate")
            return grpc::Status::OK;

        // determine availability of token metadata
        auto token_kv = auth_metadata.find(Const::TokenKeyName());
        if (token_kv == auth_metadata.end())
            return grpc::Status(grpc::StatusCode::UNAUTHENTICATED, "Missing Token");

        // determine validity of token metadata
        auto token_value = std::string(token_kv->second.data());
        if (tokens.count(token_value) == 0)
            return grpc::Status(grpc::StatusCode::UNAUTHENTICATED, "Invalid Token");

        // once verified, mark as consumed and store user for later retrieval
        consumed_auth_metadata->insert(std::make_pair(Const::TokenKeyName(), token_value));     // required
        context->AddProperty(Const::PeerIdentityPropertyName(), tokens[token_value]);           // optional
        context->SetPeerIdentityPropertyName(Const::PeerIdentityPropertyName());                // optional

        return grpc::Status::OK;
    }

    std::map<std::string, std::string> tokens;
};
class MyServiceImplSecure : public MyPackage::MyService::Service
{

public:

    MyServiceImplSecure(std::string _server_priv, std::string _server_cert, std::string _ca_cert) :
        server_priv(_server_priv), server_cert(_server_cert), ca_cert(_ca_cert) {}

    std::shared_ptr<grpc::ServerCredentials> GetServerCredentials()
    {
        grpc::SslServerCredentialsOptions::PemKeyCertPair pkcp;
        pkcp.private_key = server_priv;
        pkcp.cert_chain = server_cert;

        grpc::SslServerCredentialsOptions ssl_opts;
        ssl_opts.pem_key_cert_pairs.push_back(pkcp);
        ssl_opts.pem_root_certs = ca_cert;

        std::shared_ptr<grpc::ServerCredentials> creds = grpc::SslServerCredentials(ssl_opts);
        creds->SetAuthMetadataProcessor(auth_processor);
        return creds;
    }

    void GetContextUserMapping(::grpc::ServerContext* context, std::string& username)
    {
        username = context->auth_context()->GetPeerIdentity()[0].data();
    }

private:

    std::string server_priv;
    std::string server_cert;
    std::string ca_cert;

    std::shared_ptr<MyServiceAuthProcessor> auth_processor =
        std::shared_ptr<MyServiceAuthProcessor>(new MyServiceAuthProcessor());
};
classmyservicecimplsecure:public MyPackage::MyService::Service
{
公众:
MyServiceImplSecure(std::string\u server\u priv,std::string\u server\u cert,std::string\u ca\u cert):
服务器私有(服务器私有)、服务器证书(服务器证书)、ca证书(ca证书){}
std::shared_ptr GetServerCredentials()
{
grpc::SslServerCredentialsOptions::PemKeyCertPair pkcp;
pkcp.private_key=server_priv;
pkcp.cert\u chain=服务器证书;
grpc::SslServerCredentialsOptions ssl_opts;
ssl_opts.pem_key_cert_pairs.push_back(pkcp);
ssl_opts.pem_root_certs=ca_cert;
std::shared_ptr creds=grpc::SslServerCredentials(ssl_opts);
creds->SetAuthMetadataProcessor(auth_processor);
回信;
}
void GetContextUserMapping(::grpc::ServerContext*上下文,std::字符串和用户名)
{
username=context->auth_context()->GetPeerIdentity()[0].data();
}
私人:
std::字符串服务器_priv;
std::字符串服务器证书;
标准::字符串证书;
std::共享\u ptr验证\u处理器=
std::shared_ptr(新的MyServiceAuthProcessor());
};

谢谢。在gRPC源代码中通过一些测试用例后,我也做了类似的操作。它应该是auto-token\u-value=std::string(token\u-kv->second.data(),token\u-kv->second.length());如果有的话