mirror of
https://gitlab.com/Binaryify/neteasecloudmusicapi.git
synced 2025-05-23 22:37:41 +08:00
增加二维码登录
This commit is contained in:
parent
bf50fa65eb
commit
77775b25f5
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
[sqaiyan/netmusic-node](https://github.com/sqaiyan/netmusic-node)
|
[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. 手机登录
|
#### 1. 手机登录
|
||||||
|
|
||||||
@ -419,6 +419,24 @@ v3.30.0后支持手动传入cookie,登录接口返回内容新增 `cookie` 字
|
|||||||
cookie:"xxx"
|
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`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#### 注意
|
#### 注意
|
||||||
|
|
||||||
|
34
module/login_qr_check.js
Normal file
34
module/login_qr_check.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
18
module/login_qr_create.js
Normal file
18
module/login_qr_create.js
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
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) : '',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
26
module/login_qr_key.js
Normal file
26
module/login_qr_key.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
@ -1,21 +1,26 @@
|
|||||||
// 登录状态
|
module.exports = async (query, request) => {
|
||||||
|
const data = {}
|
||||||
module.exports = (query, request) => {
|
let result = await request(
|
||||||
return request(
|
'POST',
|
||||||
'GET',
|
`https://music.163.com/weapi/w/nuser/account/get`,
|
||||||
`https://music.163.com`,
|
data,
|
||||||
{},
|
{
|
||||||
{ cookie: query.cookie, proxy: query.proxy, realIP: query.realIP },
|
crypto: 'weapi',
|
||||||
).then((response) => {
|
cookie: query.cookie,
|
||||||
try {
|
proxy: query.proxy,
|
||||||
let profile = eval(`(${/GUser\s*=\s*([^;]+);/.exec(response.body)[1]})`)
|
realIP: query.realIP,
|
||||||
let bindings = eval(`(${/GBinds\s*=\s*([^;]+);/.exec(response.body)[1]})`)
|
},
|
||||||
response.body = { code: 200, profile: profile, bindings: bindings }
|
)
|
||||||
return response
|
if (result.body.code === 200) {
|
||||||
} catch (err) {
|
result = {
|
||||||
response.status = 301
|
status: 200,
|
||||||
response.body = { code: 301 }
|
body: {
|
||||||
return Promise.reject(response)
|
data: {
|
||||||
|
...result.body,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
cookie: result.cookie,
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"express-fileupload": "^1.1.9",
|
"express-fileupload": "^1.1.9",
|
||||||
"pac-proxy-agent": "^4.0.0",
|
"pac-proxy-agent": "^4.0.0",
|
||||||
|
"qrcode": "^1.4.4",
|
||||||
"tunnel": "^0.0.6"
|
"tunnel": "^0.0.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
66
public/qrlogin.html
Normal file
66
public/qrlogin.html
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<!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 {
|
try {
|
||||||
answer.body = body
|
answer.body = body
|
||||||
answer.status = answer.body.code || res.status
|
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
|
answer.status = 200
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user