本文将详细的介绍微信小程序的登录流程以及在ssm框架下如何实现小程序用户登录(日后补上过滤器的配置。。。)

登录流程概要

主要的登录流程可以参考官方提供的一张流程图:

1.微信前台页面:

在微信版本更新之后,提高了安全机制,我们需要为用户提供一个授权按钮,让用户同意授权,页面中的button必须包含 open-type="getUserInfo"这个属性:

一般授权页面如下:

    <form bindsubmit="bindSave">
<wxc-button type="success" size='large' btn-style='margin-top:10%;' open-type="getUserInfo" bindgetuserinfo="bindGetUserInfo"
value="同意授权登录"></wxc-button>
<view style='width:100%;padding-left:30rpx;font-size: 30rpx;margin-top:50rpx;'>1. 同意当前小程序获取我的微信头像;</view>
<view style='width:100%;padding-left:30rpx;font-size: 30rpx;margin-top:20rpx;'>2. 同意当前小程序获取我的微信昵称等其他信息;</view>
<wxc-button type="danger" size='large' btn-style='margin-top:30rpx;' bindtap='rejectLogin' value="拒绝授权"></wxc-button>
</form>

2.登录前台实现

当用户登录时,我们先去判断小程序缓存中用户的token存不存在:

  -----如果存在,将token传到后台去检查redis缓存中的用户信息是否失效:

    -----如果失效,前台将用户信息删除,重新调用登录接口。

    -----未失效,返回原页面,后台更新缓存失效时间。

  -----如果不存在,前台调用官方提供的小程序登录接口:wx.login(),获得它返回的code:

    -----code获取成功,前台调用wx.getSetting()获取授权以及用户的授权配置:

      -----用户授权成功,前台调用wx.getUserInfo()获取encryptedData(密文)和 iv(偏移向量

        ------以上都获取成功后,我们将codeencryptedData和iv全部传到后台。

         (code用来换取openid和sessionKey,encryptedData和iv用来获得并解密用户信息)

          -----如果后台获取用户信息成功,返回token和用户信息到前台,前台小程序在缓存中更新token和用户信息。

           登录成功。

     -----------------------任意一个步骤失败,提示用户无法登录。

微信小程序前台登录函数如下(下面这个函数较长,可以拆分,看的更清晰):

  login: function () {
let that = this;
let token = wx.getStorageSync("token");
console.log("进入页面登录开始取token"+token);
if (token) {
console.log("如果token存在");
wx.request({
url: urlMangerData.api0_check_token,///wxma/user/check-token
data: {
token: token
},
success: function (res) {
console.log("前台token存在,校验token后返回值"+JSON.stringify(res));
//如果后台缓存已经不在了
if (!res.data.success) {
console.log("如果后台缓存已经失效了,小程序清空token和userinfo和openid");
wx.removeStorageSync("token");
wx.removeStorageSync("userInfo");
that.login();
} else {
console.log("后台缓存中的信息也存在,直接返回");
// 回到原来的地方
wx.navigateBack();
}
}
});
}
console.log("如果token不存在");
//小程序登录,
wx.login({
success: function (res) {
if(res.code){
wx.getSetting({
success: res2 => {
if (res2.authSetting["scope.userInfo"]) {
wx.getUserInfo({
success:datas=>{
console.log("开始获取code和一些加密过的用户信息" + res.code);
console.log("datas.encryptedData" + datas.encryptedData);
wx.request({
url: urlMangerData.api0_loginAuth,
data: {
code: res.code,
encryptedData: datas.encryptedData,
iv: datas.iv
},
header: {
'content-type': 'application/json'
},
success: function (res) {
console.log("后台成功后得到返回值" + res.data.code);
if(res.data.code != 0) {
console.log("后台登录错误")
wx.hideLoading();
wx.showModal({
title: "提示",
content: "无法登录,请重试",
showCancel: false
});
return;
}
console.log("存储用户信息token" + res.data.token);
console.log("存储用户信息userInfo" + JSON.stringify(res.data.wxMaUserInfoExtends));
wx.setStorageSync("token", res.data.token);
wx.setStorageSync("userInfo", res.data.wxMaUserInfoExtends);
wx.setStorageSync("user_id", res.data.wxMaUserInfoExtends.user_id);
wx.navigateBack();
}
});//request
}
})//getuserinfo
}
}
})//getsetting
}
}//success
})
}

再贴一下第一次登录时,控制台打印信息:

3.登录后台实现

当用户登录时,先检查前台传来的token在redis中是否存在:存在即更新redis中用户信息的失效时间,不存在则返回登录失效信息。

前台获得失效信息后,正常去调用获取用户信息接口,传入code,encryptedData和iv:

controller层:

    @RequestMapping(value = "/loginAuth", method = RequestMethod.GET, produces = "application/json; charset=utf-8")
public String loginAuth(String code,String encryptedData,String iv) throws WxErrorException {
if (StringUtils.isBlank(code)) {
return "empty jscode";
}
//处理登录授权 获得openid和sessionkey,生成userid 并将session存到缓存中
WxMaAuthResult result =
weixinMaService.dealLoginAuth(code,encryptedData,iv);
return JsonUtils.objectToJson(result); }

service层:

    /**
* 处理小程序登录授权
*/
@Override
public WxMaAuthResult dealLoginAuth(String code,String data,String iv) {
WxMaJscode2SessionResult session =new WxMaJscode2SessionResult();
//调微信官方接口获得sesssion_key openid存到 session对象里
try {
       //code换取sessionKey
session = wxMaService.getUserService().getSessionInfo(code);
this.logger.info(session.getSessionKey());
this.logger.info(session.getOpenid()); } catch (WxErrorException e) {
this.logger.error("获得sessionKey失败", e);
}
WxMaAuthResult wxMaAuthResult = new WxMaAuthResult();
     //该类用来存储用户信息
WxMaUserInfoExtends wxMaUserInfoExtends = new WxMaUserInfoExtends();
WxMaUserInfo wxMaUserInfo = new WxMaUserInfo();
//暂时写死失效时间
int expire=3600;
String sessionKey = session.getSessionKey();
String rawData = StringEscapeUtils.unescapeHtml4(data);
// 解密用户信息
try {
       //sessionkey data iv 解密用户信息
wxMaUserInfo = this.wxMaService.getUserService().getUserInfo(sessionKey, data, iv);
} catch (Exception e) {
// TODO Auto-generated catch block
logger.error("解密用户信息失败");
e.printStackTrace();
}
BeanUtils.copyProperties(wxMaUserInfo, wxMaUserInfoExtends);
String third_session = Base64UUID.ramdomID();
wxMaAuthResult.setToken(third_session);
String user_id = Base64UUID.ramdomID();
wxMaUserInfoExtends.setUser_id(user_id);
//通过openid获取或新增用户信息
if(wxMaUserMapper.countAny(session.getOpenid())>0 ){
//存在 数据库更新
wxMaUserMapper.addWxMaUser(wxMaUserInfoExtends);
//这里是将用户信息存到redis
wxMaAuthSessionStorage.addWxMaSession(expire,third_session,wxMaUserInfoExtends);
//不把openId传到前台
wxMaUserInfo.setOpenId("");
wxMaAuthResult.setIsReg(true);
wxMaAuthResult.setSuccess(true);
wxMaAuthResult.setWxMaUserInfoExtends(wxMaUserInfoExtends);
} else {
//不存在 数据库保存信息
wxMaUserMapper.addWxMaUser(wxMaUserInfoExtends);
wxMaAuthSessionStorage.addWxMaSession(expire,third_session,wxMaUserInfoExtends);
wxMaUserInfo.setOpenId("");
wxMaAuthResult.setSuccess(true);
wxMaAuthResult.setIsReg(false);
wxMaAuthResult.setWxMaUserInfoExtends(wxMaUserInfoExtends);
}
return wxMaAuthResult;
}

实体类:

public class WxMaUserInfoExtends{

    private String user_id;

      private String openId;
private String nickName;
private String gender;
private String language;
private String city;
private String province;
private String country;
private String avatarUrl;
private String unionId;
private Date create_date; ...
}
public class WxMaAuthResult extends WxMaJscode2SessionResult{

    private String code;

    private String token;

    private int expiresIn = -1;

    Boolean isReg = false; //是否保存过用户信息

    private boolean success;

    private WxMaUserInfoExtends wxMaUserInfoExtends;

    ...

}

注:还有一些是api提供的。

redis存取方法:

   @Autowired
private JedisClient jedisClient;
/**
* 存放token和用户信息
*/
//内部事务回滚不影响外部事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void addWxMaSession(int expire,String token,WxMaUserInfoExtends wxMaUserInfoExtends) {
String json = JsonUtils.objectToJson(wxMaUserInfoExtends);
try {
jedisClient.set(token, json);
jedisClient.expire(token, expire);
} catch (Exception e) {
e.printStackTrace();
}
}
  //从缓存中获取用户信息
