當用戶打開某頁面(如:/goodslist
),咱們須要獲取用戶信息或實現用戶自動登陸,讓用戶進行微信受權。html
使頁面跳轉到微信給定的受權頁面(https://open.weixin.qq.com/connect/oauth2/authorize?{一些傳參}#wechat_redirect
)前端
該受權頁會提示用戶受權,這樣用戶是否受權,微信可以感知到。react
受權成功後,跳回咱們在{一些參數}中指定的redirect_uri
重定向頁面,通常設爲跳轉以前的頁面(/goodslist
)ios
微信會在重定向uri後面添加參數code,如:/goodslist?code=xxxxxx(還有一個參數state)
web
在跳回的頁面拿到code去跟微信換取用戶信息(第一步,使用code換取access_token;第二步,拉取用戶信息)redux
使用code換取用戶信息由咱們本身的服務端去請求,前端就不用管了,由於須要提交一些安全性參數後端
code
應用受權做用域,可選值:snsapi_base, snsapi_userinfoapi
snsapi_base瀏覽器
不彈出受權頁面,直接跳轉,只能獲取用戶openid安全
snsapi_userinfo
彈出受權頁面,可經過openid拿到暱稱、性別、所在地。而且, 即便在未關注的狀況下,只要用戶受權,也能獲取其信息
// src/utils/env.js
// 使用bowser庫
import Bowser from 'bowser'
const parsed = Bowser.getParser(window.navigator.userAgent).parsedResult
// 是否微信環境
export const inWechat = parsed.browser.name === 'WeChat'
export const inIOS = parsed.os.name === 'iOS'
export const inSafari = parsed.browser.name === 'Safari'
複製代碼
// src/auth.js
import qs from 'qs'
// store2庫 方便操做localStorage 和 sessionStorage
import store from 'store2'
import { inWechat } from '@/utils/env'
import { getUserInfo } from '@/service/login'
// 微信appid
const appid = 'wxxxxxxxxxxxxx'
// 前往受權
const goAuth = () => {
const uri = 'https://open.winxin.qq.com/connect/oauth2/authorize'
const params = {
appid,
redirect_uri: window.location.href,
response_type: 'code',
scope: 'snsapi_userinfo',
state: 'STATE'
}
const hash = 'wechat_redirect'
const url = `${url}?${qs.stringify(params)}#${hash}`
// 頁面跳轉,ios等機型禁止了直接使用location.href跳轉
// window.location.href = url // 不能使用
const nextPage = document.createElement('a')
nextPage.setAttribute('href', url)
nextPage.click()
// 這裏爲了得到更友好的效果,能夠提示用戶須要受權,給出一個前往受權的按鈕。用戶點擊後觸發
}
/** 受權返回 * code - 受權後redirect_uri後面參數中的code * callback - 這裏通常指定爲dom渲染的操做 */
const authBack = async (code, callback) => {
// 使用code請求用戶信息
await getUserInfo(code)
callback()
}
export default async callback => {
if (
window.location.pathname === '/login' // 登陸綁定頁
|| store('token') // 已登陸
|| !inWechat // 非微信環境下
) {
// 直接渲染dom
return callback()
}
// 解析querystring
const params = qs.parse(window.location.search, { ignoreQueryPrefix: true })
params.code === undefined ? goAuth() : await authBack(params.code, callback)
}
複製代碼
// src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import auth from './auth'
import { Provider } from 'react-redux'
import store from './store'
import Router from './router'
const renderDom = () => ReactDOM.render(
<Provider store={store}> <Router /> </Provider>,
document.getElementById('root')
)
// 受權完成後,才能繼續頁面渲染,這樣能夠阻止頁面中發出的請求。
// 尤爲是這些請求中有的是要求必須登陸的,將致使頁面跳轉到登陸頁
auth(renderDom)
複製代碼
redirect_uri
設置爲一個後端地址(前端路由不能匹配到的地址,如:/auth
);
state
設置爲前端回跳地址, 如:window.location.href
用戶受權成功後,微信跳轉到後端地址並帶上code和state參數(/auth?code={code}&state={前端地址}
)
後端(/auth
)獲取到code以後,跟微信交換用戶信息。若是該微信用戶已註冊,則進行登陸操做,返回token,將頁面重定向到{前端地址}?token={token}&openid={openid}&{其餘用戶信息}
;該用戶未註冊,則重定向到{登陸頁面}?openid={openid}
能夠簡化前端流程
後端重定向前端頁面,會將token等用戶信息數據暴露,致使安全風險