微信小程序之登录模块的实现

 最近在弄小程序登录模块,看了微信官方文档,还找了挺多博客,也不知道那个登录态怎么弄。话说这个session,真的不是很懂。由于openid几乎是不变的(同一个appID下),于是就采用openid来请求数据,然后自己自己研究了一套登陆逻辑,不采用session请求,每次传输请求带一个openid过去操作吧,这样就简单多了。

下图是我的画的登录逻辑流程(有点丑,大家将就看吧):

登录流程:

1、用户第一次登录,先通过wx.getSetting判断小程序是否授权过,此时是没有授权过的,于是进入授权页面调用登录API  wx.login获取到一个code,将此code连同用户信息userInfo一并发到开发者服务器。

2、开发者服务器获取到code之后,连同appID、appSecret通过网络请求微信服务器的code2session接口,获取到openid和session_key。

3、将步骤2的openid拿到数据库中查找是否有该用户数据,没有的话就将信息插入到数据库。我在此把openid、session_key(虽然没用到这个数据,还是先预留着,万一下次需要用到呢)、userInfo整理存入数据库,然后返回一个openid给小程序;如果数据库中有该条信息,则返回一个openid给小程序。

4、小程序获取到服务器返回的openid后,保存到本地缓存中,并放入全局变量,跳转到用户主界面。

5、小程序第二次登录,通过wx.getSetting,可以查到此时是用户授权过的,然后就同步获取缓存中的openid。若获取失败和没有找到openid的话,就再次调用wx.login登录获取openid,之后步骤也和2、3一样;若获取到了openid,就把他放到全局变量中,直接跳转主页面,不再请求开发者服务器。

下面来看看代码吧:

页面就直接贴出来了:

首先是app.js的逻辑,用于获取授权状态判断

// 封装的登陆逻辑
var loginUtil = require("/utils/login.js")

App({
  onLaunch: function () {
    // 获取用户信息
    wx.getSetting({
      success: res => {
        console.log("wx.getSetting判断授权情况",res)
        if (res.authSetting['scope.userInfo']) {
          // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
          wx.getUserInfo({
            success: res => {
              // 将用户信息放入到全局变量
              this.globalData.userInfo = res.userInfo

              // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
              // 所以此处加入 callback 以防止这种情况
              if (this.userInfoReadyCallback) {
                this.userInfoReadyCallback(res)
              }

              // 查看缓存的openid
              // 若没有则重新登录获取;存在的话放入全局变量
              try{
              	let openid = wx.getStorageSync('openid')
              	if(openid != null && openid != ""){
              		console.log("获取到openid、放入globalData中")
              		getApp().globalData.openid = openid

              		// 跳转主页面
              		wx.redirectTo({
              			url: "/main/index/index"
              		})
              	}else{
              		console.log("openid为空,重新登录获取")
              		loginUtil.login()
              	}
              }catch(err){
              	console.log("openid获取异常,重新登录获取")
              	loginUtil.login()
              }

            }
          })
        }

      }
    })
  },
  globalData: {
    userInfo: null,
    openid: null
  }
})

登陆请求我是单独写成一个工具的,通过wx.login获取到code,然后连同userInfo上传到开发者服务器:

function login(){
  console.log("登陆请求获取openid")

  // 登录
  wx.login({
    success: res => {
      console.log("wx.login.code", res)
      
      // 加载进度
      wx.showLoading({
        title: '正在请求数据',
        mask: false
      })
      
      // 发送 res.code 到后台换取 openId, sessionKey,返回openid保存
      wx.request({
        url: 'http://192.168.0.240:8080/MiniProgramServer/login/login',
        data: {
          code: res.code,
          // 将用户信息传到服务器保存
          userInfo: getApp().globalData.userInfo
        },
        header: {
          'content-type': 'application/json' // 默认值
        },
        method: 'POST',
        success(res) {
          console.log("成功", res)
          // 获取到openid后将openid存入本地,同时放到全局变量里
          getApp().globalData.openid = res.data.openid

          wx.setStorage({
            key: 'openid',
            data: res.data.openid
          })

          wx.hideLoading()
          // 然后跳转主页面
          wx.redirectTo({
            url: '/main/index/index'
          })
        },
        fail(res){
          console.log("请求失败")
          wx.hideLoading()
          wx.showToast({
            title: '请求失败',
            icon: 'none', // "success", "loading", "none"
            duration: 1500,
            mask: false
          })
        }
      })
      // request请求结束
    }
  })
};

module.exports = {
  login: login
}

登录界面,主要是添加一个授权的按钮,页面弄得不咋的,见谅啊,页面地址是  global/login/index

<!-- 这是登录页面 global/login/index -->

