Skip to main content

ShangCloud OAuth 2.0 SDK for Python

Project description

ShangCloud SDK for Python

Python SDK,封装了授权登录与基础用户信息接口。

  • Package: shangcloud
  • Python 版本: 3.8+
  • 无外部依赖(纯标准库)
  • License: MIT

安装

pip install shangcloud-sdk

快速开始

以下是一个基于 Flask 的完整 OAuth 授权码模式 (Authorization Code) 流程示例。

from flask import Flask, redirect, request
from shangcloud import Client

app = Flask(__name__)

client = Client(
    client_id="your-client-id",
    client_secret="your-client-secret",
    redirect_uri="https://your-app.example.com/oauth/callback",
)

# 生成授权跳转 URL,将用户引导到授权页
@app.route("/login")
def login():
    return redirect(client.generate_oauth_url())

# 处理授权回调,使用 code 换取 User 实例
@app.route("/oauth/callback")
def callback():
    code = request.args.get("code")
    state = request.args.get("state")

    user = client.generate_user_instance(code, state)

    # 3. 拉取用户基本信息
    info = user.get_basic_info()
    return f"Hello, {info.nickname} (uid={info.user_id})"

核心 API

Client(client_id, client_secret, redirect_uri)

创建 SDK 客户端。默认 scopeuser:basicbase_urlhttps://api.yearnstudio.cn,并使用内置的内存 KV 作为 state 存储。如需自定义,可在返回的实例上直接赋值。

client = Client("client-id", "client-secret", "https://example.com/callback")
# 工厂方法
client = Client.init_client("client-id", "client-secret", "https://example.com/callback")

# 覆盖默认值
client.scope    = "user:basic"
client.base_url = "https://api.yearnstudio.cn"

client.generate_oauth_url() -> str

生成授权跳转 URL,内部随机生成 state 并写入 kv_storage,用于后续回调校验。

client.generate_user_instance(code, state) -> User

校验 state,向 /oauth/token 换取 access token / refresh token,返回实现了 User 接口的实例。

异常:

  • StateNotFoundError — state 不存在或已被消费(重放攻击防护)
  • AuthError — 服务端授权失败(非 200 响应)
  • ShangCloudError — 其他网络或服务端错误

client.set_client_secret(client_secret)

更换 Client Secret。

client.set_client_secret("new-secret")

User 接口

class User(ABC):
    def init_user(self, access_token, refresh_token, token_type, expires_in, client): ...
    def save(self) -> None: ...
    def is_expired(self) -> bool: ...
    def get_basic_info(self) -> UserBasicInfo: ...
    def get_variable(self, key: str) -> str: ...
    def set_variable(self, key: str, value: str) -> None: ...
    def delete_variable(self, key: str) -> None: ...

SDK 提供了默认的内存实现 UserInstanceis_expired() 会提前 60 秒返回 Trueget_basic_info() 会请求 /api/user/info

用户变量读写

get_variable / set_variable / delete_variable 通过 /api/varibles 操作当前用户的变量存储,需要授权时携带 var:io scope。

user.set_variable("theme", "dark")
value = user.get_variable("theme")
user.delete_variable("theme")

UserBasicInfo

@dataclass
class UserBasicInfo:
    user_id: int      # uid
    nickname: str
    mail: str
    avatar: str

自定义扩展

自定义 state 存储

实现 TempVarStorage 抽象类,替换为 Redis 等共享存储,适用于多进程 / 多实例部署:

from shangcloud import TempVarStorage, Client
import redis

class RedisKv(TempVarStorage):
    def __init__(self):
        self._r = redis.Redis()

    def set_temp_variable(self, key: str, value: str) -> None:
        self._r.setex(key, 300, value)  # 5 分钟过期

    def get_temp_variable(self, key: str) -> str:
        v = self._r.get(key)
        if v is None:
            raise KeyError(key)
        return v.decode()

    def delete_temp_variable(self, key: str) -> None:
        self._r.delete(key)

client = Client("id", "secret", "https://example.com/callback")
client.kv_storage = RedisKv()

实现须自行保证线程安全(内置 RamKv 已通过 threading.Lock 保证)。

自定义 User 持久化

继承 User 抽象类,在 init_user / save 中加入数据库持久化逻辑:

from shangcloud import User, UserBasicInfo, Client

class SessionUser(User):
    def __init__(self, session: dict):
        self._session = session
        self._client: Client | None = None

    def init_user(self, access_token, refresh_token, token_type, expires_in, client):
        self._client = client
        self._session["access_token"]  = access_token
        self._session["refresh_token"] = refresh_token
        self._session["token_type"]    = token_type
        self._session["expires_in"]    = expires_in
        self.save()

    def save(self):
        pass  # session dict 自动持久化

    def is_expired(self) -> bool:
        from datetime import datetime, timedelta
        expiry = self._session.get("expiry_time")
        if expiry is None:
            return True
        return datetime.now() + timedelta(seconds=60) > expiry

    def get_basic_info(self) -> UserBasicInfo:
        return self._client._get_user_basic_info(
            self._session["access_token"],
            self._session["token_type"],
        )

注意事项

  • 内存 KV 仅适用于单进程。多 worker / 多进程部署(如 gunicorn 多进程模式)时,请替换 kv_storage 为 Redis 等共享存储,否则 state 校验会失败。
  • _client_secret 与 token 字段均为私有属性,不会出现在 vars(client) 或日志中,但仍应避免将客户端对象直接序列化输出。
  • is_expired() 提前 60 秒返回 True,确保 token 在请求过程中不会中途失效。
  • SDK 不实现 token 刷新,refresh_tokenUserInstance 存储但不主动使用;需要刷新时请自行调用平台的 refresh 端点后重建 UserInstance

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

shangcloud_sdk-1.0.0.tar.gz (9.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

shangcloud_sdk-1.0.0-py3-none-any.whl (8.3 kB view details)

Uploaded Python 3

File details

Details for the file shangcloud_sdk-1.0.0.tar.gz.

File metadata

  • Download URL: shangcloud_sdk-1.0.0.tar.gz
  • Upload date:
  • Size: 9.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for shangcloud_sdk-1.0.0.tar.gz
Algorithm Hash digest
SHA256 ea49b6fca0784affa6174699349359ff08dcb4a42b13825cec3be894b71eec94
MD5 88c692ba1d86dcf2e980521749e35b15
BLAKE2b-256 ac2e012cde27c2ecb98aed43b8c2161ce067bb08e9bddf44699694d77f10b6c3

See more details on using hashes here.

Provenance

The following attestation bundles were made for shangcloud_sdk-1.0.0.tar.gz:

Publisher: publish.yml on YearnstudioHorizon/shangcloud-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file shangcloud_sdk-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: shangcloud_sdk-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 8.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for shangcloud_sdk-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e2a9d4574c5045facf0f9e000eeb5af8afc56ee395494a98dd4464f53c279d6d
MD5 828f23de31ca127a32a4a8b3830056dc
BLAKE2b-256 01ea9e497ea3a7c5dda5861fba0fd2beb49a2b1894af4527d68044cfd074640e

See more details on using hashes here.

Provenance

The following attestation bundles were made for shangcloud_sdk-1.0.0-py3-none-any.whl:

Publisher: publish.yml on YearnstudioHorizon/shangcloud-sdk-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page