使用Google日历API的Web应用程序

发布于 2025-01-31 06:28:40 字数 441 浏览 1 评论 0原文

我创建了一个简单的Python/Flask网站,该网站通过Google Calendar API连接到Google日历。 I followed the instructions at https://developers.google.com/calendar/api/quickstart /python ,它运行良好...

整个事情对我的公司是内部的。

我将Recorpers.json和Token.json以及我的网站一起复制到我用作Web服务器的内部设备。同样,一切都很好。

除了在某个阶段,我的凭据将会到期,并且Web服务器将需要重新认证我的个人Google帐户。

我该如何解决?

谢谢

I've created a simple Python/flask website which connects to a Google Calendar via the Google Calendar API. I followed the instructions at https://developers.google.com/calendar/api/quickstart/python, and it works well...

The whole thing is internal to my company.

I copied the credentials.json and token.json along with my website to an internal device I'm using as a webserver. Again, all works fine.

Except, at some stage, I am under the impression that my credentials will expire, and the web server will need to re-authenticate with my personal google account.

How do I get around this?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

梦纸 2025-02-07 06:28:40

您的刷新令牌到期的原因是您的应用仍处于测试阶段。在同意屏幕下转到Google Cloud Console,然后将其设置为生产。您的令牌将停止到期。

Web应用程序与已安装的应用程序

您应该注意的是示例

a href =“ https://i.sstatic.net/7ceov.png” rel =“ nofollow noreferrer”>

并为已安装的应用程序使用代码,

flow = InstalledAppFlow.from_client_secrets_file(
            'credentials.json', SCOPES)

因此通过遵循此示例,您没有创建您正在创建已安装的应用程序的Web应用程序。

The reason your refresh token is expiring is that your app is still in the testing phase. Go to google cloud console under the consent screen and set it to production. Your tokens will stop expiring.

web app vs installed app

You should note is the sample you are following states

enter image description here

and uses the code for an installed application

flow = InstalledAppFlow.from_client_secrets_file(
            'credentials.json', SCOPES)

So by following this example you are not creating a web application you are creating an installed application.

陌伤ぢ 2025-02-07 06:28:40

使用烧瓶您可以设计以下方案。

  • 您应该具有/auth端点,该端点生成授权>您可以重定向以在Google API中执行授权。
  • 当您在Google API中授权完成时,您应该有一个/callback端点。在此回调中,您可以将凭据存储在烧瓶会话中。
  • 在提出事件请求之前,您应该检查存储的凭据是否仍然有效。如果没有,您应该再次致电/auth

在GCP应用程序控制台中,当您为应用程序创建凭据时,应该选择“ Web应用程序”。

from flask import Flask, redirect, request, url_for
from google_auth_oauthlib.flow import Flow

app = Flask(__name__)
app.secret_key = os.environ.get("SECRET_KEY")
app.config["SESSION_TYPE"] = "filesystem"

# this callback URL should match one saved in GCP app console "Authorized redirection URIs" section 
CALLBACK_URL = os.environ.get("CALLBACK_URL") # you can use `url_for('callback')` instead
API_CLIENT_ID = os.environ.get("API_CLIENT_ID")
API_CLIENT_SECRET = os.environ.get("API_CLIENT_SECRET")
SCOPES = ["https://www.googleapis.com/auth/calendar"]

class CalendarClient:
    API_SERVICE = "calendar"
    API_VERSION = "v3"

    def __init__(self, client_id: str, client_secret: str, scopes: Sequence[str]):
        self._client_id = client_id
        self._client_secret = client_secret
        self._scopes = scopes
        self._client_config = {
            "web": {
                "client_id": client_id,
                "client_secret": client_secret,
                "auth_uri": "https://accounts.google.com/o/oauth2/auth",
                "token_uri": "https://oauth2.googleapis.com/token",
            }
        }

    def get_flow(self, callback_url: str) -> Flow:
        return Flow.from_client_config(
            self._client_config, self._scopes, redirect_uri=callback_url
        )

    def get_auth_url(self, callback_url: str) -> str:
        flow = self.get_flow(callback_url)
        auth_url, _ = flow.authorization_url(
            access_type="offline", include_granted_scopes="true"
        )
        return auth_url

    def get_credentials(self, code: str, callback_url: str) -> Credentials:
        flow = self.get_flow(callback_url)
        flow.fetch_token(code=code)
        return flow.credentials

@app.route("/callback")
def callback():
    credentials = client.get_credentials(
        code=request.args.get("code"),
        callback_url=CALLBACK_URL,
    )
    session["credentials"] = {
        "token": credentials.token,
        "refresh_token": credentials.refresh_token,
        "token_uri": credentials.token_uri,
        "client_id": credentials.client_id,
        "client_secret": credentials.client_secret,
        "scopes": credentials.scopes,
    }
    return credentials.to_json()


@app.route("/auth")
def auth():
    return redirect(client.get_auth_url(CALLBACK_URL))

完整代码库: https://github.com/jorzel.com/jorzel/jorzel/jorzel/flask -google-calendar

Using flask you can design the following scheme.

  • You should have a /auth endpoint that generates authorization_url that you can redirect to perform authorization in Google API.
  • You should have a /callback endpoint that handles requests when your authorization in Google API is completed. In this callback, you can store your credentials in a flask session.
  • Before making events request, you should check whether your stored credentials are still valid. If not, you should call /auth again.

In GCP app console, when you create credentials for your app you should choose "web application".
enter image description here