<image class="img" src="/assets/img/wechat.png" mode="scaleToFill"></image>

<view class="line"></view>

<view class="title">申请获取以下权限</view>

<view class="content">获取你的公开信息(昵称、头像等)</view>

<button class="btn" type="primary" open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo">授权登录</button>

 登录界面样式

 /* 这是登录页面样式 global/login/index */

page{
	width: 100%;
	height:100%;
	display:flex;
	flex-direction:column;
	justify-content: flex-start;
	align-items:center;
}
.img{
	width: 180rpx;
	height: 180rpx;
	background-size: cover;
	margin-top: 300rpx;
}
.line{
	width: 600rpx;
	height: 2rpx;
	background-color: grey;
	margin: 50rpx 0 30rpx 0;
}
.title{
	width: 500rpx;
	height: 70rpx;
	font-size: 35rpx;
}
.content{
	width: 500rpx;
	height: 70rpx;
	font-size: 30rpx;
	color: grey;
}
.btn{
	width: 600rpx;
	height: 70rpx;
	font-size: 30rpx;
	line-height: 70rpx;
	color: #FFF;
	background-color: #2DC100;
	border-radius: 70rpx;
}

登录界面的处理逻辑,主要处理授权:

// 封装的登录模块
let loginUtil = require("../../utils/login.js")

Page({

  /**
   * 页面的初始数据
   */
  data: {
    //判断小程序的API,回调,参数,组件等是否在当前版本可用
    canIUse: wx.canIUse("button.open-type=getUserInfo")
  },

  // 用户授权
  bindGetUserInfo: (res) => {
    console.log("bindGetUserInfo获取权限",res)
    if(res.detail.userInfo){
      // 成功获取到权限,将用户信息存入全局变量
      console.log("bindGetUserInfo获取用户信息成功!")

      getApp().globalData.userInfo = res.detail.userInfo
      
      // 登录
      loginUtil.login()

    }else{
      console.log("bindGetUserInfo获取用户信息失败!")

      wx.showToast({
        title: '您想正常使用,请先授权哦!',
        icon: 'none', // "success", "loading", "none"
        duration: 2000,
        mask: false
      })
    }
  }
})

跳转的主页面,这里我就偷懒了,就写了一行代码(简单点写吧),页面地址  main/index/index

          <text style="color:pink;font-size:40rpx;margin-top:300rpx;">欢迎进入!</text>

 

后台服务器:

服务器端使用的是自己之前写的一个SSM框架的demo,jar包使用的是maven管理,不习惯maven的,我还在demo的libs下面提取出了所需的jar包,大家可以直接创建web工程,将jar包扔进去,再配一下web.xml就行啦。我使用这个这个SSM的demo做服务器的原因有两点,一嘛就是有点懒不想动,二来则是直接通过注解就能将一些对象装换成JSON,挺方便的(其实还是懒啊)。

也是直接扔代码吧:

登陆逻辑:

@ResponseBody
@RequestMapping("/login")
public Object login(@RequestBody Map<String,Object> obj,HttpServletRequest request) {
    // 获取服务器传送过来的数据
    String key = (String) obj.get("code");
    System.err.println(key);
    Map<String,Object> userInfo = (Map<String,Object>)obj.get("userInfo");
    System.out.println(userInfo);
		
    //微信服务器返回的openid和session_key数据
    String res = request(key);
		
    // 解析数据
    String[] wxres = res.replace("\"", "").split(",");
    String openid = wxres[1].split(":")[1].replace("}", "");
    String session_key = wxres[0].split(":")[1];
		
    // 查找数据库是否有该用户,没有则新增,有的话不做处理
    int count = select(openid);
    if(count < 1) {
        //插入数据库
        System.out.println("新用户,插入数据库");
        insert(openid,session_key,userInfo);
    }else {
        System.out.println("老用户,返回openid");
    }
		
    //整理数据,向客户端返回openid
    return "{\"openid\":\""+openid+"\"}";
}

请求code2session接口:

/**
 * 发起网络请求
 * @param code	小程序发过来的code
 * @return	微信服务器返回的数据
 */