@Override
public WxMaAuthResult getWxMaSessionBy3rdKey(String token) {
WxMaAuthResult wxMaAuthResult = new WxMaAuthResult();
try {
String json = jedisClient.get(token);
if(json == null) {
wxMaAuthResult.setSuccess(false);
return wxMaAuthResult;
}
wxMaAuthResult.setSuccess(true);
WxMaUserInfoExtends wxMaUserInfoExtends= JsonUtils.jsonToPojo(json, WxMaUserInfoExtends.class);
wxMaAuthResult.setWxMaUserInfoExtends(wxMaUserInfoExtends);
return wxMaAuthResult;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
wxMaAuthResult.setSuccess(false);
return wxMaAuthResult;
} }

注:这里使用了binarywang(一个github上的开源开发者)提供的API,该API封装了调用微信小程序官方接口的方法,并提供了一些小程序登录信息和用户信息的实体类,非常方便,有需要可以下载下来用:https://github.com/binarywang

后台大体流程:

1.我们用code去换取sessionKey和openId,再通过sessionKey,encryptedData和iv来解密用户信息(解密过程已经封装好了)。

2.生成一个随机字符串,将它作为key(token),用户信息作为value存入redis缓存并设置或更新失效时间。

3.返回登录结果和用户信息到前台。

