微信小程序授权登录三种实现方式

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"
	]
}

以上是关于微信小程序授权登录三种实现方式的主要内容,如果未能解决你的问题,请参考以下文章

微信小程序怎么授权登录

微信小程序用户授权

微信小程序中用户拒绝授权的处理方式

微信小程序入门之授权登录

微信小程序用户授权

微信小程序用户授权登录