Python客户端在Nextcloud上通过OAuth2访问CalDAV

时间:2018-05-09 17:09:34

标签: python oauth-2.0 caldav nextcloud

使用CalDAV的规范examples始终使用用户名/密码身份验证。但是Nextcloud支持OAuth2,因此我想通过oauth使用CalDAV。

我已经对Google日历API做了同样的事情,但只是调整了Google提供的oauth2client示例:

client_secrets = 'client_secrets.json'
flow = client.flow_from_clientsecrets(client_secrets, scope="",
                                      message=tools.message_if_missing(client_secrets))
storage = file.Storage('calendar_credentials.dat')
credentials = storage.get()
if credentials is None or credentials.invalid:
    credentials = tools.run_flow(flow, storage)

http = credentials.authorize(http=build_http())

build_http()替换为caldav.DAVClient的实例不起作用。内部request() API完全不同,调用caldav客户端的任何方法在authorize()包装时都会失败。所以,问题是:如何将caldav.DAVClientoauth2client进行整合?

还有关于使用OAuth和nextCloud的文档很少。我找到了this posting,但现在仍然不明显是什么。

1 个答案:

答案 0 :(得分:1)

让我们从配置开始。在Nextcloud中,转到安全设置(https://mycloud.example.com/settings/admin/security)。有一节OAuth 2.0 clients。添加客户端。您可以使用任何名称,例如calendar,但重定向URI为http://localhost:8080非常重要。为什么? tools.run_flow()将默认情况下实例化http服务器以接收对此地址的身份验证调用。点击“添加”。您现在应该看到一个新的客户端ID。将客户端ID和密码(单击要显示的眼睛图标)复制到client_secrets.json,这应该是这样的:

{
  "web": {
    "client_id": "stuff copied from Client Identifier",
    "client_secret": "stuff copied from secret",
    "auth_uri": "https://mycloud.example.com/index.php/apps/oauth2/authorize",
    "token_uri": "https://mycloud.example.com/index.php/apps/oauth2/api/v1/token",
    "redirect_uris": []
  }
}

当您现在运行问题部分中的示例时,您的浏览器应自动定向到mycloud.example.com实例,并且应该会显示一条消息“您即将授予日历访问权限到你的mycloud.example.com帐户。“点击“授予访问权限”。输入您的用户名和密码后,浏览器现在应重定向到http://localhost:8080,您应该看到消息“认证流程已完成。”

注意:

  • 我发现client_secrets.json是否以web开头没有区别 或者installed。但是,它必须是这两者中的一个。
  • 显然,redirect_uris可以保持为空。

现在编程问题(毕竟这是程序员的论坛......)

caldav.DAVClient的构造函数允许auth参数,该参数应该是requests.auth.AuthBase的实例。所以让我们创建一个:

from requests.auth import AuthBase


class OAuth(AuthBase):
    def __init__(self, credentials):
        self.credentials = credentials

    def __call__(self, r):
        self.credentials.apply(r.headers)
        return r

现在,不要像Google的原始示例中那样调用credentials.authorize(http=build_http()),而是编写

caldav_client = caldav.DAVClient(
    "https://mycloud.example.com/remote.php/dav/",
    auth=OAuth(credentials))

就是这样!我们现在可以写

principal = caldav_client.principal()
calendars = principal.calendars()

,如original example