使用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.DAVClient
与oauth2client
进行整合?
还有关于使用OAuth和nextCloud的文档很少。我找到了this posting,但现在仍然不明显是什么。
答案 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()