01.授权码登录open应用¶
同一个开放应用 id,最多同时有 2 个登录,如果有新的登录,则自动踢掉较早的那一个。
下面的几个案例代码,展示了用 授权码模式 授权登录:
1. 登录 openlist¶
#!/usr/bin/env python3
# encoding: utf-8
__author__ = "ChenyangGao <https://github.com/ChenyangGao>"
__version__ = (0, 0, 1)
from pathlib import Path
from p115client import P115Client
client = P115Client(Path("~/115-cookies.txt").expanduser())
from base64 import b64decode
from json import loads
from urllib.parse import parse_qsl, unquote, urlsplit
resp = client.request("https://api.oplist.org/115cloud/requests?driver_txt=115cloud_go&server_use=true")
client.cookies = dict(client.cookies)
payload = dict(parse_qsl(urlsplit(unquote(resp["text"][38:])).query))
resp = client.login_authorize_open(payload)
resp = client.request(resp["url"], follow_redirects=False, parse=...)
resp = loads(b64decode(resp.headers["location"][1:]))
client.access_token = resp["access_token"]
client.refresh_token = resp["refresh_token"]
2. 登录 clouddrive¶
#!/usr/bin/env python3
# encoding: utf-8
__author__ = "ChenyangGao <https://github.com/ChenyangGao>"
__version__ = (0, 0, 1)
from pathlib import Path
from p115client import P115Client
client = P115Client(Path("~/115-cookies.txt").expanduser())
from urllib.parse import parse_qsl, urlsplit
resp = client.login_authorize_open({
"client_id": 100195313,
"redirect_uri": "https://redirect115.zhenyunpan.com",
"state": "http://localhost:19798/",
})
resp = client.request(resp["url"], follow_redirects=False, parse=...)
resp = dict(parse_qsl(urlsplit(resp.headers["location"]).query))
client.access_token = resp["access_token"]
client.refresh_token = resp["refresh_token"]
可以直接借用它的 授权码登录 服务器,打开网页即自动授权,然后立即取得 access_token 和 refresh_token
#!/usr/bin/env python3
# encoding: utf-8
__author__ = "ChenyangGao <https://github.com/ChenyangGao>"
__version__ = (0, 0, 1)
from urllib.parse import urlencode
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, RedirectResponse
app = FastAPI(debug=True)
@app.get("/")
def index(request: Request):
return HTMLResponse("""\
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>115 开放应用授权示例</title>
<style>
body {
font-family: 'Roboto', sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background: linear-gradient(135deg, #f0f2f5 0%, #e0e5ec 100%);
color: #333;
}
.container {
background-color: #ffffff;
padding: 40px;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
text-align: center;
width: 90%;
max-width: 600px;
}
.fetch-button {
background-color: #4CAF50;
color: white;
padding: 15px 30px;
border: none;
border-radius: 8px;
font-size: 1.1em;
font-weight: 500;
cursor: pointer;
transition: background-color 0.3s ease, transform 0.2s ease;
box-shadow: 0 4px 10px rgba(76, 175, 80, 0.3);
margin-bottom: 30px;
}
.fetch-button:hover {
background-color: #45a049;
transform: translateY(-2px);
}
.input-group {
display: flex;
align-items: center;
margin-bottom: 20px;
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 10px;
padding: 10px;
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05);
}
.input-group label {
min-width: 80px;
text-align: right;
margin-right: 15px;
font-weight: 500;
color: #555;
}
.data-input {
flex-grow: 1;
padding: 12px;
border: 1px solid #ccc;
border-radius: 8px;
font-size: 1em;
color: #333;
background-color: #fff;
transition: border-color 0.3s ease;
}
.data-input:focus {
outline: none;
border-color: #6a82fb;
box-shadow: 0 0 0 3px rgba(106, 130, 251, 0.2);
}
.copy-button {
background-color: #007bff;
color: white;
padding: 10px 15px;
border: none;
border-radius: 8px;
margin-left: 10px;
cursor: pointer;
font-size: 0.9em;
transition: background-color 0.3s ease, transform 0.2s ease;
box-shadow: 0 2px 8px rgba(0, 123, 255, 0.2);
}
.copy-button:hover {
background-color: #0056b3;
transform: translateY(-1px);
}
</style>
</head>
<body>
<div class="container">
<button class="fetch-button" onclick="window.open('/auth', '_self')">点击授权</button>
<div class="input-group">
<label for="access_token">access_token</label>
<input type="text" id="access_token" class="data-input" readonly placeholder="点击按钮获取数据">
<button class="copy-button" data-target="access_token">复制</button>
</div>
<div class="input-group">
<label for="refresh_token">refresh_token</label>
<input type="text" id="refresh_token" class="data-input" readonly placeholder="点击按钮获取数据">
<button class="copy-button" data-target="refresh_token">复制</button>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const params = new URLSearchParams(window.location.search);
document.getElementById('access_token').value = params.get("access_token") || "";
document.getElementById('refresh_token').value = params.get("refresh_token") || "";
document.querySelectorAll('.copy-button').forEach(button => {
button.addEventListener('click', (event) => {
const targetElement = document.getElementById(event.target.dataset.target);
targetElement.select();
navigator.clipboard.writeText(targetElement.value);
});
});
});
</script>
</body>
</html>""")
@app.get("/auth")
def auth(request: Request):
url = "https://passportapi.115.com/open/authorize?" + urlencode({
"client_id": 100195313,
"redirect_uri": "https://redirect115.zhenyunpan.com",
"response_type": "code",
"state": "{scheme}://{server[0]}:{server[1]}".format_map(request.scope),
})
return RedirectResponse(url, 302)
if __name__ == "__main__":
from uvicorn import run
run(app, host="0.0.0.0", port=8115)