public String request(String code) {
	try {
		String str = "https://api.weixin.qq.com/sns/jscode2session?";
		str += "appid=你的小程序的appId";
		str += "&secret=你的小程序的appSecret";
		str += "&js_code="+code+"&grant_type=authorization_code";
		URL url = new URL(str);
			
		//	请求微信服务器
		HttpURLConnection conn = (HttpURLConnection) url.openConnection();
		conn.setReadTimeout(5000);
		conn.setRequestMethod("POST");
			
		if(conn.getResponseCode() == 200) {
		    //用getInputStream()方法获得服务器返回的输入流
		    InputStream in = conn.getInputStream();
			    
		    //	获取服务器返回数据,将数据转成字符串
		    ByteArrayOutputStream swapStream = new ByteArrayOutputStream(); 
		    byte[] buff = new byte[100];
		    int rc = 0; 
		    while ((rc = in.read(buff, 0, 100)) > 0) { 
		    	swapStream.write(buff, 0, rc); 
		    } 
		    byte[] byteData = swapStream.toByteArray();
			    
		    String data = new String(byteData, "UTF-8");
		    System.out.println("成功获取微信服务器返回的数据"+data);

		    in.close();
		    return data;
		}
			
	} catch (MalformedURLException e) {
		e.printStackTrace();
	} catch (IOException e) {
		e.printStackTrace();
	}
		
	return "";
}

插入数据库(使用的是原生jdbc,想简单点但不会写了):

//存入数据库
public static int insert(String openid, String session_key, Map<String,Object> userInfo) {
	String url = "jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&amp;characterEncoding=utf-8";
	String username = "root";
	String passwd = "root";
		
	try {
		//加载驱动
		Class.forName("com.mysql.jdbc.Driver");
		//连接数据库 
		Connection conn = (Connection) DriverManager.getConnection(url, username, passwd);
		//操作数据库
		Statement st = (Statement) conn.createStatement();
		String sql = "insert into wx_login(session_key,openid,nickName,gender,city,province,country,avatarUrl,addTime) values('"
					+session_key+"','"+openid+"','"+userInfo.get("nickName")+"',"+userInfo.get("gender")+",'"+userInfo.get("city")
					+"','"+userInfo.get("province")+"','"+userInfo.get("country")+"','"+userInfo.get("avatarUrl")+"','"
					+new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date())+"')";
			
		int count = st.executeUpdate(sql);
		System.out.println("插入成功返回影响条数:"+count);
			
		if(count > 0) {
			return count;
		}
	} catch (ClassNotFoundException e) {
		e.printStackTrace();
	} catch (SQLException e) {
		e.printStackTrace();
	}
		
	return 0;
}

根据openid查询数据库是否有该用户:

/**
 * 通过openid查找是否有该用户
 * @param openid
 * @return
 */
public static int select(String openid) {
	String url = "jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&amp;characterEncoding=utf-8";
	String username = "root";
	String passwd = "root";
	int count = 0;
		
	try {
		Class.forName("com.mysql.jdbc.Driver");
		//	创建连接
		Connection conn = (Connection) DriverManager.getConnection(url, username, passwd);
		//	操作数据库
		Statement st = (Statement) conn.createStatement();
		String sql = "select count(1) from wx_login where openid = '"+openid+"'";
		ResultSet rs = st.executeQuery(sql);
		while(rs.next()) {
			count = rs.getInt(1);//太久没用原生jdbc了,这里的columnIndex默认是从1开始的
		}
		System.out.println("查找到该用户的数据条数:"+count);
			
		return count;
	}catch(Exception e) {
		e.printStackTrace();
	}
	return 0;
}

数据库脚本如下:

CREATE DATABASE ;

USE `ssm`;

DROP TABLE IF EXISTS `wx_login`;

CREATE TABLE `wx_login` (
  `id` int(10) NOT NULL AUTO_INCREMENT,
  `openid` varchar(255) DEFAULT NULL,
  `session_key` varchar(255) DEFAULT NULL,
  `nickName` varchar(255) DEFAULT NULL,
  `gender` int(1) DEFAULT NULL,
  `country` varchar(255) DEFAULT NULL,
  `province` varchar(255) DEFAULT NULL,
  `city` varchar(255) DEFAULT NULL,
  `avatarUrl` varchar(255) DEFAULT NULL,
  `addTime` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=33 DEFAULT CHARSET=utf8;


insert  into `wx_login`(`id`,`openid`,`session_key`,`nickName`,`gender`,`country`,`province`,`city`,`avatarUrl`,`addTime`) values 

(32,'oyMvT5Lihfbj04qU6EVanyq3g9Fo','d4fYu4h42whrYXy3z/keow==','林哥哥',1,'China','Sichuan','Luzhou','https://wx.qlogo.cn/mmopen/vi_32/X9FT5ck3rC9vZ8vkwfQibzicuhyicYaDMuyzrpAr5ItRKfUXCLmIHIw9vTaJGdWroMMUhUFrKD60rtlicwmNOSbB9w/1322','2019-01-20 04:33:35')

大致就是这样的,有问题可以留言啊,demo上传到Github了,地址:  https://github.com/stevenlin5520/LoginDemo

 

  • 10
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值