作者 Eaton

导语

在我们使用微服务架构时,经常会选择通过 RPC 通信框架方便地实现服务间的调用。但方便的同时也带来了一些安全隐患,任何用户都能够访问对外公开的接口,可能造成部分敏感数据的泄露,这是我们不希望看到的,怎么避免呢?这要求我们对访问的用户进行鉴别,因此我们需要一个细化到服务的鉴权访问机制。本文将介绍 TARS 的服务鉴权及其使用方法。

目录

  • 什么是鉴权
  • TARS 服务鉴权

    • 服务准备
    • 开启鉴权
  • 总结

什么是鉴权

鉴权是指验证用户或服务是否具有访问系统的权利。对于部分公开的接口,我们并不希望所有用户或服务都能够访问,只希望特定的对象能够访问,因此我们需要鉴别访问接口的用户或服务的身份,确保访问的对象是我们希望的,保证接口的安全,这就是鉴权。

鉴权一般可分为用户鉴权和服务鉴权。

  • 用户身份鉴权通常依赖于用户系统,需要在业务代码中实现,实现方式有很多种,取决于具体的业务需求和使用的用户系统。
  • 服务鉴权则是对调用方服务的鉴别,确保只有特定的服务或客户端能够调用该服务。

TARS 服务鉴权

TARS 提供了一个强大的 RPC 框架,你只需要得到被调用方的 TARS 协议文件,就可以使用TARS框架编码,请求被调方服务。同时 TARS 框架中还提供了一个细化到服务的鉴权访问机制,通过账号密钥对的形式,使被调服务能够对调用方进行鉴别。

接下来我们以 TarsCpp为例,通过一个实例来看看如何在 TARS 中使用服务鉴权。

服务准备

我们需要准备两个服务,一个是被调服务,一个主调服务。

被调服务 TestServer

首先我们创建一个被调服务,应用名为 TestApp,服务名为 TestServerObj 名为 Test,如下

/usr/local/tars/cpp/script/cmake_tars_server.sh TestApp TestServer Test

生成如下文件

TestServer
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    ├── Test.h
    ├── TestImp.cpp
    ├── TestImp.h
    ├── TestServer.cpp
    ├── TestServer.h
    └── Test.tars

然后修改 Test.tars 文件,定义一个 test 接口,传入一个字符串 input,返回一个字符串 output

module TestApp
{

interface Test
{
    int test(string input, out string output);
};

};

接着,在 TestImp.cpp 接口实现文件中,添加接口实现,如下

int TestImp::test(const string &input, string &output, tars::TarsCurrentPtr current)
{
    output = input;

    return 0;
}

实现非常简单,接收到一个字符串,然后直接返回这个字符串。最后,编译构建服务,并在 TarsWeb 平台发布该服务即可。

关于 TARS 服务的创建与部署,参考文档 TARS 开发入门,这里不再赘述。

主调服务 HttpServer

为了便于演示,我们创建一个 HTTP 服务作为主调服务,这样我们可以直接通过 HTTP 请求访问这个服务。服务应用名 TestApp,服务名 HttpServerObj 名为 Http,命令如下

/usr/local/tars/cpp/script/cmake_http_server.sh TestApp HttpServer Http

生成如下文件

HttpServer
├── build
├── CMakeLists.txt
└── src
    ├── CMakeLists.txt
    ├── HttpImp.cpp
    ├── HttpImp.h
    ├── HttpServer.cpp
    └── HttpServer.h

因为主调服务要调用被调服务 TestServer 的接口,我们需要将 Test.tars 复制到路径 src 下。

接着,在 HttpImp.h 中添加一个 TestPrx 类型成员变量 prx_,作为调用 TestServer 的代理,如下

private:
    TestApp::TestPrx prx_;

然后我们修改 HttpImp.cpp,在 initialize 中初始化 prx_,并添加 doRequest 的实现。

//////////////////////////////////////////////////////
void HttpImp::initialize()
{
    prx_ = Application::getCommunicator()->stringToProxy<TestApp::TestPrx>("TestApp.TestServer.TestObj");
}

...
...

int HttpImp::doRequest(const TC_HttpRequest &req, TC_HttpResponse &rsp)
{
    string msg;
    try
    {   // 调用 test 接口,传入字符串 HttpServer,msg 获取 test 返回的字符串
        prx_->test("Hello", msg);
    }
    catch (exception &e)
    {   // 接口调用失败,捕捉错误,传递给 msg
        msg = e.what();
    }
    // 设置 HTTP 响应头
    rsp.setContentType("text/html");
    // 设置 body
    rsp.setResponse(msg.c_str(), msg.size());
    return 0;
}

可以看到 doRequest 函数会尝试调用 test 接口,并将结果传递给 msg。调用失败则是传递错误信息给 msg