from flask import Flask, redirect, request, url_for
from google_auth_oauthlib.flow import Flow

app = Flask(__name__)
app.secret_key = os.environ.get("SECRET_KEY")
app.config["SESSION_TYPE"] = "filesystem"

# this callback URL should match one saved in GCP app console "Authorized redirection URIs" section 
CALLBACK_URL = os.environ.get("CALLBACK_URL") # you can use `url_for('callback')` instead
API_CLIENT_ID = os.environ.get("API_CLIENT_ID")
API_CLIENT_SECRET = os.environ.get("API_CLIENT_SECRET")
SCOPES = ["https://www.googleapis.com/auth/calendar"]

class CalendarClient:
    API_SERVICE = "calendar"
    API_VERSION = "v3"

    def __init__(self, client_id: str, client_secret: str, scopes: Sequence[str]):
        self._client_id = client_id
        self._client_secret = client_secret
        self._scopes = scopes
        self._client_config = {
            "web": {
                "client_id": client_id,
                "client_secret": client_secret,
                "auth_uri": "https://accounts.google.com/o/oauth2/auth",
                "token_uri": "https://oauth2.googleapis.com/token",
            }
        }

    def get_flow(self, callback_url: str) -> Flow:
        return Flow.from_client_config(
            self._client_config, self._scopes, redirect_uri=callback_url
        )

    def get_auth_url(self, callback_url: str) -> str:
        flow = self.get_flow(callback_url)
        auth_url, _ = flow.authorization_url(
            access_type="offline", include_granted_scopes="true"
        )
        return auth_url

    def get_credentials(self, code: str, callback_url: str) -> Credentials:
        flow = self.get_flow(callback_url)
        flow.fetch_token(code=code)
        return flow.credentials

@app.route("/callback")
def callback():
    credentials = client.get_credentials(
        code=request.args.get("code"),
        callback_url=CALLBACK_URL,
    )
    session["credentials"] = {
        "token": credentials.token,
        "refresh_token": credentials.refresh_token,
        "token_uri": credentials.token_uri,
        "client_id": credentials.client_id,
        "client_secret": credentials.client_secret,
        "scopes": credentials.scopes,
    }
    return credentials.to_json()


@app.route("/auth")
def auth():
    return redirect(client.get_auth_url(CALLBACK_URL))

Full codebase: https://github.com/jorzel/flask-google-calendar

甜扑 2025-02-07 06:28:40

我不知道您是否仍在为此努力。我看到门票已经9个月大了,但最近做了类似的事情,所以我想我会分享。不要使用Google提出的OAUTH2方法。而是:

  1. 在GCS&GT上创建一个服务帐户;创建一个键并下载要访问的日历中的 json (作为纪录级或任何您想要的)
  2. ,转到“设置”>我的日历的设置>选择要使用的日历转到“活动访问权限”> +添加人员和团体>粘贴在您的服务帐户电子邮件中>将权限设置为对事件进行更改
  3. 导航到集成日历并复制calendarId(它不会是 primary ,就像使用您自己的帐户时,但大多数可能您的电子邮件地址)
  4. 存储您的 recertentials.json (仅用于测试)
  5. 设置一个称为 Google_application_credentials 的环境变量到您的 recredentials.json < /strong>。我使用 .env 文件,然后使用 python-dotenv 加载它,但请随意做。 (ex。google_application_credentials = recortentials.json
  6. 存储您的calendarid某处(我将其存储在config.py.py
  7. service = build('valendar','v3')。该验证是在后台使用此方法完成的。

这是一个对我来说很好的示例。使用服务帐户,您无需通过OAuth流量。

import config
from googleapiclient.discovery import build
from datetime import datetime

def get_calendar_events():
    service = build('calendar', 'v3')
    now = datetime.utcnow().isoformat() + 'Z'
    events_result = service.events().list(calendarId=config.MAIL_USERNAME, timeMin=now).execute()
    events = events_result.get('items', [])
    return events

I don't know if you are still working on this. I see the ticket is 9 months old but was doing something similar recently so I thought I'd share. Don't use the Oauth2 method that google proposes. Instead:

  1. Create a service account on GCS > Create a key and download the json (as credentials.json or whatever you want)
  2. In the calendar you want to access, go to Settings > Settings for my calendars > Select calendar you want to use > Go to "Access permissions for events" > + Add people and groups > Paste in your service account email > Set permissions to Make changes to events
  3. Navigate to Integrate calendar and copy the calendarId (it will not be primary as when using your own account but most likely your email address)
  4. Store your credentials.json in your project (only for testing)
  5. Set an environment variable called GOOGLE_APPLICATION_CREDENTIALS to the path of your credentials.json. I use an .env file and load it using python-dotenv but feel free to do as you please. (ex. GOOGLE_APPLICATION_CREDENTIALS=credentials.json)
  6. Store your calendarId somewhere (I stored it in config.py)
  7. Build whatever process you need starting with service = build('calendar', 'v3'). The auth is done in the background using this method.

Here is an example that works fine for me. With a service account, you don't need to go through the OAuth flow.

import config
from googleapiclient.discovery import build
from datetime import datetime

def get_calendar_events():
    service = build('calendar', 'v3')
    now = datetime.utcnow().isoformat() + 'Z'
    events_result = service.events().list(calendarId=config.MAIL_USERNAME, timeMin=now).execute()
    events = events_result.get('items', [])
    return events
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文