Skip to content

Commit

Permalink
Add LinuxDo OAuth2 (#9)
Browse files Browse the repository at this point in the history
* Add Linux Do OAuth2

* Fix Linux Do get token
  • Loading branch information
wu-clan authored Jul 6, 2024
1 parent b0b42bb commit b8b6e91
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 28 deletions.
6 changes: 3 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
rev: v4.6.0
hooks:
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml

- repo: https://github.com/charliermarsh/ruff-pre-commit
rev: v0.2.0
rev: v0.5.0
hooks:
- id: ruff
args:
- '--fix'
- id: ruff-format

- repo: https://github.com/pdm-project/pdm
rev: 2.12.3
rev: 2.16.1
hooks:
- id: pdm-lock-check
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@
![GitHub release (with filter)](https://img.shields.io/github/v/release/fastapi-practices/fastapi_oauth20)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)


在 FastAPI 中异步授权 OAuth2 客户端

我们的目标是集成多个 CN 第三方客户端,敬请期待
我们的目标是集成多个 CN 第三方客户端,敬请期待(🐦)...

#### TODO:

如果我们能够很容易获取测试客户端,对接将会很快发生
如果我们能够很容易获取测试客户端,或许这会很快

- [ ] library tests
- [x] Google
- [ ] tests
- [x] [Google](https://developers.google.cn/identity/protocols/oauth2/javascript-implicit-flow?hl=en)
- [ ] 微信
- [ ] QQ
- [ ] 抖音
- [x] 飞书
- [x] [飞书](https://open.feishu.cn/document/common-capabilities/sso/web-application-sso/web-app-overview)
- [ ] 钉钉
- [ ] 微博
- [ ] 百度
- [x] Gitee
- [x] Github
- [X] 开源中国
- [x] [Gitee](https://gitee.com/api/v5/oauth_doc#/)
- [x] [Github](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app)
- [X] [开源中国](https://www.oschina.net/openapi)
- [ ] 阿里云
- [ ] [Linux Do](https://connect.linux.do/)
8 changes: 4 additions & 4 deletions example/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

GOOGLE_CLIENT_ID = '1053650337583-ljnla4m1e5cg16erq3tld5vjflqh4bij.apps.googleusercontent.com'
GOOGLE_CLIENT_SECRET = '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'
GOOGLE_REDIRECT_URI = 'http://localhost:8000/auth/google'
GOOGLE_REDIRECT_URI = 'http://localhost:8000/auth2/google'

google_client = GoogleOAuth20(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET)
oauth20 = FastAPIOAuth20(google_client, GOOGLE_REDIRECT_URI)
Expand All @@ -22,9 +22,9 @@ async def login_google():
return await google_client.get_authorization_url(redirect_uri=GOOGLE_REDIRECT_URI)


@app.get('/auth/google', response_model=None)
async def auth_google(oauth: oauth20 = Depends()):
token, state = oauth
@app.get('/auth2/google', response_model=None)
async def auth2_google(oauth2: oauth20 = Depends()):
token, state = oauth2
access_token = token['access_token']
print(access_token)
# do something
Expand Down
13 changes: 11 additions & 2 deletions fastapi_oauth20/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
"""在 FastAPI 中异步授权 OAuth2 客户端"""

__version__ = '0.0.1a1'
__version__ = '0.0.1a2'

__all__ = ['OSChinaOAuth20', 'GoogleOAuth20', 'FeiShuOAuth20', 'GiteeOAuth20', 'GitHubOAuth20', 'FastAPIOAuth20']
__all__ = [
'OSChinaOAuth20',
'GoogleOAuth20',
'FeiShuOAuth20',
'GiteeOAuth20',
'GitHubOAuth20',
'FastAPIOAuth20',
'LinuxDoOAuth20',
]

from .clients.feishu import FeiShuOAuth20
from .clients.gitee import GiteeOAuth20
from .clients.github import GitHubOAuth20
from .clients.google import GoogleOAuth20
from .clients.linuxdo import LinuxDoOAuth20
from .clients.oschina import OSChinaOAuth20
from .integrations.fastapi import OAuth20 as FastAPIOAuth20
3 changes: 2 additions & 1 deletion fastapi_oauth20/clients/feishu.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
AUTHORIZE_ENDPOINT = 'https://passport.feishu.cn/suite/passport/oauth/authorize'
ACCESS_TOKEN_ENDPOINT = 'https://passport.feishu.cn/suite/passport/oauth/token'
REFRESH_TOKEN_ENDPOINT = AUTHORIZE_ENDPOINT
REVOKE_TOKEN_ENDPOINT = None
DEFAULT_SCOPES = ['contact:user.employee_id:readonly', 'contact:user.base:readonly', 'contact:user.email:readonly']
PROFILE_ENDPOINT = 'https://passport.feishu.cn/suite/passport/oauth/userinfo'

Expand All @@ -19,7 +20,7 @@ def __init__(self, client_id: str, client_secret: str):
authorize_endpoint=AUTHORIZE_ENDPOINT,
access_token_endpoint=ACCESS_TOKEN_ENDPOINT,
refresh_token_endpoint=REFRESH_TOKEN_ENDPOINT,
revoke_token_endpoint=None,
revoke_token_endpoint=REVOKE_TOKEN_ENDPOINT,
oauth_callback_route_name='feishu',
default_scopes=DEFAULT_SCOPES,
)
Expand Down
3 changes: 2 additions & 1 deletion fastapi_oauth20/clients/gitee.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
AUTHORIZE_ENDPOINT = 'https://gitee.com/oauth/authorize'
ACCESS_TOKEN_ENDPOINT = 'https://gitee.com/oauth/token'
REFRESH_TOKEN_ENDPOINT = ACCESS_TOKEN_ENDPOINT
REVOKE_TOKEN_ENDPOINT = None
DEFAULT_SCOPES = ['user_info']
PROFILE_ENDPOINT = 'https://gitee.com/api/v5/user'

Expand All @@ -19,7 +20,7 @@ def __init__(self, client_id: str, client_secret: str):
authorize_endpoint=AUTHORIZE_ENDPOINT,
access_token_endpoint=ACCESS_TOKEN_ENDPOINT,
refresh_token_endpoint=REFRESH_TOKEN_ENDPOINT,
revoke_token_endpoint=None,
revoke_token_endpoint=REVOKE_TOKEN_ENDPOINT,
oauth_callback_route_name='gitee',
default_scopes=DEFAULT_SCOPES,
)
Expand Down
9 changes: 5 additions & 4 deletions fastapi_oauth20/clients/github.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@

AUTHORIZE_ENDPOINT = 'https://github.com/login/oauth/authorize'
ACCESS_TOKEN_ENDPOINT = 'https://github.com/login/oauth/access_token'
REFRESH_TOKEN_ENDPOINT = None
REVOKE_TOKEN_ENDPOINT = None
DEFAULT_SCOPES = ['user', 'user:email']
PROFILE_ENDPOINT = 'https://api.github.com/user'
EMAILS_ENDPOINT = 'https://api.github.com/user/emails'


class GitHubOAuth20(OAuth20Base):
Expand All @@ -18,8 +19,8 @@ def __init__(self, client_id: str, client_secret: str):
client_secret=client_secret,
authorize_endpoint=AUTHORIZE_ENDPOINT,
access_token_endpoint=ACCESS_TOKEN_ENDPOINT,
refresh_token_endpoint=None,
revoke_token_endpoint=None,
refresh_token_endpoint=REFRESH_TOKEN_ENDPOINT,
revoke_token_endpoint=REVOKE_TOKEN_ENDPOINT,
oauth_callback_route_name='github',
default_scopes=DEFAULT_SCOPES,
)
Expand All @@ -35,7 +36,7 @@ async def get_userinfo(self, access_token: str) -> dict:

email = res.get('email')
if email is None:
response = await client.get(EMAILS_ENDPOINT)
response = await client.get(f'{PROFILE_ENDPOINT}/emails')
await self.raise_httpx_oauth20_errors(response)

emails = response.json()
Expand Down
2 changes: 1 addition & 1 deletion fastapi_oauth20/clients/google.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(self, client_id: str, client_secret: str):
)

async def get_userinfo(self, access_token: str) -> dict:
"""Gets user info from Google"""
"""Get user info from Google"""
headers = {'Authorization': f'Bearer {access_token}'}
async with httpx.AsyncClient() as client:
response = await client.get(PROFILE_ENDPOINT, headers=headers)
Expand Down
61 changes: 61 additions & 0 deletions fastapi_oauth20/clients/linuxdo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import httpx

from fastapi_oauth20.oauth20 import OAuth20Base

AUTHORIZE_ENDPOINT = 'https://connect.linux.do/oauth2/authorize'
ACCESS_TOKEN_ENDPOINT = 'https://connect.linux.do/oauth2/token'
REFRESH_TOKEN_ENDPOINT = ACCESS_TOKEN_ENDPOINT
REVOKE_TOKEN_ENDPOINT = None
DEFAULT_SCOPES = None
PROFILE_ENDPOINT = 'https://connect.linux.do/api/user'


class LinuxDoOAuth20(OAuth20Base):
def __init__(self, client_id: str, client_secret: str):
super().__init__(
client_id=client_id,
client_secret=client_secret,
authorize_endpoint=AUTHORIZE_ENDPOINT,
access_token_endpoint=ACCESS_TOKEN_ENDPOINT,
refresh_token_endpoint=REFRESH_TOKEN_ENDPOINT,
revoke_token_endpoint=REVOKE_TOKEN_ENDPOINT,
oauth_callback_route_name='linuxdo',
default_scopes=DEFAULT_SCOPES,
)

async def get_access_token(self, code: str, redirect_uri: str, code_verifier: str | None = None) -> dict:
"""Obtain the token based on the Linux do authorization method"""
data = {
'code': code,
'redirect_uri': redirect_uri,
'grant_type': 'authorization_code',
}

auth = httpx.BasicAuth(self.client_id, self.client_secret)

if code_verifier:
data.update({'code_verifier': code_verifier})
async with httpx.AsyncClient(auth=auth) as client:
response = await client.post(
self.access_token_endpoint,
data=data,
headers=self.request_headers,
)
await self.raise_httpx_oauth20_errors(response)

res = response.json()

return res

async def get_userinfo(self, access_token: str) -> dict:
"""Get user info from Linux Do"""
headers = {'Authorization': f'Bearer {access_token}'}
async with httpx.AsyncClient() as client:
response = await client.get(PROFILE_ENDPOINT, headers=headers)
await self.raise_httpx_oauth20_errors(response)

res = response.json()

return res
6 changes: 4 additions & 2 deletions fastapi_oauth20/clients/oschina.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
AUTHORIZE_ENDPOINT = 'https://www.oschina.net/action/oauth2/authorize'
ACCESS_TOKEN_ENDPOINT = 'https://www.oschina.net/action/openapi/token'
REFRESH_TOKEN_ENDPOINT = ACCESS_TOKEN_ENDPOINT
REVOKE_TOKEN_ENDPOINT = None
DEFAULT_SCOPES = None
PROFILE_ENDPOINT = 'https://www.oschina.net/action/openapi/user'


Expand All @@ -18,9 +20,9 @@ def __init__(self, client_id: str, client_secret: str):
authorize_endpoint=AUTHORIZE_ENDPOINT,
access_token_endpoint=ACCESS_TOKEN_ENDPOINT,
refresh_token_endpoint=REFRESH_TOKEN_ENDPOINT,
revoke_token_endpoint=None,
revoke_token_endpoint=REVOKE_TOKEN_ENDPOINT,
oauth_callback_route_name='oschina',
default_scopes=None,
default_scopes=DEFAULT_SCOPES,
)

async def get_userinfo(self, access_token: str) -> dict:
Expand Down
5 changes: 4 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,12 @@ order-by-type = true
quote-style = "single"

[tool.pdm]
package-type = "library"
distribution = true
version = { source = "file", path = "fastapi_oauth20/__init__.py" }

[tool.pdm.scripts]
lint = "pre-commit run --all-files"

[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"

0 comments on commit b8b6e91

Please sign in to comment.