微信小程序授权登录三种实现方式
Posted 天边月_
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了微信小程序授权登录三种实现方式相关的知识,希望对你有一定的参考价值。
方式一:小程序授权登录
通过wx.login获取 临时登录凭证code,向后端换取token。 可以做到无感登录。
时序图:
说明:
1、客户端调用 wx.login() 获取 临时登录凭证code,通过 wx.request() 发起网络请求,将 code 传给服务端
2、服务端使用 code + appid + appsecret 向微信换取 (调用 auth.code2Session 接口)用户唯一标识openid 和 会话密钥session_key
3、服务端自定义 登录状态token(与openid、session_key关联)返回客户端
4、客户端将 登录状态token 存入 缓存storage(推荐使用 wx.setStorageSync(‘key’, ‘value’) 同步存储)
5、客户端wx.request() 发起请求时,携带 登录状态token (推荐使用 wx.getStorageSync(‘key’) 同步获取)
6、服务端通过 登录状态token 查询到对应 openid 和 session_key
7、验证成功后,返回业务数据给客户端
注意:
1、会话密钥session_key 是对⽤户数据进⾏加密签名的密钥。为了应⽤⾃身的数据安全,开发者服务器不应该把会话密钥下发到⼩程序,也不应该对外提供这个密钥。
2、临时登录凭证code 只能使⽤⼀次
code(以uni-app框架为例):
新建http.js,封装登录方法
// baseurl
let baseUrl = 'https://test.com.cn'
// 请求封装
async function _request(url, method, data = )
let res = await requestPromise(url, method, data)
if (res.code == 200)
return Promise.resolve(res)
else if (res.code == 401) // 无感刷新
return await login(url, method, data)
else
return Promise.reject(res)
// 登录
async function login(url, method, data)
let openIdUrl = new String()
// #ifdef MP-WEIXIN
openIdUrl = '微信登录接口地址'
//#endif
//#ifdef MP-ALIPAY
openIdUrl = '支付宝登录接口地址'
//#endif
let res = await requestPromise(openIdUrl, 'POST', code: await _getAppCode(), source: 'MP' )
if (res.code == 200)
// 将token,userid存入缓存
uni.setStorageSync('token', res.data.token)
uni.setStorageSync('userId', res.data.userId)
// 再次发起请求
return await _request(url, method, data)
else
return Promise.reject(res)
// 发送request请求
function requestPromise(url, method, data = )
return new Promise((resolve, reject) =>
uni.request(
header:
'Content-Type': 'application/json;charset=UTF-8',
'X-Token': uni.getStorageSync('token') || new String(),
'X-UserId': uni.getStorageSync('userId') || new String()
,
url: `$baseUrl$url`,
method: method,
data: data,
success: result =>
resolve(result)
,
fail: error =>
reject(error)
,
)
)
// 获取临时登录凭证code
function _getAppCode()
return new Promise((resolve, reject) =>
// #ifdef MP-WEIXIN
uni.login(
provider: 'weixin',
success(res)
resolve(res.code)
,
fail(err)
reject(err)
)
// #endif
// #ifdef MP-ALIPAY
// 系统建议使用支付宝原生写法
my.getAuthCode(
scopes: 'auth_base',
success(res)
resolve(res.authCode)
,
fail(err)
reject(err)
)
// #endif
)
module.exports =
$get: function(url, data, onSuccess, onError)
_request(url, 'GET', data).then(res =>
onSuccess && onSuccess(res)
).catch(err =>
onError && onError(err)
)
,
$put: function(url, data, onSuccess, onError)
_request(url, 'PUT', data).then(res =>
onSuccess && onSuccess(res)
).catch(err =>
onError && onError(err)
)
,
$post: function(url, data, onSuccess, onError)
_request(url, 'POST', data).then(res =>
onSuccess && onSuccess(res)
).catch(err =>
onError && onError(err)
)
,
$delete: function(url, data, onSuccess, onError)
_request(url, 'DELETE', data).then(res =>
onSuccess && onSuccess(res)
).catch(err =>
onError && onError(err)
)
,
baseUrl: baseUrl
新建api.js,对接口进行封装
import https from '../utils/https.js'
export function test(params)
return new Promise((resolve, reject) =>
https.$get("/api", params, res =>
return resolve(res)
, err =>
return reject(err)
)
)
方式二:手机号授权登录
过button按钮的bindgetphonenumber事件,弹出手机号授权,获取到加密数据后,向后端换取token。
说明:
1、过button按钮的bindgetphonenumber事件获取手机号加密数据,按钮需要设置open-type=“getPhoneNumber”
2、调用 wx.login() 获取 临时登录凭证code
3、将加密数据(encryptedData、iv、signature、rawData)和 临时登录凭证code传给服务端
4、服务端使用 code + appid + appsecret 向微信换取 (调用 auth.code2Session 接口)用户唯一标识openid 和 会话密钥session_key
5、服务端根据session_key,appid ,encryptedData,iv解密手机号
6、服务端自定义 登录状态token(与openid、session_key关联)返回客户端
7、客户端将 登录状态token 存入 缓存storage(推荐使用 wx.setStorageSync(‘key’, ‘value’) 同步存储)
8、客户端wx.request() 发起请求时,携带 登录状态token (推荐使用 wx.getStorageSync(‘key’) 同步获取)
9、服务端通过 登录状态token 查询到对应 openid 和 session_key
10、验证成功后,返回业务数据给客户端
注意:
在回调中调⽤ wx.login 登录,可能会刷新登录态。此时服务器使⽤ code 换取的sessionKey 不是加密时使⽤的 sessionKey,导致解密失败。建议开发者提前进⾏ login;或者在回调中先使⽤ checkSession 进⾏登录态检查,避免 login刷新登录态。
也就是说在触发getPhoneNumber方法(用户点击button)之前,就需要获取最新code。
code(以uni-app框架为例):
新建wxLogin.vue
<template>
<view class="wx-login">
<!-- #ifdef MP-WEIXIN -->
<u-button type="primary" text="微信用户一键登录" open-type="getPhoneNumber" :plain="true" @getphonenumber="getUserPhoneNumber"></u-button>
<!-- #endif -->
<!-- #ifdef MP-ALIPAY -->
<button open-type="getPhoneNumber" :plain="true"@getphonenumber="getUserPhoneNumber" scope='userInfo'>支付宝用户一键登录</button>
<!-- #endif -->
</view>
</template>
<script>
import mapActions from 'vuex'
export default
async created()
this.code = await this.getAppCode()
,
data()
return
// 用户凭证
code: new String()
,
methods:
...mapActions(['Login']),
// 微信用户手机号登录
getUserPhoneNumber(event)
if(event.detail.errMsg !== 'getPhoneNumber:ok') return
uni.showToast(
title: '登录中',
icon: 'loading',
mask: true
)
event.detail.code = this.code
this.Login( userInfo: event.detail ).then(async ( code, msg ) =>
if (code == 200) // 登录成功,跳转首页
uni.reLaunch( url: '/pages_home/home/index' )
else
this.code = await this.getAppCode()
uni.showToast(
icon: 'none',
title: msg,
duration: 2000
)
)
,
// 获取code
getAppCode()
return new Promise((resolve, reject) =>
// #ifdef MP-WEIXIN
uni.login(
provider: 'weixin',
success(res)
resolve(res.code)
,
fail(err)
reject(err)
)
// #endif
// #ifdef MP-ALIPAY
my.getAuthCode(
scopes: 'auth_base',
success(res)
resolve(res.authCode)
,
fail(err)
reject(err)
)
// #endif
)
,
</script>
<style lang="less" scoped>
.wx-login
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 0 32rpx 60rpx;
button
font-size: 28rpx;
font-weight: 400;
</style>
新建store/index.js 封装登录逻辑
import Vue from "vue"
import Vuex from 'vuex'
import loginByMobile from '@/api/login.js'
Vue.use(Vuex)
const store = new Vuex.Store(
state:
token: new String(),
userId: new String(),
userInfo: new Object(),
,
mutations:
SET_TOKEN: (state, token) =>
state.token = token
,
SET_USER: (state, userInfo) =>
state.userInfo = userInfo
,
SET_USERID: (state, userId) =>
state.userId = userId
,
,
actions:
// 登录
Login( commit , userInfo )
// 微信手机号登录
userInfo.type = 'WX_MP'
delete userInfo.errMsg
return new Promise((resolve, reject) =>
loginByMobile(userInfo).then(response =>
if (response.code == 200)
uni.setStorageSync('USER_ID', response.data.userId)
uni.setStorageSync('ACCESS_TOKEN', response.data.token)
uni.setStorageSync('userInfo', response.data)
commit('SET_USERID', response.data.userId)
commit('SET_TOKEN', response.data.token)
commit('SET_USER', response.data)
resolve(response)
).catch(error =>
reject(error)
)
)
,
// 登出
Logout( commit, state )
return new Promise((resolve) =>
commit('SET_USERID', new String())
commit('SET_TOKEN', new String())
commit('SET_USER', new Object())
uni.removeStorageSync('USER_ID')
uni.removeStorageSync('ACCESS_TOKEN')
uni.removeStorageSync('userInfo')
resolve('200')
)
,
,
)
export default store
main.js中引入vuex 并且挂载到vue实例上
//引入vuex 并且挂载到vue实例上
import store from "./store/index.js"
Vue.prototype.$store = store
request.js封装
import env from './env.js'
// http
export const request = (url, method, data = ) =>
return new Promise((resolve, reject) =>
uni.request(
header:
'Content-Type': 'application/json;charset=UTF-8',
'X-Token': uni.getStorageSync('ACCESS_TOKEN'),
'X-UserId': uni.getStorageSync('USER_ID'),
'satoken': uni.getStorageSync('userInfo').satoken
,
url: `$env.root$url`,
method: method,
data: data,
success: res =>
if (res.data.code == 401 || res.data.message == '请先登录')
// token过期 重新登录
uni.showToast(
icon: 'none',
title: '登录超时,请重新登录',
duration: 2000
)
uni.removeStorageSync('ACCESS_TOKEN')
uni.removeStorageSync('USER_ID')
uni.removeStorageSync('userInfo')
// 跳转登录
uni<完整微信小程序授权登录页面教程
完整微信小程序授权登录页面教程
1、前言
微信官方对getUserInfo接口做了修改,授权窗口无法直接弹出,而取而代之是需要创建一个button,将其open-type属性绑定getUseInfo方法。在参考了网路上各种方案之后,实现了用户在授权之后跳转到小程序首页的授权登录页面。
2、实现效果
3、实现思路
在进入小程序时先对授权情况进行判断,若已经过授权则直接跳转到首页,若还未经过授权则进入授权页面,点击页面的授权按钮会弹出选择框,选择“拒绝”则不进行跳转,选择“允许“则进行授权并跳转到小程序首页。
4、实现代码
<!--login.wxml-->
<view wx:if="{{canIUse}}">
<view class=‘header‘>
<image src=‘/assets/tasks_icon/check.png‘></image>
</view>
<view class=‘content‘>
<view>申请获取以下权限</view>
<text>获得你的公开信息(昵称,头像等)</text>
</view>
<button class=‘bottom‘ type=‘primary‘ open-type="getUserInfo" lang="zh_CN" bindgetuserinfo="bindGetUserInfo">
授权登录
</button>
</view>
<view wx:else>请升级微信版本</view>
//login.wxss
.header {
margin: 90rpx 0 90rpx 50rpx;
border-bottom: 1px solid #ccc;
text-align: center;
width: 650rpx;
height: 300rpx;
}
.header image {
width: 200rpx;
height: 200rpx;
}
.content {
margin-left: 50rpx;
margin-bottom: 90rpx;
}
.content text {
display: block;
color: #9d9d9d;
margin-top: 40rpx;
}
.bottom {
border-radius: 80rpx;
margin: 70rpx 50rpx;
font-size: 35rpx;
}
//login.js
Page({
data: {
//判断小程序的API,回调,参数,组件等是否在当前版本可用。
canIUse: wx.canIUse(‘button.open-type.getUserInfo‘)
},
onLoad: function () {
var that = this;
// 查看是否授权
wx.getSetting({
success: function (res) {
if (res.authSetting[‘scope.userInfo‘]) {
wx.getUserInfo({
success: function (res) {
// 用户已经授权过,调用微信的 wx.login 接口,从而获取code,再直接跳转到主页
wx.login({
success: res => {
// 获取到用户的 code 之后:res.code
console.log("用户的code:" + res.code);
}
});
wx.switchTab({
url: ‘/pages/home/home‘, //这里填入要跳转目的页面的url
success: (result) => {
console.log("跳转到首页");
},
fail: () => {}
});
}
});
} else {
// 用户没有授权,显示授权页面,这里不进行操作
}
}
});
},
bindGetUserInfo: function (e) {
if (e.detail.userInfo) {
//用户按了允许授权按钮
var that = this;
// 获取到用户的信息了,打印到控制台上看下
console.log("用户的信息如下:");
console.log(e.detail.userInfo);
//授权成功后,跳转页面
wx.switchTab({
url: ‘/pages/home/home‘, //这里填入要跳转目的页面的url
success: (result) => {
console.log("跳转到首页");
},
fail: () => {}
});
} else {
//用户按了拒绝按钮
wx.showModal({
title: ‘警告‘,
content: ‘您拒绝了授权,将无法进入小程序,请授权之后再进入!‘,
showCancel: false,
confirmText: ‘返回‘,
success: function (res) {
// 用户没有授权成功,不需要改变 isHide 的值
if (res.confirm) {
console.log(‘用户点击了“返回”‘);
}
}
});
}
}
})
最后在app.json文件中将login设置为第一个页面即可。
//app.json
{
"pages": [
"pages/login/login",
"pages/home/home"
]
}
以上是关于微信小程序授权登录三种实现方式的主要内容,如果未能解决你的问题,请参考以下文章