微信小程序:授权登录 + 基于token的身份验证详解
微信小程序授权、服务器保存信息到数据库
通过 wx.login() 获取到用户登录态之后,需要维护登录态。开发者要注意不应该直接把 session_key、openid 等字段作为用户的标识或者 session 的标识,而应该自己派发一个 session 登录状态 (请参考登录时序图)。对于开发者自己生成的 session,应该保证其安全性且不应该设置较长的过期时间。session 派发到小程序客户端之后,可将其存储在 storage ,用于后续通信使用。
微信小程序授权登录与用户信息保存流程
图里其实说的很清楚了,清理下流程:
1.前端调用wx.login()获取code值
2.前端通过调用wx.getUserInfo获取iv、rawData、signature、encryptedData等加密数据,传递给后端
3.服务器通过code请求api换回session_key和openid
4.服务器通过前端给的rawData 加获取的session_key使用sha1加密,计算出signature1
5.比对前端传的signature和自己算出来的signature1是否一致(防止数据不一致)
6.用AES算法解密encryptedData里的敏感数据
7.拿着敏感数据后做自己的逻辑
8.通知前端登陆成功
这里只是想拿到用户的openid,则直接1,3就可以做到了。
1
第一步:
通过wx.login(微信前端--小程序)接口获取code,将code传到后台
注意:
code的来源:是用户打开小程序的时候,随机生成的,是腾讯生成的,每个code只能使用一次,因此,理论上这个code是安全的
2
第二步:
后台通过code访问微信(腾讯)接口,微信(腾讯)接口返回当前登录的信息:session_key及openid。
返回的openid是每个用户唯一的,通过这个 可以匹配 微信(腾讯)的用户 跟 我们的用户,就是我们后台通过openid来判断这个人是谁,
UserController.java 微信小程序登录
其中:就是下面的第三步
//调用service.weChatLogin(model) WeChatLoginResult<UserAccount> loginResult = service.weChatLogin(model);
3
第三步:
后台检查openid是否存在,
去UserService.java
去数据库中检查openid是否存在:
UserAccountMapper.java
- 如果不存在:就是该用户的第一次登录,后台数据库新添加一个用户信息
- 如果存在:就不是该用户的第一次登录,以前登陆过,就更新后台数据库中该用户的第一次登录时间
- 返回用户信息
4
第四步:
下发token
其中生成token的步骤:BaseController.java
利用JWT框架生成token
至此,再理一下上面的步骤:
- 微信小程序通过访问wx.login获得一个code,返回给后台
- 后台拿着这个code,调用腾讯的接口,获取到openid、seesion-key等信息,openid是用户唯一的
- 后台拿着openid去数据库中检查,该用户是否是第一次登陆。如果是第一次登陆,那么就新建一个用户--UserAcount;如果不是第一次登陆,就修改该用户的最后登录时间不管是不是第一次登录,都有了一个用户
- 然后根据用户的信息利用JWT生成token,下发给微信小程序
5
第五步
微信小程序收到token后,存起来
6
第六步
微信小程序请求后台
微信小程序把token放在请求头中
7
第七步
先介绍一个注解:
Authorize
说明:如果有这个注解,就需要验证token
用拦截器,验证token
流程:
1、从http请求头中取出token
String token = httpServletRequest.getHeader("authorization");
2、如果没有token,抛出异常,请用户登录。如果有token,利用JWT从token中取出userid,添加到request参数
3、根据userid去后台数据库中查询用户是否存在,如果不存在,抛出异常:用户不存在,请重新登录
User user = userService.getUserById(userId);
这个方法:
4、如果用户存在,再利用JWT从token中取出seesion-key,添加到request参数
Stringsession_key=JWT.decode(token).getClaim("session_key").as(String.class);
拦截器介绍一下:
- preHandle:在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;
- postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView;
- afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);
8
第八步:
request里面有userid,后台就可以识别是对哪个用户做处理
总结
微信小程序授权登录和信息保存,看起来是有点麻烦 ,但是这个流程是很清晰的 ,大家只要理解了逻辑控制流程 ,就能很好的完成开发。
- SQL 行列转换简单示例
- SQLSERVER 2012计算上一条,下一条数据的函数
- 使用命名管道实现进程间通信
- 获取SqlServer存储过程定义的3种方法
- 【自然框架】开源社区活动,会员注册的第一份代码!
- CentOS 7 安装Mono 和 MonoDevelop
- 【自然框架】注册会员活动——第一份代码的修改建议(第一版)
- 【视频】自然框架之分页控件的使用方法(一) PostBack方式的一般分页方式
- Java中的Socket编程学习
- 【视频】自然框架之分页控件的使用方法(二) 下载、DLL说明和web.config的设置
- Jsp开发中遇到的中文乱码问题及解决方法
- 开发中最常见的Java字符串问题总结
- .net异步性能测试(包括ASP.NET MVC WebAPI异步方法)
- Java 8的函数式编程学习
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- PHP 之文件上传类封装
- 多线程循环打印数组 -- Java笔记
- C++核心准则SF.4:在其他声明之前include .h文件
- PHP 之变量
- 在网页中常用到的几种居中方法
- 秋招面经三(作业帮、新浪、阿里云)
- 初识HTML
- iOS 点击按钮复制文本
- AntUI滑块Sliders
- AntUI卡片Cards
- AntUI常规Forms表单
- 二叉树:看看这些树的最大深度
- C++核心准则SF.5: .cpp文件必须包含定义它接口的.h文件
- C++核心准则SF.6:(只)为转换,基础库或在局部作用域内部使用using namspace指令
- C++核心准则SF.7:不要在头文件中的全局作用域中使用using namespace指令