提交 77775b25 编写于 作者: B binaryify

增加二维码登录

上级 bf50fa65
......@@ -18,6 +18,8 @@
[sqaiyan/netmusic-node](https://github.com/sqaiyan/netmusic-node)
[greats3an/pyncm](https://github.com/greats3an/pyncm)
## 环境要求
......
......@@ -373,7 +373,7 @@ $ sudo docker run -d -p 3000:3000 netease-music-api
### 登录
说明 : 登录有个接口,建议使用`encodeURIComponent`对密码编码或者使用`POST`请求,避免某些特殊字符无法解析,如`#`(`#`在url中会被识别为hash,而不是query)
说明 : 登录有个接口,建议使用`encodeURIComponent`对密码编码或者使用`POST`请求,避免某些特殊字符无法解析,如`#`(`#`在url中会被识别为hash,而不是query)
#### 1. 手机登录
......@@ -419,6 +419,24 @@ v3.30.0后支持手动传入cookie,登录接口返回内容新增 `cookie` 字
cookie:"xxx"
}
```
#### 3. 二维码登录
说明: 二维码登录涉及到3个接口
1. 二维码key生成接口
说明: 调用此接口可生成一个key
**接口地址 :** `/login/qr/key`
2. 二维码生成接口
说明: 调用此接口传入上一个接口生成的key可生成二维码图片的base64和二维码信息,可使用base64展示图片,或者使用二维码信息内容自行使用第三方二维码生产库渲染二维码
可选参数: `qrimg` 传入后
**接口地址 :** `/login/qr/create`
3. 二维码检测扫码状态接口
说明: 轮询此接口可获取二维码扫码状态,801为等待扫码,802为待确认,803为授权登陆成功
**接口地址 :** `/login/qr/check`
#### 注意
......
module.exports = async (query, request) => {
const data = {
key: query.key,
type: 1,
}
try {
let result = await request(
'POST',
`https://music.163.com/weapi/login/qrcode/client/login`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
result = {
status: 200,
body: {
...result.body,
cookie: result.cookie.join(';'),
},
cookie: result.cookie,
}
return result
} catch (error) {
return {
status: 200,
body: {},
cookie: result.cookie,
}
}
}
const QRCode = require('qrcode')
module.exports = (query, request) => {
return new Promise(async (resolve) => {
const url = `https://music.163.com/login?codekey=${query.key}`
return resolve({
code: 200,
status: 200,
body: {
code: 200,
data: {
qrurl: url,
qrimg: query.qrimg ? await QRCode.toDataURL(url) : '',
},
},
})
})
}
module.exports = async (query, request) => {
const data = {
type: 1,
}
const result = await request(
'POST',
`https://music.163.com/weapi/login/qrcode/unikey`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
return {
status: 200,
body: {
data: {
...result.body,
code: 200,
},
},
cookie: result.cookie,
}
}
// 登录状态
module.exports = (query, request) => {
return request(
'GET',
`https://music.163.com`,
{},
{ cookie: query.cookie, proxy: query.proxy, realIP: query.realIP },
).then((response) => {
try {
let profile = eval(`(${/GUser\s*=\s*([^;]+);/.exec(response.body)[1]})`)
let bindings = eval(`(${/GBinds\s*=\s*([^;]+);/.exec(response.body)[1]})`)
response.body = { code: 200, profile: profile, bindings: bindings }
return response
} catch (err) {
response.status = 301
response.body = { code: 301 }
return Promise.reject(response)
module.exports = async (query, request) => {
const data = {}
let result = await request(
'POST',
`https://music.163.com/weapi/w/nuser/account/get`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
if (result.body.code === 200) {
result = {
status: 200,
body: {
data: {
...result.body,
},
},
cookie: result.cookie,
}
})
}
return result
}
......@@ -40,6 +40,7 @@
"express": "^4.17.1",
"express-fileupload": "^1.1.9",
"pac-proxy-agent": "^4.0.0",
"qrcode": "^1.4.4",
"tunnel": "^0.0.6"
},
"devDependencies": {
......
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>二维码登录</title>
</head>
<body>
<img id="qrImg" />
<div id="info" class="info"></div>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.20.0-0/axios.min.js
"></script>
<script>
async function checkStatus(key) {
const res = await axios({
url: `/login/qr/check?key=${key}&timerstamp=${Date.now()}`,
withCredentials: true, //关键
})
return res.data
}
async function getLoginStatus() {
const res = await axios({
url: `/login/status?timerstamp=${Date.now()}`,
withCredentials: true, //关键
})
document.querySelector('#info').innerText = JSON.stringify(res.data, null, 2)
}
async function login() {
let timer
let timestamp = Date.now()
this.getLoginStatus()
const res = await axios({
url: `/login/qr/key?timerstamp=${Date.now()}`,
withCredentials: true, //关键
})
const key = res.data.data.unikey
const res2 = await axios({
url: `/login/qr/create?key=${key}&qrimg=true&timerstamp=${Date.now()}`,
withCredentials: true, //关键
})
document.querySelector('#qrImg').src = res2.data.data.qrimg
timer = setInterval(async () => {
const statusRes = await this.checkStatus(key)
if (statusRes.code === 800) {
alert('二维码已过期,请重新获取')
clearInterval(timer)
}
if (statusRes.code === 803) {
// 这一步会返回cookie
clearInterval(timer)
alert('授权登录成功')
await this.getLoginStatus()
}
}, 3000)
}
login()
</script>
<style>
.info{
white-space: pre;
}
</style>
</body>
</html>
......@@ -153,7 +153,11 @@ const createRequest = (method, url, data, options) => {
try {
answer.body = body
answer.status = answer.body.code || res.status
if (answer.body.code === 502) {
if (
[201, 302, 400, 502, 800, 801, 802, 803].indexOf(answer.body.code) >
-1
) {
// 特殊状态码
answer.status = 200
}
} catch (e) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册