更新时间:2022-06-14 22:59:02
是的。您需要为 AuthMetadataProcessor
子类化,重写其 Process
方法,并在服务中注册派生类型的实例。完成此操作后,所有方法调用将被 Process
拦截,并将为该请求提供与请求一起发送的客户端元数据。
Yes. You need to subclass AuthMetadataProcessor
, override its Process
method and register an instance of the derived type with your service. Once that is done, all method invocations will be intercepted by Process
and it will be given the client metadata sent with the request.
您的 Process
的实现必须决定是否需要对所拦截的方法进行身份验证(即,对于您的 Authenticate $ c而言不是必需的) $ c>方法,但对于各种随后调用的方法都是必需的)。如问题:path
元数据键来完成此操作。 rel = noreferrer>#9211 ,它是一个可信任的值,用于指定被拦截的方法。
Your implementation of Process
must decide whether authentication is required for the intercepted method (i.e., cannot be required for your Authenticate
method, but will be required for various subsequently invoked methods). This can be done by examining the :path
metadata key, as documented in issue #9211, which is a trusted value designating the intercepted method.
您对 Process的实现
必须确定令牌是否在请求中提供并有效。这是一个实现细节,但通常 Process
是指由 Authenticate
生成的有效令牌的存储。
Your implementation of Process
must decide whether the token is supplied in the request and is valid. This is an implementation detail, but generally Process
refers to a store of valid tokens generated by Authenticate
. Which is probably how you have it set up in Java already.
不幸的是,您不能在不安全的凭据上注册AuthMetadataProcessor,这意味着您将必须使用SSL,
Unfortunately, one cannot register an AuthMetadataProcessor on top of insecure credentials, meaning that you will have to use SSL, or else attempt to intercept methods differently.
该框架还提供了方便的功能,允许您使用对等身份属性。 Process
可以在身份验证上下文上调用 AddProperty
,提供令牌隐含的身份,后跟 SetPeerIdentityPropertyName
。然后,调用的方法可以使用 GetPeerIdentity
访问信息,并避免将令牌重新映射到身份。
The framework also provides convenience functionality allowing you to work with a peer identity property. Process
can call AddProperty
on the authentication context, providing the identity implied by the token, followed by SetPeerIdentityPropertyName
. The invoked method can then access the information using GetPeerIdentity
and avoid remapping tokens to identities.
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;
};
安全服务中的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());
};