目前的框架中token是使用jwt生成,存储到redis控制token时效,而认证是使用UsernamePasswordAuthenticationToken实现的

微信小程序登录授权

  • 需求分析
  • 解决方案
  • 代码改造
    • 新建WxUser类
    • 修改LoginUser类
    • 修改SysLoginService类
    • 修改SysLoginController类
    • 修改SecurityConfig类
  • 总结

需求分析

  1. 微信小程序登录是通过上传一个code到后台,后台根据code调用微信端接口获取到openIdsessionKey(有些场景下不需要),返回token给小程序,小程序后面的请求带上token,后台要解析验证token
  2. 小程序没有用户信息表,如果有,那和后台用的用户表也不是同一个表

解决方案

如果能通过openIdsessionKey伪造一个用户名密码,那代码改动起来会简单很多,只需要给一个类似SysUserWxUserLoginUser里可以多加一个WxUser属性,在SysLoginService扩展一个微信登录方法即可,而且登录方法内也只是做一个假的授权,并不去调用UserDetailsServiceImpl.loadUserByUsername,这样就很简单的实现统一管理token,验证token时候也没有问题

代码改造

新建WxUser类

common模块下新建一个WxUser,和SysUser同级

package com.ruoyi.common.core.domain.entity;import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;import com.ruoyi.common.core.domain.BaseEntity;/*** 微信用户实体* * @author Ricky*/
public class WxUser extends BaseEntity
{private static final long serialVersionUID = 1L;/** 微信唯一标识 */private String openId;/** 微信会话秘钥 */private String sessionKey;public WxUser(String openId, String sessionKey){super();this.openId = openId;this.sessionKey = sessionKey;}public String getOpenId(){return openId;}public void setOpenId(String openId){this.openId = openId;}public String getSessionKey(){return sessionKey;}public void setSessionKey(String sessionKey){this.sessionKey = sessionKey;}@Overridepublic String toString() {return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE).append("openId", getOpenId()).append("sessionKey", getSessionKey()).toString();}
}

修改LoginUser类

LoginUser中加入WxUser属性,生成gettersetter,并且改写getPasswordgetUsername 方法

package com.ruoyi.common.core.domain.model;import java.util.Collection;
import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.entity.WxUser;/*** 登录用户身份权限* * @author ruoyi*/
public class LoginUser implements UserDetails
{private static final long serialVersionUID = 1L;/*** 用户唯一标识*/private String token;/*** 登录时间*/private Long loginTime;/*** 过期时间*/private Long expireTime;/*** 登录IP地址*/private String ipaddr;/*** 登录地点*/private String loginLocation;/*** 浏览器类型*/private String browser;/*** 操作系统*/private String os;/*** 权限列表*/private Set<String> permissions;/*** 用户信息*/private SysUser user;/*** 微信用户信息*/private WxUser wxUser;public String getToken(){return token;}public void setToken(String token){this.token = token;}public LoginUser(){}public LoginUser(SysUser user, Set<String> permissions){this.user = user;this.permissions = permissions;}public LoginUser(WxUser wxUser){this.wxUser = wxUser;}@JsonIgnore@Overridepublic String getPassword(){return user != null ? user.getPassword() : wxUser.getSessionKey();}@Overridepublic String getUsername(){return user != null ? user.getUserName() : wxUser.getOpenId();}/*** 账户是否未过期,过期无法验证*/@JsonIgnore@Overridepublic boolean isAccountNonExpired(){return true;}/*** 指定用户是否解锁,锁定的用户无法进行身份验证* * @return*/@JsonIgnore@Overridepublic boolean isAccountNonLocked(){return true;}/*** 指示是否已过期的用户的凭据(密码),过期的凭据防止认证* * @return*/@JsonIgnore@Overridepublic boolean isCredentialsNonExpired(){return true;}/*** 是否可用 ,禁用的用户不能身份验证* * @return*/@JsonIgnore@Overridepublic boolean isEnabled(){return true;}public Long getLoginTime(){return loginTime;}public void setLoginTime(Long loginTime){this.loginTime = loginTime;}public String getIpaddr(){return ipaddr;}public void setIpaddr(String ipaddr){this.ipaddr = ipaddr;}public String getLoginLocation(){return loginLocation;}public void setLoginLocation(String loginLocation){this.loginLocation = loginLocation;}public String getBrowser(){return browser;}public void setBrowser(String browser){this.browser = browser;}public String getOs(){return os;}public void setOs(String os){this.os = os;}public Long getExpireTime(){return expireTime;}public void setExpireTime(Long expireTime){this.expireTime = expireTime;}public Set<String> getPermissions(){return permissions;}public void setPermissions(Set<String> permissions){this.permissions = permissions;}public SysUser getUser(){return user;}public void setUser(SysUser user){this.user = user;}public WxUser getWxUser(){return wxUser;}public void setWxUser(WxUser wxUser){this.wxUser = wxUser;}@Overridepublic Collection<? extends GrantedAuthority> getAuthorities(){return null;}
}