spring mvc+redis实现微信小程序登录的更多相关文章

  1. Spring Security 整合 微信小程序登录的思路探讨

    1. 前言 原本打算把Spring Security中OAuth 2.0的机制讲完后,用小程序登录来实战一下,发现小程序登录流程和Spring Security中OAuth 2.0登录的流程有点不一样 ...

  2. 基于Shiro,JWT实现微信小程序登录完整例子

    小程序官方流程图如下,官方地址 : https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html ...

  3. 微信小程序登录JAVA后台

    代码地址如下:http://www.demodashi.com/demo/12736.html 登录流程时序登录流程时序 具体的登录说明查看 小程序官方API 项目的结构图: springboot项目 ...

  4. Flask与微信小程序登录(后端)

    开发微信小程序时,接入小程序的授权登录可以快速实现用户注册登录的步骤,是快速建立用户体系的重要一步.这篇文章将介绍 python + flask + 微信小程序实现用户快速注册登录方案(本文主要进行后 ...

  5. 微信小程序登录方案

    微信小程序登录方案 登录程序 app.js 调用wx.login获取code 将code作为参数请求自己业务登录接口获取session_key 存储session_key 如果有回调执行回调 App( ...

  6. 微信小程序登录,获取code,获取openid,获取session_key

    微信小程序登录 wx.login(Object object) 调用接口获取登录凭证(code).通过凭证进而换取用户登录态信息,包括用户的唯一标识(openid)及本次登录的会话密钥(session ...

  7. 微信小程序登录对接Django后端实现JWT方式验证登录

    先上效果图 点击授权按钮后可以显示部分资料和头像,点击修改资料可以修改部分资料. 流程 1.使用微信小程序登录和获取用户信息Api接口 2.把Api获取的用户资料和code发送给django后端 3. ...

  8. 全栈项目|小书架|微信小程序-登录及token鉴权

    小程序登录 之前也写过微信小程序登录的相关文章: 微信小程序~新版授权用户登录例子 微信小程序-携带Token无感知登录的网络请求方案 微信小程序开通云开发并利用云函数获取Openid 也可以通过官方 ...

  9. Taro -- 微信小程序登录

    Taro微信小程序登录 1.调用Taro.login()获取登录凭证code: 2.调用Taro.request()将code传到服务器: 3.服务器端调用微信登录校验接口(appid+appsecr ...

随机推荐

  1. andorid下从相册选取/拍照选取一张相片并剪切

    http://www.2cto.com/kf/201401/270144.html 在Android编程中,从相册选取或是拍照选取一张照片然后对其进行剪切的需求非常的多 之前的一篇文章只说到如何从相册 ...

  2. Learn flask in the hard way:配置环境的安装

    开发用的是win10的环境. 首先确保安装了python环境,个人比较适应python2.x的代码方式,所以安装的是python2.7.10. 另外IDE还是我最喜欢的pycharm. 然后开始安装F ...

  3. 如何使用php生成唯一ID的4种方法

    php生成唯一ID的应用场景非常普遍,如临时缓存文件名称,临时变量,临时安全码等,uniqid()函数基于以微秒计的当前时间,生成一个唯一的 ID.由于生成唯一ID与微秒时间关联,因此ID的唯一性非常 ...

  4. Servlet 单例多线程【转】

    源地址:Servlet 单例多线程 Servlet如何处理多个请求访问?Servlet容器默认是采用单实例多线程的方式处理多个请求的:1.当web服务器启动的时候(或客户端发送请求到服务器时),Ser ...

  5. printf输出格式介绍(转)

    格式代码 A ABC ABCDEFGH %S A ABC ABCDEFGH %5S ####A ##ABC ABCDEFGH %.5S A ABC ABCDE %5.5S ####A ##ABC AB ...

  6. 云计算一:VMware workstation的安装和使用教程

    VMware workstation的安装和使用教程 一.VMware 安装 1.从网上找到VMware的安装包以及要安装的映像文件,下载到本地,然后备份一份存储到百度云盘. 链接:http://pa ...

  7. [已解决]pycharm的debugger模式不显示调试结果?

    由于朋友遇到这个问题,特意上网搜索了很久,没有相关答案,后来自己尝试与能正常显示的做设置对比,才找到控制开关,在此做个记录,分享给遇到这个问题的朋友. 问题如下图: 解决办法: 左上角File--&g ...

  8. 设计模式之模板方法(Template Method)

    在整理模板方法之前,先来说点废话吧.除了记录学习总结,也来记录一下生活吧. 我们公司的老板在北京,老板也会因为项目来公司,不过不是天天来.公司有个同事,只要老板不在就天天迟到,而且一天比一天晚,经常来 ...

  9. Unity3D学习(六):《Unity Shader入门精要》——Unity的基础光照

    前言 光学中,我们是用辐射度来量化光. 光照按照不同的散射方向分为:漫反射(diffuse)和高光反射(specular).高光反射描述物体是如何反射光线的,漫反射则表示有多少光线会被折射.吸收和散射 ...

  10. 【手记】ASP.NET提示“未能创建类型”处理

    我是在本机启动IIS Express调试一个ashx(一般处理程序)时遇到这个报错,网上的说法普遍有这么几种: 把bbb.ashx中的Class="aaa.bbb" 改为Class ...