赞
踩
微信小程序登录流程
前端先调用wx.login()
接口获取code,再把code发个后端
login() {
wx.login({
success: (res) => {
wx.request({
url:"/login",
method:"POST",
data:{
code:res
},
dataType:'json'
})
},
})
}
后端采用是SpringSecurity+jwt+redis
@RestController public class LoginController { @Autowired LoginService loginService; @PostMapping("/login") public R<Map<String,Object>> login(@RequestBody Map<String, String> params) { String code = params.get("code"); if (StringUtils.isBlank(code)) { throw new ValidateException("code不能为空"); } return loginService.login(code); } }
后端接收code之后再发送http到微信官方获得openid
@Component @ConfigurationProperties(prefix = "wx") @Data public class WxLogin { private String appid; private String secret; private String grant_type; private String wxurl; public String getOpenId(String code) throws IOException, URISyntaxException { URL url = new URL(wxurl); URI uri = new URIBuilder().setScheme(url.getProtocol()) .setHost(url.getHost()) .setPort(url.getPort()) .setPath(url.getPath()) .setParameters( new BasicNameValuePair("appid",appid), new BasicNameValuePair("secret",secret), new BasicNameValuePair("js_code",code), new BasicNameValuePair("grant_type",grant_type) ).build(); HttpGet httpGet = new HttpGet(uri); CloseableHttpClient httpClient = HttpClientBuilder.create().build(); // 配置信息 RequestConfig requestConfig = RequestConfig.custom() // 设置连接超时时间(单位毫秒) .setConnectTimeout(5000) // 设置请求超时时间(单位毫秒) .setConnectionRequestTimeout(5000) // socket读写超时时间(单位毫秒) .setSocketTimeout(5000) // 设置是否允许重定向(默认为true) .setRedirectsEnabled(true).build(); httpGet.setConfig(requestConfig); //响应 CloseableHttpResponse response = httpClient.execute(httpGet); // 从响应模型中获取响应实体 String openId = null; try { HttpEntity responseEntity = response.getEntity(); // System.out.println("响应状态为:" + response.getStatusLine()); if (StringUtils.isNull(responseEntity)) { throw new WxLoginException("响应体为空"); } // System.out.println("响应内容长度为:" + responseEntity.getContentLength()); // System.out.println("响应内容为:" + EntityUtils.toString(responseEntity)); JSONObject json = JSON.parseObject(EntityUtils.toString(responseEntity)); openId = json.getString("openid"); if (StringUtils.isNull(openId)) { throw new WxLoginException("openid重复使用"); } } finally { httpClient.close(); response.close(); } return openId; } }
通过opid查询数据库进行登录注册。
springsecurity登录流程
@Service public class LoginServiceImpl implements LoginService { @Autowired private WxLogin wxLogin; @Autowired private UserService userService; @Autowired private RedisCache redisCache; @Autowired private AuthenticationManager authenticationManager; @Autowired private TokenService tokenService; @Override public R<Map<String, Object>> login(String code) { //得到openID String openId = null; try { openId = wxLogin.getOpenId(code); } catch (IOException | URISyntaxException e) { e.printStackTrace(); return R.fail(HttpStatus.ERROR,"服务器请求异常"); } //查询数据库是否存在openID boolean exist = true; //先查缓存再查数据库 LoginUser loginUser = redisCache.getCacheObject(RedisCacheKeys.USERINFO_KEY + openId); if (StringUtils.isNull(loginUser)) { loginUser = new LoginUser(); } if (StringUtils.isNull(loginUser.getUser())) { LambdaQueryWrapper<User> uqw = new LambdaQueryWrapper<>(); uqw.eq(User::getOpenid,openId); User user = userService.getOne(uqw); if (StringUtils.isNull(user)) { exist = false; } else { loginUser.setUser(user); redisCache.setCacheObject(RedisCacheKeys.USERINFO_KEY+openId, loginUser); } } //不存在就注册,再登录 if(!exist) { register(openId); } //springsecurity进行登录,存在就登录 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(openId, "null"); Authentication authenticate = authenticationManager.authenticate(authenticationToken); if (StringUtils.isNull(authenticate)) { throw new UsernameNotFoundException("用户名不出在!"); } //封装 LoginUser user = (LoginUser) authenticate.getPrincipal(); //生成token String token = tokenService.createToken(user); UserInfoVo userInfo = BeanUtils.copyBean(loginUser.getUser(),UserInfoVo.class); HashMap<String, Object> res = new HashMap<String, Object>(); res.put("token",token); res.put("userInfo",userInfo); return R.ok(res); } @Override public void register(String openId) { // User user = new User(); user.setOpenid(openId); userService.save(user); } }
token生成 @Component public class TokenService { // 令牌自定义标识 @Value("${token.header}") private String header; // 令牌秘钥 @Value("${token.secret}") private String secret; // 令牌有效期(默认30分钟) @Value("${token.expireTime}") private int expireTime; protected static final long MILLIS_SECOND = 1000; protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; protected static final long MILLIS_HOURS = 60 * MILLIS_MINUTE; private static final Long MILLIS_MINUTE_TEN = 60 * 60 * 1000L; @Autowired private RedisCache redisCache; /** * 获取用户身份信息 * * @return 用户信息 */ public LoginUser getLoginUser(HttpServletRequest request) { // 获取请求携带的令牌 String token = getToken(request); if (StringUtils.isNotEmpty(token)) { try { Claims claims = parseToken(token); // 解析对应的权限以及用户信息 String openid = (String) claims.get(Constants.LOGIN_USER_KEY); String userKey = getTokenKey(openid); return redisCache.getCacheObject(userKey); } catch (Exception e) { e.printStackTrace(); } } return null; } /** * 删除用户身份信息 */ public void delLoginUser(String token) { if (StringUtils.isNotEmpty(token)) { String userKey = getTokenKey(token); redisCache.deleteObject(userKey); } } /** * 创建令牌 * * @param loginUser 用户信息 * @return 令牌 */ public String createToken(LoginUser loginUser) { refreshToken(loginUser); Map<String, Object> claims = new HashMap<>(); claims.put(Constants.LOGIN_USER_KEY, loginUser.getUser().getOpenid()); return createToken(claims); } /** * 验证令牌有效期,相差不足一个小时,自动刷新缓存 * * @param loginUser * @return 令牌 */ public void verifyToken(LoginUser loginUser) { long expireTime = loginUser.getExpireTime(); long currentTime = System.currentTimeMillis(); if (expireTime - currentTime <= MILLIS_MINUTE_TEN) { refreshToken(loginUser); } } /** * 刷新令牌有效期 * * @param loginUser 登录信息 */ public void refreshToken(LoginUser loginUser) { loginUser.setLoginTime(System.currentTimeMillis()); loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_HOURS); // 根据uuid将loginUser缓存 String userKey = getTokenKey(loginUser.getUser().getOpenid()); redisCache.setCacheObject(userKey, loginUser, expireTime,TimeUnit.HOURS); } /** * 从数据声明生成令牌 * * @param claims 数据声明 * @return 令牌 */ private String createToken(Map<String, Object> claims) { return Jwts.builder() .setClaims(claims) .signWith(SignatureAlgorithm.HS512, secret).compact(); } /** * 从令牌中获取数据声明 * * @param token 令牌 * @return 数据声明 */ private Claims parseToken(String token) { return Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody(); } /** * 从令牌中获取用户名 * * @param token 令牌 * @return 用户名 */ public String getUsernameFromToken(String token) { Claims claims = parseToken(token); return claims.getSubject(); } /** * 获取请求token * * @param request * @return token */ private String getToken(HttpServletRequest request) { return request.getHeader(header); } private String getTokenKey(String openId) { return RedisCacheKeys.USERINFO_KEY + openId; } }
完整流程图
**
* 获取请求token
*
* @param request
* @return token
*/
private String getToken(HttpServletRequest request)
{
return request.getHeader(header);
}
private String getTokenKey(String openId)
{
return RedisCacheKeys.USERINFO_KEY + openId;
}
}
完整流程图
[外链图片转存中...(img-KPgnRjWY-1678029553423)]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。