编译并在 TarsWeb 平台上部署这个服务。部署时记得记下部署的端口号,并确保端口可访问,本例使用 8088 端口。部署后,我们可以使用 curl 命令或者直接使用浏览器请求 HttpServer,这时会返回字符串 Hello,如下

$ curl http://192.168.0.121:8088/
Hello

开启鉴权

TARS 鉴权的使用非常简单,你不需要修改一行代码,只需要修改服务的配置。按照下面三个步骤修改即可。

修改被调用方的 endpoint,开启鉴权机制

在 TarsWeb 平台,选中需要启用鉴权的服务,编辑 servant,修改 endpoint,添加 -e 1-e 及其参数表示是否开启鉴权,默认为 0 是不开启的,为 1 则是开启。操作如下图

修改被调用方的配置文件添加账号密钥对

在 TarsWeb 平台,修改服务的私有模板,对 TestApp.TestServer.TestObjAdapter 设置账号 test 以及密钥 123456,如下

由于截图不全,实际私有模板内容如下:

<tars>
  <application>
    <server>
      <TestApp.TestServer.TestObjAdapter>
        accesskey=test
        secretkey=123456
      </TestApp.TestServer.TestObjAdapter>
    </server>
  </application>
</tars>

现在,在 TarsWeb 上重启 TestServer 服务,然后我们再次请求 HttpServer 服务,结果如下

$ curl http://192.168.0.121:8088/
[ServantProxy::invoke timeout:3000,servant:TestApp.TestServer.TestObj,func:test,adapter:tcp -h 192.168.0.121 -p 29712 -t 3000,reqid:2]

可见服务 HttpServer 调用 TestServer 时超时了,没有响应。因为开启服务鉴权后,请求服务无法匹配账号和密钥的话,被调服务会直接关闭连接。

查询被调服务 TestServer 的日志,会发现 TestServer 接收到了本次请求,但是认证失败了,因此直接关闭了此连接。

2020-11-10 19:09:35|140215793313664|DEBUG|[TARS]accept [192.168.0.121:38279] [17] incomming
2020-11-10 19:09:35|140215247173376|ERROR|[TARS]authProcess failed with new state [AUTH_WRONG_AK]
2020-11-10 19:09:35|140215247173376|DEBUG|[TARS]send [192.168.0.121:38279] close connection by user.

修改主调方的配置文件添加账号密钥

要让主调服务 HttpServer 能够调用开启了鉴权的 TestServer 服务,我们也要在 HttpServer 中配置相同账号和密钥。

配置方式同样是在私有模板中配置,如图,配置调用 TestApp.TestServer.TestObj 的账号 test 和密钥 123456

由于截图不全,实际私有模板内容如下:

<tars>
  <application>
    <client>
      <TestApp.TestServer.TestObj>
        accesskey=test
        secretkey=123456
      </TestApp.TestServer.TestObj>
    </client>
  </application>
</tars>

现在,在 TarsWeb 重启 HttpServer 服务,我们再次发起请求,结果如下

$ curl http://192.168.0.121:8088/
Hello

返回 Hello,说明本次调用鉴权成功。

进阶:主调方需要调用多个开启鉴权的被调服务时,只需在上述模板文件的 client 域中,继续以相同的方式添加被调服务,并添加属性 accesskeysecretkey 即可,如下
<tars>
  <application>
    <client>
      <TestApp.TestServer.TestObj>
        accesskey=test
        secretkey=123456
      </TestApp.TestServer.TestObj>
      <TestApp.AnotherServer.HelloObj>
        accesskey=hello
        secretkey=654321
      </TestApp.AnotherServer.HelloObj>
    </client>
  </application>
</tars>

总结

本文介绍了 TARS 框架中的服务鉴权功能以及如何使用。从文中实例可以看出,服务鉴权完全与业务代码无关,在框架层面实现。通过 TARS 服务鉴权,能够实现服务间身份的鉴别,从而确保一些敏感接口的安全,避免被滥用。

TARS 可以在考虑到易用性和高性能的同时快速构建系统并自动生成代码,帮助开发人员和企业以微服务的方式快速构建自己稳定可靠的分布式应用,从而令开发人员只关注业务逻辑,提高运营效率。多语言、敏捷研发、高可用和高效运营的特性使 TARS 成为企业级产品。

TARS微服务助您数字化转型,欢迎访问:

TARS官网:https://TarsCloud.org

TARS源码:https://github.com/TarsCloud

Linux基金会官方微服务免费课程:https://www.edx.org/course/bu...

获取《TARS官方培训电子书》:https://wj.qq.com/s2/6570357/...

或扫码获取:

QR


TARS基金会
16 声望7 粉丝

2020年3月10日,Linux基金会正式宣布旗下的TARS开源项目将成立TARS基金会。TARS基金会是一个专注于微服务领域的开源基金会,致力于帮助企业在拓展新领域时拥抱微服务体系架构,解决在使用微服务方面可能出现的问...