在服务器和客户端中拦截GRPC C 调用
Intercept gRPC C++ calls in server and client
我要执行的基本任务:在GRPC服务器中提供Authenticate
服务,所有客户端最初都调用(并提供用户名和密码)以获得授权令牌(例如JWT)。接下来,当客户端拨打其他服务调用时,应验证令牌。
这可以在Java API中使用ServerInterceptor
和ClientInterceptor
接口轻松完成。在ServerInterceptor
中,我可以检查哪个服务并决定是否允许或拒绝呼叫。在ClientInterceptor
侧,我可以将授权令牌作为元数据添加到每个服务调用中。
C 中有此AuthMetadataProcessor
抽象类。但不确定如何完成类似于Java API的任务。有没有办法在C API中做类似的事情?
是。您需要子类AuthMetadataProcessor
,覆盖其Process
方法,然后在服务中注册派生类型的实例。完成此操作后,所有方法调用将被Process
拦截,并将为其提供请求的客户端。
您的Process
的实现必须决定是否需要拦截方法的身份验证(即,您的Authenticate
方法不需要需要身份验证,但随后调用的方法需要进行身份验证)。这可以通过检查:path
元数据密钥来完成,如第9211期中的记录,这是指定截距方法的值得信赖的值。
您对Process
的实现必须决定是否在请求中提供令牌并有效。这是一个实现细节,但通常Process
是指Authenticate
生成的有效令牌的存储。您已经在Java中设置了它的方式。
不幸的是,一个人无法在不安全凭据之上注册authmetadataprocessor,这意味着您必须使用SSL,或者尝试以不同的方式拦截方法。
该框架还提供了便利功能,使您可以使用Peer Identity属性。Process
可以在身份验证上下文上调用AddProperty
,提供令牌所隐含的身份,然后是SetPeerIdentityPropertyName
。然后,调用方法可以使用GetPeerIdentity
访问信息,并避免将令牌重新映射到身份。
AUTHMETMETADATAPROCESSOR实现示例
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;
};
authmetadataprocessor在安全服务中设置
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());
};
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- 为什么使用 "this" 指针调用派生成员函数?
- 函数调用中参数的顺序重要吗
- OpenGL - 在抛出"__gnu_cxx::recursive_init_error"实例后终止调用?
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 在c++类上调用void函数
- 为什么 std::unique 不调用 std::sort?
- 如何使用CMake编译.proto文件来生成.grpcp.pb.cc和.grpc.pb.h文件
- 调用专用模板时出错"no matching function for call to [...]"
- 选择要调用的构造函数
- C++为什么尽管我调用了void函数,它却不起作用
- 构造函数正在调用一个使用当前类类型的函数
- ::grpc::ServerReaderWriter 对象在另一个线程中一段时间后无法调用
- 优先考虑GRPC调用以避免服务器过载
- 跟踪 gRPC 服务器C++中的所有 RPC 调用
- 在服务器和客户端中拦截GRPC C 调用
- gRPC C++客户端对Bigtable的调用偶尔会挂起
- 如何在c++中向流式grpc调用添加元数据