修改SysLoginService类

SysLoginService加入微信登录处理的方法,这里是假授权,因为没有用户表,如果你有用户表,可以和login方法一样去执行UserDetailsServiceImpl.loadUserByUsername验证用户后授权,至于如何区分是系统用户还是微信用户,可以在调用

authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));

时给用户名上加前缀来处理

/*** 微信登录验证* * @param openId 微信唯一标识* @param sessionKey 微信会话密钥* @return 结果*/public String wxLogin(String openId, String sessionKey){LoginUser loginUser = new LoginUser(new WxUser(openId, sessionKey));UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(openId, sessionKey);authenticationToken.setDetails(loginUser);SecurityContextHolder.getContext().setAuthentication(authenticationToken);// 生成tokenreturn tokenService.createToken(loginUser);}

修改SysLoginController类

SysLoginController中加入微信登录接口(请关注重点:String token = loginService.wxLogin(openId, sessionKey);

 /*** 小程序登录* * @param appId 小程序的appId* @param code 小程序wx.login返回的临时凭证* @return*/@PostMapping("/api/wx/login")public JsonResult login(String appId, String code){String _prefix = "【小程序登录】";_log.info("{}appId:{}, 临时凭证:{}", _prefix, appId, code);try{if (StringUtils.isEmpty(appId)){return JsonResult.error("appId为空");}// 用户登录凭证(有效期五分钟)if (StringUtils.isEmpty(code)){return JsonResult.error("登录凭证不能为空");}WxConfig config = new WxConfigImpl(appId);WxaLogin wxaLogin = new WxaLogin(config);String result = wxaLogin.code2Session(code);_log.info("{}微信根据code获取用户信息结果:{}", _prefix, result);JSONObject code2SessionRes = JSON.parseObject(result);String openId = code2SessionRes.getString("openid");String sessionKey = code2SessionRes.getString("session_key");if (StringUtils.isEmpty(openId)){return JsonResult.error("登录失败,无效的登录凭证");}JSONObject res = new JSONObject();// 生成令牌String token = loginService.wxLogin(openId, sessionKey);res.put(Constants.TOKEN, token);_log.info("{}生成的token:{}", _prefix, token);return JsonResult.success().put("data", res);}catch (Exception e){String msg = "接口异常";if (StringUtils.isNotEmpty(e.getMessage())){msg = e.getMessage();}_log.error("{}接口发生异常:{}", _prefix, e);return JsonResult.error(msg);}}

修改SecurityConfig类

SecurityConfig放行登录接口

// 对于登录login 验证码captchaImage 允许匿名访问
.antMatchers("/login", "/captchaImage", "/api/wx/login").anonymous()

总结

大功告成,使用你的小程序调用接口吧,登录后调用接口需要带上token,携带方式和vue一样,并且已经实现了token续签,如果有其他应用,登录方式还可以按现在这种来,如果可以一张用户表的那都不用改,不是同一张用户表的就可以按这种方式伪造用户名密码,因为code换取openIdsessionKey这个操作一定是安全的操作,而且获取token的前提就是必须成功获取微信的这两个参数,所以不用担心伪造用户名密码欺骗授权对系统安全造成威胁

RuoYi-Vue微信小程序登录授权相关推荐

  1. UNIAPP---实现微信小程序登录授权和手机号授权(uniapp做微信小程序)

    UNIAPP-实现微信小程序登录授权和手机号授权(uniapp做微信小程序) 描述:uniapp开发小程序,先授权用户信息后再出现手机号授权的页面进行手机号授权.完成后返回上一页面并把信息存入后台以及 ...

  2. uni-app微信小程序登录授权

    uni-app微信小程序登录授权 首先是需要用到一个授权按钮来触发获取用户信息授权: 关键在于 open-type 为 getUserInfo , 然后有个@getuserinfo的事件,把获取授权接 ...

  3. 微信小程序登录授权与授权手机号

    文章目录 前言 微信小程序登录授权与授权手机号 一.登录授权 1. 发送 res.code 到后台换取 openId, sessionKey 二.授权手机号 官方规定 因为需要用户主动触发才能发起获取 ...

  4. android微信登录获取微信账号,微信小程序--登录授权,一键获取用户微信手机号并登录...

    一.前言 微信小程序登录流程时序 说明: 小程序调用wx.login() 获取 临时登录凭证code ,并回传到开发者服务器 开发者服务器以code换取 用户唯一标识openid 和 会话密钥sess ...

  5. 使用若依写微信小程序登录授权认证接口

    本文教程,主要介绍一下,如何利用若依框架完成微信小程序的登录授权整个流程. 目录 一.注册微信小程序账号 二.获取AppID和AppSecret 三.微信小程序授权登录流程

  6. 微信小程序登录授权流程

    文章目录 小程序授权登陆流程 1.当用户进入微信小程序时,首先我们先判断用户是否授权过此小程序 2.如果没有授权,我们通过一个按钮来实现授权登录 3.通过bindgetuserinfo事件,我们可以获 ...

  7. 关于微信小程序登录授权

    小程序的API接口文档写的很清晰,现在理一遍思路. 前端通过wx.login()获取code ,把code发给后台,后台返回openid,再获取用户的授权信息(这里先判断是否授权,授权过的就直接进入小 ...

  8. 微信小程序登录授权{errcode:40013,errmsg:invalid appid, hints: [ req_id: qECcC0yFe-_ ]}问题

    登录授权{"errcode":40013,"errmsg":"invalid appid, hints: [ req_id: qECcC0yFe-_ ...

  9. 2021.4月28日24时新版本微信小程序登录授权新方法

    旧版本: Login:function(callback = () =>{}){ let that = this; uni.login({ success:function(loginRes){ ...

最新文章

  1. 【NOI2015】软件包管理器
  2. 关于gradle加快构建速度采用阿里云中央仓库的配置
  3. python上下文管理关键字_详解 Python 中的 with 与 上下文管理器
  4. LeetCode——排序
  5. 唤醒计算机运行此任务_如何停止Windows 8唤醒计算机以运行维护
  6. c语言malloc calloc,C语言内存管理:malloc、calloc、free的实现
  7. 电脑与电脑之间数据是如何传输的(数据封装与解装)
  8. Vue 安装 live-server
  9. 4.线性和卷积——边界问题、解决边界方法和Matlab实战_3
  10. display方法php,ThinkPHP 模板输出 display 方法
  11. JavaSE学习--面向对象
  12. 用计算机绘制函数图像结题报告,《几何画板》在高中数学教学中的应用小课题结题报告...
  13. ThinkPHP3.1.3 { Fast Simple OOP PHP Framework } — [ WE CAN DO IT JUST THINK ] 报错解决办法。...
  14. js对象数组中的某属性值,拼接成字符串形式
  15. UI设计图的标注工具大比拼
  16. 小程序开发平台有哪些?第三方小程序电商开发平台一览
  17. 练手之经典病毒熊猫烧香分析(上)
  18. 15米 GMSLFPDLink传输线束降速问题
  19. UltraEdit15.10的注册码
  20. 如何有效解决电脑桌面开始菜单不见了

热门文章

  1. 【数据结构(郝斌)】03线性结构-栈
  2. pixel2会支持android11吗,Android 11将是最后一次支持Pixel 2系列设备的操作系统更新...
  3. 科普SLAM之位姿图优化建图
  4. java中list中sublist_Java 中 List.subList() 方法的使用陷阱
  5. 终于跑完了马拉松半程了
  6. 餐饮到底怎么做才能提升利润?
  7. postmain报400_Postman测试@RequestBody发送请求时报400错误
  8. MediaCodec硬解流程
  9. vue+elementUI 超长文本省略显示,多余文字鼠标移入时显示全部
  10. 如何成功的做好服务销售