6.5.3 QQ 登录:QQ 互联平台接入
一句话破题
QQ 登录通过 QQ 互联平台接入,流程与标准 OAuth 2.0 一致,是国内接入门槛相对较低的社交登录方式。
核心价值
接入 QQ 登录能让你:
- 覆盖 QQ 生态的用户群体
- 相比微信,个人开发者也能申请
- 熟悉标准 OAuth 2.0 流程
快速上手
前置条件
- 注册 QQ 互联 开发者账号
- 创建应用,配置回调地址
- 获取 APP ID 和 APP Key
实现代码
typescript
// app/api/auth/qq/route.ts
export async function GET() {
const state = generateSecureState()
const params = new URLSearchParams({
response_type: 'code',
client_id: process.env.QQ_APP_ID!,
redirect_uri: 'https://your-site.com/api/auth/qq/callback',
state,
scope: 'get_user_info',
})
return Response.redirect(
`https://graph.qq.com/oauth2.0/authorize?${params}`
)
}typescript
// app/api/auth/qq/callback/route.ts
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const code = searchParams.get('code')
const state = searchParams.get('state')
if (!verifyState(state)) {
return Response.redirect('/login?error=invalid_state')
}
// 1. 用 code 换 access_token
const tokenRes = await fetch(
`https://graph.qq.com/oauth2.0/token?` +
`grant_type=authorization_code` +
`&client_id=${process.env.QQ_APP_ID}` +
`&client_secret=${process.env.QQ_APP_KEY}` +
`&code=${code}` +
`&redirect_uri=${encodeURIComponent('https://your-site.com/api/auth/qq/callback')}`
)
// QQ 返回的是 query string 格式
const tokenText = await tokenRes.text()
const tokenParams = new URLSearchParams(tokenText)
const accessToken = tokenParams.get('access_token')
// 2. 获取 OpenID
const openidRes = await fetch(
`https://graph.qq.com/oauth2.0/me?access_token=${accessToken}`
)
const openidText = await openidRes.text()
// 返回格式: callback( {"client_id":"...","openid":"..."} );
const openidJson = JSON.parse(openidText.match(/\{.*\}/)?.[0] || '{}')
const openid = openidJson.openid
// 3. 获取用户信息
const userRes = await fetch(
`https://graph.qq.com/user/get_user_info?` +
`access_token=${accessToken}` +
`&oauth_consumer_key=${process.env.QQ_APP_ID}` +
`&openid=${openid}`
)
const userInfo = await userRes.json()
// 4. 创建或关联用户
const user = await findOrCreateUser({
qqOpenid: openid,
nickname: userInfo.nickname,
avatar: userInfo.figureurl_qq_2 || userInfo.figureurl_qq_1,
})
await createSession(user)
return Response.redirect('/dashboard')
}QQ 登录的特殊之处
1. 返回格式非标准 JSON
QQ 的某些接口返回的不是标准 JSON,需要特殊处理:
typescript
// access_token 返回格式
access_token=xxx&expires_in=7776000&refresh_token=xxx
// me 接口返回格式
callback( {"client_id":"xxx","openid":"xxx"} );2. 没有 unionid
QQ 登录目前不提供类似微信 unionid 的跨应用统一标识,只有 openid。
避坑指南
新手最容易犯的错
- 没有正确解析非标准 JSON 响应
- 回调地址必须与注册时完全一致(包括协议)
- scope 参数使用下划线:
get_user_info
