用户授权信息获取流程
OAuth 2.0 授权流程及微信小程序用户信息获取实现
问题
描述前端获取用户授权信息的完整流程,包括 OAuth 2.0 授权码模式和微信小程序授权。
解答
OAuth 2.0 授权码模式流程
┌──────────┐ ┌──────────┐
│ 用户 │ │ 第三方应用 │
└────┬─────┘ └────┬─────┘
│ │
│ 1. 点击第三方登录 │
│─────────────────────────────────────────>│
│ │
│ 2. 重定向到授权服务器 │
│<─────────────────────────────────────────│
│ │
│ 3. 用户登录并授权 │
│─────────────────────────────────────────>│ 授权服务器
│ │
│ 4. 返回授权码 code │
│<─────────────────────────────────────────│
│ │
│ 5. 携带 code 请求后端 │
│─────────────────────────────────────────>│ 后端服务器
│ │
│ 6. 后端用 code 换 access_token │
│ │
│ 7. 用 token 获取用户信息 │
│ │
│ 8. 返回用户信息给前端 │
│<─────────────────────────────────────────│
前端实现(以 GitHub 登录为例)
// 1. 跳转到授权页面
function redirectToAuth() {
const clientId = 'your_client_id'
const redirectUri = encodeURIComponent('https://yoursite.com/callback')
const scope = 'user:email'
window.location.href =
`https://github.com/login/oauth/authorize?client_id=${clientId}&redirect_uri=${redirectUri}&scope=${scope}`
}
// 2. 回调页面处理授权码
function handleCallback() {
const urlParams = new URLSearchParams(window.location.search)
const code = urlParams.get('code')
if (code) {
// 将 code 发送给后端换取用户信息
fetchUserInfo(code)
}
}
// 3. 请求后端获取用户信息
async function fetchUserInfo(code) {
const response = await fetch('/api/auth/github', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code })
})
const userInfo = await response.json()
// 存储用户信息和 token
localStorage.setItem('user', JSON.stringify(userInfo))
}
微信小程序授权流程
// 1. 获取用户登录凭证 code
async function login() {
const { code } = await wx.login()
// 2. 发送 code 到后端,换取 openid 和 session_key
const { data } = await wx.request({
url: 'https://yourserver.com/api/wx/login',
method: 'POST',
data: { code }
})
// 存储自定义登录态
wx.setStorageSync('token', data.token)
}
// 3. 获取用户信息(需用户点击授权按钮)
function getUserProfile() {
wx.getUserProfile({
desc: '用于完善用户资料',
success: (res) => {
const { userInfo, encryptedData, iv } = res
// 发送加密数据到后端解密
wx.request({
url: 'https://yourserver.com/api/wx/userinfo',
method: 'POST',
data: { encryptedData, iv },
header: { Authorization: wx.getStorageSync('token') }
})
}
})
}
<!-- 小程序 WXML:必须通过按钮触发 -->
<button bindtap="getUserProfile">获取用户信息</button>
后端处理示例(Node.js)
// 用 code 换取 access_token 和用户信息
async function githubAuth(code) {
// 1. 用 code 换 access_token
const tokenRes = await fetch('https://github.com/login/oauth/access_token', {
method: 'POST',
headers: { Accept: 'application/json' },
body: JSON.stringify({
client_id: process.env.GITHUB_CLIENT_ID,
client_secret: process.env.GITHUB_CLIENT_SECRET,
code
})
})
const { access_token } = await tokenRes.json()
// 2. 用 access_token 获取用户信息
const userRes = await fetch('https://api.github.com/user', {
headers: { Authorization: `Bearer ${access_token}` }
})
return userRes.json()
}
关键点
- 授权码模式:code 只能使用一次,且有效期短(通常几分钟)
- 前后端分离:code 换 token 必须在后端完成,避免暴露 client_secret
- 微信小程序:wx.login 获取 code,wx.getUserProfile 需用户主动点击触发
- 安全存储:access_token 存后端,前端只存自定义的登录态 token
- state 参数:OAuth 授权时应携带随机 state 防止 CSRF 攻击
目录