博客
关于我
RuoYi-Vue微信小程序登录授权
阅读量:603 次
发布时间:2019-03-11

本文共 8232 字,大约阅读时间需要 27 分钟。

微信小程序登录授权

需求分析

微信小程序登录通常通过在后台上传一个 code,后台利用 code 调用微信端接口获取 openIdsessionKey。在某些场景下,sessionKey 可能不需要。接着,后台将 token 返回给小程序,后续请求中小程序需携带 token,后台需解析验证 token

值得注意的是,小程序通常没有用户信息表,这与后台的用户表并不完全一致。


解决方案

为简化代码改动,可以通过 openIdsessionKey 伪造一个用户名密码。这样可以在不修改用户表的情况下,直接在 LoginUser 类中添加 WxUser 属性。在 SysLoginService 类中扩展一个微信登录方法,该方法仅进行假授权,避免调用 UserDetailsServiceImpl.loadUserByUsername。这样可以实现对 token 的统一管理和验证。


代码改造

新建 WxUser

common 模块下新建 WxUser 类,与 SysUser 同级。

package com.ruoyi.common.core.domain.entity;
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;
}
@Override
public 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;
public class LoginUser implements UserDetails {
private static final long serialVersionUID = 1L;
private String token;
private Long loginTime;
private Long expireTime;
private String ipaddr;
private String loginLocation;
private String browser;
private String os;
private Set
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
permissions) {
this.user = user;
this.permissions = permissions;
}
public LoginUser(WxUser wxUser) {
this.wxUser = wxUser;
}
@JsonIgnore
@Override
public String getPassword() {
return user != null ? user.getPassword() : wxUser.getSessionKey();
}
@Override
public String getUsername() {
return user != null ? user.getUserName() : wxUser.getOpenId();
}
@JsonIgnore
@Override
public boolean isAccountNonExpired() {
return true;
}
@JsonIgnore
@Override
public boolean isAccountNonLocked() {
return true;
}
@JsonIgnore
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@JsonIgnore
@Override
public 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
getPermissions() {
return permissions;
}
public void setPermissions(Set
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;
}
@Override
public Collection
getAuthorities() {
return null;
}
}
修改 SysLoginService

SysLoginService 类中增加微信登录处理方法,进行假授权操作。

package com.ruoyi.sys.login.service;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.security.service.SecurityContextHolder;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.stereotype.service;
@Service
public class SysLoginService {
private static final String Wx_PREFIX = "WX_";
public String wxLogin(String openId, String sessionKey) {
LoginUser loginUser = new LoginUser(new WxUser(openId, sessionKey));
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
openId, sessionKey, loginUser
);
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
return tokenService.createToken(loginUser);
}
}
修改 SysLoginController

SysLoginController 类中增加微信登录接口。

package com.ruoyi.sys.login.controller;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.security.service.SecurityContextHolder;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.stereotype.controller;
import java.util.HashMap;
import java.util.Map;
@Controller
public class SysLoginController {
private static final String LOGIN_PATH = "/api/wx/login";
@PostMapping(LOGIN_PATH)
public ResponseEntity
login(String appId, String code) {
String _prefix = "【小程序登录】";
if (StringUtils.isBlank(appId)) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST, null, _prefix + "appId为空");
}
if (StringUtils.isBlank(code)) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST, null, _prefix + "登录凭证不能为空");
}
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.isBlank(openId)) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST, null, _prefix + "登录失败,无效的登录凭证");
}
Map
response = new HashMap<>();
response.put(Constants.TOKEN, loginService.wxLogin(openId, sessionKey));
_log.info("{}生成的token:{}", _prefix, response.get(Constants.TOKEN));
return new ResponseEntity<>(response, HttpStatus.OK);
}
}
修改 SecurityConfig

SecurityConfig 类中放行登录接口。

package com.ruoyi.security.config;
import org.springframework.security.config.annotation.builders.WebSecurity;
import org.springframework.security.config.annotation.web.builders.HttpInterceptor;
import org.springframework.security.config.annotation.web.config.WebMvcConfigurer;
@Configuration
public class SecurityConfig extends WebMvcConfigurer {
@Override
public void addInterceptors(WebSecurity webSecurity) {
webSecurity
.antMatchers("/login", "/captchaImage", "/api/wx/login")
.anonymous()
;
}
}

总结

通过以上改造,可以实现微信小程序的登录授权。小程序登录时,后台接收 code,调用微信接口获取 openIdsessionKey,然后调用 wxLogin 方法生成 token。小程序后续请求需携带 token,后台通过 LoginUser 类验证 token。这一方案无需修改用户表,且通过伪造用户名密码的方式实现了统一管理,保证了系统安全性。

转载地址:http://nkatz.baihongyu.com/

你可能感兴趣的文章
Objective-C实现MATLAB中Filter函数功能(附完整源码)
查看>>
Objective-C实现matrix chainorder矩阵链顺序算法(附完整源码)
查看>>
Objective-C实现matrix exponentiation矩阵求幂算法(附完整源码)
查看>>
Objective-C实现MatrixMultiplication矩阵乘法算法 (附完整源码)
查看>>
Objective-C实现max non adjacent sum最大非相邻和算法(附完整源码)
查看>>
Objective-C实现max subarray sum最大子数组和算法(附完整源码)
查看>>
Objective-C实现max sum sliding window最大和滑动窗口算法(附完整源码)
查看>>
Objective-C实现MaxHeap最大堆算法(附完整源码)
查看>>
Objective-C实现MaximumSubarray最大子阵列(Brute Force蛮力解决方案)算法(附完整源码)
查看>>
Objective-C实现MaximumSubarray最大子阵列(动态规划解决方案)算法(附完整源码)
查看>>
Objective-C实现maxpooling计算(附完整源码)
查看>>
Objective-C实现max_difference_pair最大差异对算法(附完整源码)
查看>>
Objective-C实现max_heap最大堆算法(附完整源码)
查看>>
Objective-C实现MD5 (附完整源码)
查看>>
Objective-C实现md5算法(附完整源码)
查看>>
Objective-C实现MeanSquareError均方误差算法 (附完整源码)
查看>>
Objective-C实现median filter中值滤波器算法(附完整源码)
查看>>
Objective-C实现memcmp函数功能(附完整源码)
查看>>
Objective-C实现memcpy函数功能(附完整源码)
查看>>
Objective-C实现memoization优化技术算法(附完整源码)
查看>>