微信小程序登录 + 基于token的身份验证

官方时序图如下:

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html

图里其实说的很清楚了,清理下流程:

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就可以做到了。如下:

第一步:

通过wx.login(微信前端--小程序)接口获取code,将code传到后台

注意:

code的来源:是用户打开小程序的时候,随机生成的,是腾讯生成的,每个code只能使用一次,因此,理论上这个code是安全的

package cn.wmyskxz.springboot.model.user;/*** @Author: Yangke* @Date: 2019/3/31 15:52**/
public class WeChatLoginModel {String code;public String getCode() {return code;}public void setCode(String code) {this.code = code;}
}

第二步:

后台通过code访问微信(腾讯)接口,微信(腾讯)接口返回当前登录的信息:session_key及openid

返回的openid是每个用户唯一的,通过这个 可以匹配 微信(腾讯)的用户 跟 我们的用户,就是我们后台通过openid来判断这个人是谁,

UserController.java           微信小程序登录

/*** 微信小程序登录** 登录成功后,将用户身份信息及session_key存入token* @param model* @return*/@ResponseBody@PostMapping("/weChatLogin")public SingleResult<String> weChatLogin(@RequestBody WeChatLoginModel model){/*** 登录日志:* id\ userid\ date\ wx_code\ createTime* create table loginLog (id varchar(50) primary key,userId varchar(50),logindate date,wxcode varchar(100),createtime datetime);*/SingleResult<String> result = new SingleResult<String>();//第三步:调用service.weChatLogin(model):后台检查openid是否存在,返回openid对应的用户WeChatLoginResult<UserAccount> loginResult = service.weChatLogin(model);//第四步:UserAccount user = loginResult.getUser();if(user == null ){result.setCode(0);result.setMessage("登录失败");}else {User u = new User();u.setId(user.getId());u.setPassword(user.getPassword() == null ? user.getWxopenid() : user.getPassword());u.setSessionKey(loginResult.getSession_key());String token = getToken(u);result.setToken(token);result.setCode(1);result.setMessage("登陆成功");}return result;}

其中:就是下面的第三步

//调用service.weChatLogin(model)
WeChatLoginResult<UserAccount> loginResult = service.weChatLogin(model);

 

第三步:

后台检查openid是否存在,

去UserService.java

@Overridepublic WeChatLoginResult<UserAccount> weChatLogin(WeChatLoginModel model){WeChatLoginResult<UserAccount> result = null;try {// code  -> openidString urlFormat = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";String url = String.format(urlFormat, WeChat.appId, WeChat.secret, model.getCode());String json = WeChat.sendGet(url);//将json字符串转化成对象result = JSON.parseObject(json, WeChatLoginResult.class);if(result.getErrcode() == null){// 去数据库 检查 openId 是否存在 不存在就新建用户UserAccount user = userAccount.wechatOpenIdIsExists(result.getOpenid());if(user == null || user.getId() == null){// 不存在,就是第一次登录:新建用户信息user = new UserAccount();user.setId(UUID.randomUUID().toString());user.setWxopenid(result.getOpenid());user.setLasttime(new Date());userAccount.insert(user);}else {//如果存在,就不是第一次登录,更新最后登录时间user.setLasttime(new Date());userAccount.updateByPrimaryKeySelective(user);}result.setUser(user);// 保存登录日志LoginLog log = new LoginLog();log.setId(UUID.randomUUID().toString());log.setCreatetime(new Date());log.setLogindate(new Date());log.setUserid(user.getId());log.setWxcode(model.getCode());loginLog.insert(log);}else {System.out.println(json);}}catch (Exception e){System.out.println(e.getMessage());}return result;}

去数据库中检查openid是否存在:

UserAccountMapper.java
@Select("select * from useraccount where wxOpenId = #{wxOpenId}")
UserAccount wechatOpenIdIsExists(String wxOpenId);

(1)如果不存在:就是该用户的第一次登录,后台数据库新添加一个用户信息

         如果存在:就不是该用户的第一次登录,以前登陆过,就更新后台数据库中该用户的第一次登录时间

  (2)  返回用户信息

第四步:

下发token

//第四步:UserAccount user = loginResult.getUser();if(user == null ){result.setCode(0);result.setMessage("登录失败");}else {User u = new User();u.setId(user.getId());//用户如果是第一次登录,那就是没有密码的,这里用openid当做密码u.setPassword(user.getPassword() == null ? user.getWxopenid() : user.getPassword());u.setSessionKey(loginResult.getSession_key());//利用User.class中的信息生成tokenString token = getToken(u);//下发tokenresult.setToken(token);result.setCode(1);result.setMessage("登陆成功");}return result;}

其中生成token的步骤:BaseController.java

 利用JWT框架生成token

package cn.wmyskxz.springboot.controllers;import cn.wmyskxz.springboot.model.User;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;import java.util.Date;
/*** @Author: Yangke* @Date: 2019/3/28 21:12**/
public abstract class BaseController {protected String getToken(User user) {String token="";token= JWT.create().withKeyId(user.getId()).withIssuer("www.ikertimes.com").withIssuedAt(new Date()).withJWTId("jwt.ikertimes.com").withClaim("session_key", user.getSessionKey()).withAudience(user.getId()).sign(Algorithm.HMAC256(user.getPassword()));return token;}
}

至此,再理一下上面的步骤:

(1)微信小程序通过访问wx.login获得一个code,返回给后台

(2)后台拿着这个code,调用腾讯的接口,获取到openid、seesion-key等信息,openid是用户唯一的

(3)后台拿着openid去数据库中检查,该用户是否是第一次登陆

如果是第一次登陆,那么就新建一个用户--UserAcount;如果不是第一次登陆,就修改该用户的最后登录时间

不管是不是第一次登录,都有了一个用户

(4)然后根据用户的信息利用JWT生成token,下发给微信小程序

第五步

微信小程序收到token后,存起来

第六步

微信小程序请求后台

微信小程序把token放在请求头中

第七步

先介绍一个注解:

Authorize

说明:如果有这个注解,就需要验证token

package cn.wmyskxz.springboot.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @Author: Yangke* @Date: 2019/3/28 19:57*authorize 是判断 是否需要 token**/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Authorize {boolean required() default true;
}

用拦截器,验证token

package cn.wmyskxz.springboot.interceptors;import cn.wmyskxz.springboot.annotation.AllowAnonymous;
import cn.wmyskxz.springboot.annotation.Authorize;
import cn.wmyskxz.springboot.model.User;
import cn.wmyskxz.springboot.service.UserService;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;/*** @Author: Yangke* @Date: 2019/3/28 20:00** 获取token并验证token**/
public class AuthorizationInterceptor implements HandlerInterceptor {@AutowiredUserService userService;//拦截器:请求之前preHandle@Overridepublic boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {// 如果不是映射到方法直接通过if (!(object instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) object;Method method = handlerMethod.getMethod();//检查是否有passtoken注释,有则跳过认证,注意:其中这个注解多余了if (method.isAnnotationPresent(AllowAnonymous.class)) {AllowAnonymous passToken = method.getAnnotation(AllowAnonymous.class);if (passToken.required()) {return true;}}//检查有没有需要用户权限的注解//如果有注解Authorize,就需要验证tokenif (method.isAnnotationPresent(Authorize.class)) {Authorize userLoginToken = method.getAnnotation(Authorize.class);if (userLoginToken.required()) {String token = httpServletRequest.getHeader("authorization");// 从 http 请求头中取出 token// 执行认证if (token == null) {throw new RuntimeException("无token,请重新登录");}// 获取 token 中的 user idString userId;try {// 获取 useriduserId = JWT.decode(token).getKeyId();// 添加request参数,用于传递useridhttpServletRequest.setAttribute("currentUser", userId);// 根据userId 查询用户信息User user = userService.getUserById(userId);if (user == null) {throw new RuntimeException("用户不存在,请重新登录");}try {String session_key = JWT.decode(token).getClaim("session_key").as(String.class);// 添加request参数,用于传递useridhttpServletRequest.setAttribute("sessionKey", session_key);}catch (Exception e){}// 验证 密码JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();try {jwtVerifier.verify(token);} catch (JWTVerificationException e) {throw new RuntimeException("401");}} catch (JWTDecodeException j) {throw new RuntimeException("401");}return true;}}return true;}@Overridepublic void postHandle(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object o, ModelAndView modelAndView) throws Exception {}//拦截器:请求之后:afterCompletion@Overridepublic void afterCompletion(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse,Object o, Exception e) throws Exception {}
}

流程:

1、从http请求头中取出token

String token = httpServletRequest.getHeader("authorization");

2、如果没有token,抛出异常,请用户登录

      如果有token,利用JWT从token中取出userid,添加到request参数

3、根据userid去后台数据库中查询用户是否存在,如果不存在,抛出异常:用户不存在,请重新登录

User user = userService.getUserById(userId);

这个方法:

@Override
public User getUserById(String id) {UserAccount u = userAccount.selectByPrimaryKey(id);User user = new User();user.setId(u.getId());user.setPassword(u.getPassword() == null ? u.getWxopenid() : u.getPassword());user.setUsername(u.getUsername());return  user;
}

4、如果用户存在,再利用JWT从token中取出seesion-key,添加到request参数

String session_key = JWT.decode(token).getClaim("session_key").as(String.class);

5、验证密码:因为我生成token的时候,是存了密码的,这个就是检查一下密码对不对

验证 token里面的密码 跟 你存的 是不是一样

JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
try {jwtVerifier.verify(token);
} catch (JWTVerificationException e) {throw new RuntimeException("401");
}

6、最终token验证成功,返回true,放行

拦截器介绍一下:

preHandle:在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制、权限校验等处理;
postHandle:在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染),有机会修改ModelAndView (这个博主就基本不怎么用了);
afterCompletion:在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面);

第八步:

request里面有userid,后台就可以识别是对哪个用户做处理

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/25809.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Token:用户身份验证的令牌

一、Token是什么 Token&#xff0c;就是用户身份验证的令牌&#xff0c;代表执行某些操作的权利的对象&#xff0c;本质上是服务端生成的一串加密字符串、用于客户端进行请求的“令牌”。 当用户第一次使用账号密码成功登 陆后&#xff0c;服务器就生成一个token和token失效…

调用华为API实现身份证识别

调用华为API实现身份证识别 1、作者介绍2、调用华为API实现身份证识别2.1 算法介绍2.1.1OCR简介2.1.2身份证识别原理2.1.3身份证识别应用场景 2.2 调用华为API流程 3、代码实现3.1安装相关的包3.2代码复现3.3实验结果 1、作者介绍 雷千龙&#xff0c;男&#xff0c;西安工程大…

二十二、身份验证与权限

一、 准备工作 为了讲清楚身份验证与权限&#xff0c;我们再创建一个应用projects,设计模型如下&#xff1a; class Project(models.Model):name models.CharField(项目名称, max_length20, help_text项目名称)desc models.CharField(项目描述, max_length200, help_text项目…

人脸核身基础版 SDK 接入 > 合作方后台上送身份信息

文章目录 一、概述二、实现流程2.1. 获取获取 access_token2.2. 获取 SIGN ticket2.3. 生成签名2.4. 上送身份信息2.5. 获取 NONCE ticket 三、实战3.1. 获取获取 access_token3.2. 获取 SIGN ticket3.3. 生成签名3.4. 上送身份信息3.5. 获取 NONCE ticket 四、开源地址 一、概…

身份证验证接口API(仅需一行代码,公安部实时接口)

身份确认在互联网越来越普及&#xff0c;在二手、电商、贷款、交友、招聘等主流互联网应用中都有明确的刚需&#xff0c;传统的 身份证核验方式是用户上传身份证图片&#xff0c;客服后台人肉审核&#xff0c;但问题在于根本无从确认身份证的真实性&#xff0c;也不能确认该身份…

危!GPT将影响80%工作岗位,挣得越多越危险?OpenAI发布重磅研究

源&#xff5c;新智元 GPT-4发布没几天&#xff0c;OpenAI直接告诉所有人&#xff0c;GPTs是通用技术&#xff0c;80%的美国人的工作受到影响。想要保命&#xff0c;且看这34大「铁饭碗」。 前脚刚推出GPT-4&#xff0c;OpenAI后脚就发布了35页论文官宣&#xff1a; 80%的美国人…

音视频技术开发周刊 | 286

每周一期&#xff0c;纵览音视频技术领域的干货。 新闻投稿&#xff1a;contributelivevideostack.com。 比尔盖茨&#xff1a;AI 时代开启 盖茨谈到AI如何改善人类的不平等现象&#xff0c;并在医疗、教育等方面做出贡献&#xff0c;但也存在风险。 GPT-4 Copilot X震撼来袭&a…

对话 ClickHouse CTO Alexey:目光不仅限于成为最快的数据库 | 近匠

作为世界上最快的 OLAP 列式数据库之一&#xff0c;ClickHouse 能在毫秒级的时间内处理数百亿行的数据。ClickHouse 公司在官网上&#xff0c;也是简单扼要地介绍了自己的数据库&#xff1a;“Fast”。 ClickHouse 的灵魂人物 AlexeybMilovidov&#xff0c;则是一位将“慢”践行…

马斯克放话:没有我就没有 OpenAI,连名字都是我起的!

整理 | 郑丽媛 出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09; 在 ChatGPT、GPT- 4 的爆火下&#xff0c;近来 OpenAI 这个名字已逐渐成为科技圈的“高频热词”&#xff0c;其创立初期与马斯克之间的“恩怨”也被时常提及。 有人说自从马斯克走后&#xff0c;Open…

阿里云版Chat-gpt申请内测

不允许你还不知道阿里云的chat-gpt&#xff0c;快去申请 -- 内测申请地址&#xff1a;通义千问

C++图像处理 -- 图像合成

阅读提示&#xff1a; 《C图像处理》系列以代码清晰&#xff0c;可读性为主&#xff0c;全部使用C代码。 《Delphi图像处理》系列以效率为侧重点&#xff0c;一般代码为PASCAL&#xff0c;核心代码采用BASM。 尽可能保持二者内容一致&#xff0c;可相互对照。 本文代码必须包括…

图像合成与图像融合

这一次我来给大家介绍一下图像合成与融合。 我们经常看到一些很奇妙的PS技术&#xff0c;例如下面这张&#xff0c;它把1928年的一位叫做Frankie Yale的黑帮老大被杀时的照片&#xff0c;与现在这栋房子的照片无缝融合在一起&#xff1a; 还有这张&#xff0c;将1945年柏林街道…

Chrome安装油猴插件详细教程

Chrome安装油猴插件详细教程 一、油猴安装方法 方法一&#xff1a;Google官方商店安装&#xff08;推荐&#xff0c;需要科学上网&#xff09; 方法二&#xff1a;本地安装&#xff08;无需科学上网&#xff0c;不会科学上网的适用&#xff09; 二、安装油猴插件 方法一&am…

Tampermonkey 油猴脚本,chrome插件

tampermonkey脚本是一款在谷歌浏览器上经常使用到的浏览器脚本插件&#xff0c;油猴脚本不仅为用户提供了大量的免费脚本插件外&#xff0c;而且还可以帮助你对这些脚本插件进行统一管理&#xff0c;当有最新版本的脚本推出的时候&#xff0c;它会帮助你进行自动更新。当然&…

手机上使用油猴插件 Tampermonkey

油猴 即 Tampermonkey中文名俗称油猴&#xff0c;是一款浏览器上的扩展&#xff0c;用户可以通过Tampermonkey添加和使用脚本&#xff0c;而脚本是一种可以修改网页JavaScript的程序。 在PC端&#xff0c;可以通过 Chrome浏览器的扩展程序&#xff0c;再结合 脚本 可以实现各种…

Tampermonkey油猴插件安装使用

Tampermonkey油猴插件安装使用 Tampermonkey油猴插件——安装与使用教程 Tampermonkey的crx文件&#xff0c;将下载下来的压缩包解压出来&#xff0c;其中类型为CRX文件 就是接下来需要用到的安装文件 打开浏览器设置&#xff0c;打开扩展程序页面&#xff0c;或者直接搜索Chr…

关于油猴(Tampermonkey)

油猴Tampermonkey 是一款免费的浏览器扩展和最为流行的用户脚本管理器&#xff0c;它适用于多款常见的浏览器。 前言 那么&#xff0c;油猴具体能干啥&#xff1f; 它可以让我们使用浏览器时更加便捷。 比如说&#xff0c;对于一些网页限制的解除&#xff0c;某度盘文件直接…

Tampermonkey油猴插件——安装与使用教程

安装步骤&#xff1a; Tampermonkey 是一款免费的浏览器扩展和最为流行的用户脚本管理器&#xff0c;它适用于 Chrome, Microsoft Edge, Safari, Opera Next, 和 Firefox。 油猴插件下载网址&#xff1a;Tampermonkey • Home Beta是测试版&#xff1b; Stable是稳定版&am…

安装油猴(Tampermonkey)插件,让你的浏览器更强大

插件是什么 插件及扩展程序&#xff0c;目前大多数软件及程序都提供了安装插件的功能&#xff08;edge&#xff0c;chrome&#xff0c;vscode&#xff0c;pycharm&#xff0c;office等&#xff09;&#xff0c;游戏外挂也是一种插件&#xff0c;这也是使程序功能强大的手段&…

油猴脚本(Tampermonkey)的简介

油猴脚本的使用 什么是油猴脚本 「油猴」可以通过安装各类脚本对网站进行定制。当然伟大的脚本面向的是所有上网者&#xff0c;所以借由各位大神的脚本我们能实现更多更强大的功能&#xff0c;例如&#xff1a; 直接下载百度网盘文件(全速)重新定制繁杂的微博页面去掉视频播放…