1.同步调整到OAuth2方式登录 2.微信小程序一键登录;

This commit is contained in:
sfmind 2022-06-02 17:59:57 +08:00
parent e1c08c4661
commit 13b5ad127a
11 changed files with 177 additions and 62 deletions

View File

@ -3,11 +3,13 @@ const { http } = uni.$u
//使用手机 + 密码登录
export const passwordLogin = data => http.post('/member/auth/login', data)
//退出登录
export const logout = data => http.post('/member/auth/logout', data)
//发送手机验证码
export const sendSmsCode = data => http.post('/member/auth/send-sms-code', data)
//使用手机 + 验证码登录
export const smsLogin = data => http.post('/member/auth/sms-login', data)
//社交登录,使用 (手机号授权)code + 用户信息
export const socialLogin = data => http.post('/member/auth/social-login', data)
//微信小程序的一键登录
export const weixinMiniAppLogin = data => http.post('/member/auth/weixin-mini-app-login', data)
//刷新令牌
export const refreshToken = data => http.post('/member/auth/refresh-token', data)
//退出登录
export const logout = data => http.post('/member/auth/logout', data)

View File

@ -1,6 +1,10 @@
module.exports = {
//后端接口地址
baseUrl: 'http://127.0.0.1:48080/app-api',
// 超时
timeout: 30000,
// 禁用 Cookie 等信息
withCredentials: false,
header: {
//租户ID
'tenant-id': 1

View File

@ -21,6 +21,6 @@ const app = new Vue({
})
// 引入请求封装
require('./util/request/index')(app)
require('./utils/request/index')(app)
app.$mount()

View File

@ -139,15 +139,30 @@ export default {
},
handleSubmit() {
this.$refs.form.validate().then(res => {
this.$store.dispatch('Login', { type: this.currentModeIndex, data: this.formData }).then(res => {
uni.$u.toast('登录成功')
setTimeout(() => {
uni.switchTab({
url: '/pages/user/user'
})
}, 300)
uni.login({
provider: 'weixin',
success: res => {
let data = this.formData
data.socialType = 34 //WECHAT_MINI_APP
data.socialCode = res.code
data.socialState = Math.random() //
this.mobileLogin(data)
},
fail: res => {
this.mobileLogin(this.formData)
}
})
})
},
mobileLogin(data){
this.$store.dispatch('Login', { type: this.currentModeIndex, data: data }).then(res => {
uni.$u.toast('登录成功')
setTimeout(() => {
uni.switchTab({
url: '/pages/user/user'
})
}, 300)
})
}
}
}

View File

@ -33,7 +33,7 @@ export default {
onReady() {},
methods: {
getPhoneNumber(e) {
let code = e.detail.code
let phoneCode = e.detail.code
if (!e.detail.code) {
uni.showModal({
title: '授权失败',
@ -50,10 +50,10 @@ export default {
}
})
} else {
uni.getUserInfo({
uni.login({
provider: 'weixin',
success: res => {
this.$store.dispatch('Login', { type: 2, data: { code: code, userData: res } }).then(res => {
this.$store.dispatch('Login', { type: 2, data: { phoneCode: phoneCode, loginCode: res.code } }).then(res => {
uni.$u.toast('登录成功')
setTimeout(() => {
uni.switchTab({

View File

@ -2,24 +2,25 @@ import Vue from 'vue'
import Vuex from 'vuex'
import { logout } from '@/api/auth'
import { getUserInfo } from '@/api/user'
import { passwordLogin, smsLogin, socialLogin } from '@/api/auth'
import { passwordLogin, smsLogin, weixinMiniAppLogin } from '@/api/auth'
const TokenKey = 'App-Token'
const AccessTokenKey = 'ACCESS_TOKEN'
const RefreshTokenKey = 'REFRESH_TOKEN'
Vue.use(Vuex) // vue的插件机制
// Vuex.Store 构造器选项
const store = new Vuex.Store({
state: {
openExamine: false, // 是否开启审核状态。用于小程序、App 等审核时关闭部分功能。TODO 芋艿:暂时没找到刷新的地方
token: uni.getStorageSync(TokenKey), // 用户身份 Token
userInfo: {}, // 用户基本信息
timerIdent: false // 全局 1s 定时器,只在全局开启一个,所有需要定时执行的任务监听该值即可,无需额外开启 TODO 芋艿:需要看看
accessToken: uni.getStorageSync(AccessTokenKey), // 访问令牌
refreshToken: uni.getStorageSync(RefreshTokenKey), // 刷新令牌
userInfo: {}
},
getters: {
token: state => state.token,
accessToken: state => state.accessToken,
refreshToken: state => state.refreshToken,
userInfo: state => state.userInfo,
hasLogin: state => !!state.token
hasLogin: state => !!state.accessToken
},
mutations: {
// 更新 state 的通用方法
@ -32,12 +33,14 @@ const store = new Vuex.Store({
state[param.key] = param.val
}
},
// 更新token
// 更新令牌
SET_TOKEN(state, data) {
// 设置 Token
const { token } = data
state.token = token
uni.setStorageSync(TokenKey, token)
// 设置令牌
const { accessToken, refreshToken } = data
state.accessToken = accessToken
state.refreshToken = refreshToken
uni.setStorageSync(AccessTokenKey, accessToken)
uni.setStorageSync(RefreshTokenKey, refreshToken)
// 加载用户信息
this.dispatch('ObtainUserInfo')
@ -46,10 +49,12 @@ const store = new Vuex.Store({
SET_USER_INFO(state, data) {
state.userInfo = data
},
// 清空 Token 和 用户信息
// 清空令牌 和 用户信息
CLEAR_LOGIN_INFO(state) {
uni.removeStorageSync(TokenKey)
state.token = ''
uni.removeStorageSync(AccessTokenKey)
uni.removeStorageSync(RefreshTokenKey)
state.accessToken = ''
state.refreshToken = ''
state.userInfo = {}
}
},
@ -65,7 +70,7 @@ const store = new Vuex.Store({
commit('SET_TOKEN', res.data)
})
} else {
return socialLogin(data).then(res => {
return weixinMiniAppLogin(data).then(res => {
commit('SET_TOKEN', res.data)
})
}

View File

@ -1,29 +0,0 @@
/**
* 响应拦截
* @param {Object} http
*/
module.exports = vm => {
uni.$u.http.interceptors.response.use(
res => {
//对响应成功做点什么 可使用async await 做异步操作
//可以根据业务情况做相应的处理
if (res.data.code === 0) {
return res.data
} else if(res.data.code === 401) {
//用户未登录或登录token已过期
vm.$store.commit('CLEAR_LOGIN_INFO')
} else {
console.log(res)
//其他错误信息统一处理
uni.$u.toast(res.data.msg)
return Promise.reject(res)
}
},
err => {
//对响应错误做点什么 statusCode !== 200
console.log(err)
uni.$u.toast('响应错误' + err.statusCode)
return Promise.reject(err)
}
)
}

View File

@ -0,0 +1,6 @@
export default {
'401': '认证失败,无法访问系统资源',
'403': '当前操作没有权限',
'404': '访问资源不存在',
'default': '系统未知错误,请反馈给管理员'
}

View File

@ -0,0 +1,14 @@
// 引入配置
import config from '@/common/config'
// 初始化请求配置
uni.$u.http.setConfig((defaultConfig) => {
/* defaultConfig 为默认全局配置 */
defaultConfig.baseURL = config.baseUrl /* 根域名 */
defaultConfig.header = config.header
return defaultConfig
})
module.exports = (vm) => {
require('./requestInterceptors')(vm)
require('./responseInterceptors')(vm)
}

View File

@ -9,7 +9,7 @@ module.exports = vm => {
// 初始化请求拦截器时会执行此方法此时data为undefined赋予默认{}
config.data = config.data || {}
if (vm.$store.getters.hasLogin) {
config.header.authorization = 'Bearer ' + vm.$store.getters.token
config.header.Authorization = 'Bearer ' + vm.$store.getters.accessToken
}
return config
},

View File

@ -0,0 +1,98 @@
import errorCode from '@/utils/request/errorCode'
import { refreshToken } from '@/api/auth'
// 需要忽略的提示。忽略后,自动 Promise.reject('error')
const ignoreMsgs = [
'无效的刷新令牌', // 刷新令牌被删除时,不用提示
'刷新令牌已过期' // 使用刷新令牌,刷新获取新的访问令牌时,结果因为过期失败,此时需要忽略。否则,会导致继续 401无法跳转到登出界面
]
// 请求队列
let requestList = []
// 是否正在刷新中
let isRefreshToken = false
/**
* 响应拦截
* @param {Object} http
*/
module.exports = vm => {
uni.$u.http.interceptors.response.use(
async res => {
const code = res.data.code || 0
const msg = res.data.msg || errorCode[code] || errorCode['default']
if (ignoreMsgs.indexOf(msg) !== -1) {
// 如果是忽略的错误码,直接返回 msg 异常
return Promise.reject(msg)
} else if (code === 401) {
// 如果未认证,并且未进行刷新令牌,说明可能是访问令牌过期了
if (!isRefreshToken) {
isRefreshToken = true
// 1. 如果获取不到刷新令牌,则只能执行登出操作
if (!vm.$store.getters.refreshToken()) {
vm.$store.commit('CLEAR_LOGIN_INFO')
return Promise.reject(res)
}
// 2. 进行刷新访问令牌
try {
const refreshTokenRes = await refreshToken()
// 2.1 刷新成功,则回放队列的请求 + 当前请求
vm.$store.commit('SET_TOKEN', refreshTokenRes.data)
requestList.forEach(cb => cb())
return uni.$u.http.request(res.config)
} catch (e) {
// 为什么需要 catch 异常呢?刷新失败时,请求因为 Promise.reject 触发异常。
// 2.2 刷新失败,只回放队列的请求
requestList.forEach(cb => cb())
// 登出。即不回放当前请求!不然会形成递归
vm.$store.commit('CLEAR_LOGIN_INFO')
return Promise.reject(res)
} finally {
requestList = []
isRefreshToken = false
}
} else {
// 添加到队列,等待刷新获取到新的令牌
return new Promise(resolve => {
requestList.push(() => {
res.config.header.Authorization = 'Bearer ' + vm.$store.getters.accessToken // 让每个请求携带自定义token 请根据实际情况自行修改
resolve(uni.$u.http.request(res.config))
})
})
}
} else if (code === 500) {
uni.$u.toast(msg)
return Promise.reject(res)
} else if (code === 901) {
uni.$u.toast('演示模式,无法进行写操作')
return Promise.reject(res)
} else if (code !== 0) {
if (msg === '无效的刷新令牌') {
// hard coding忽略这个提示直接登出
console.log(msg)
} else {
uni.$u.toast(msg)
}
return Promise.reject(res)
} else {
return res.data
}
},
err => {
console.log(err)
let { message } = err
if (!message) {
message = '系统发生未知错误'
}else if (message === 'Network Error') {
message = '后端接口连接异常'
} else if (message.includes('timeout')) {
message = '系统接口请求超时'
} else if (message.includes('Request failed with status code')) {
message = '系统接口' + message.substring(message.length - 3) + '异常'
}
uni.$u.toast(message)
return Promise.reject(err)
}
)
}