|
@@ -1,10 +1,22 @@
|
|
|
package com.jd.lightapplication.security;
|
|
|
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
+import cn.hutool.http.HttpUtil;
|
|
|
+import cn.hutool.json.JSONObject;
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
|
|
-import com.fasterxml.jackson.databind.ObjectMapper;
|
|
|
import com.jd.lightapplication.common.exception.CaptchaException;
|
|
|
+import com.jd.lightapplication.common.lang.WeChatConfig;
|
|
|
+import com.jd.lightapplication.model.SysRole;
|
|
|
+import com.jd.lightapplication.model.SysUser;
|
|
|
+import com.jd.lightapplication.model.SysUserRole;
|
|
|
+import com.jd.lightapplication.service.SysRoleService;
|
|
|
+import com.jd.lightapplication.service.SysUserRoleService;
|
|
|
+import com.jd.lightapplication.service.SysUserService;
|
|
|
import lombok.AllArgsConstructor;
|
|
|
import lombok.Data;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.beans.factory.InitializingBean;
|
|
|
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
|
|
import org.springframework.data.redis.core.RedisTemplate;
|
|
@@ -18,19 +30,30 @@ import javax.servlet.ServletException;
|
|
|
import javax.servlet.http.HttpServletRequest;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
import java.io.IOException;
|
|
|
-import java.io.InputStream;
|
|
|
-import java.util.HashMap;
|
|
|
-import java.util.Map;
|
|
|
|
|
|
@Data
|
|
|
@AllArgsConstructor
|
|
|
@Component
|
|
|
+@Slf4j
|
|
|
public class MobileLoginFilter extends OncePerRequestFilter implements InitializingBean {
|
|
|
+
|
|
|
+ private SysUserService sysUserService;
|
|
|
+ private SysRoleService sysRoleService;
|
|
|
+ private SysUserRoleService sysUserRoleService;
|
|
|
+
|
|
|
LoginFailureHandler loginFailureHandler;
|
|
|
private SecurityProperties securityProperties;
|
|
|
private AuthenticationFailureHandler authenticationFailureHandler;
|
|
|
private RedisTemplate redisTemplate;
|
|
|
|
|
|
+ private final String CAPTCHA = "CAPTCHA";
|
|
|
+ private final String QUICK = "QUICK";
|
|
|
+
|
|
|
+ private WeChatConfig weChatConfig;
|
|
|
+
|
|
|
+ private final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
|
|
|
+ private final String PHONE_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=%s";
|
|
|
+
|
|
|
@Override
|
|
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException, ServletException, IOException {
|
|
|
|
|
@@ -57,21 +80,100 @@ public class MobileLoginFilter extends OncePerRequestFilter implements Initializ
|
|
|
|
|
|
String phone = request.getParameter("phone");
|
|
|
String code = request.getParameter("code");
|
|
|
+ String type = request.getParameter("type");
|
|
|
|
|
|
- if (StringUtils.isBlank(phone) || StringUtils.isBlank(code)) {
|
|
|
- throw new CaptchaException("验证码错误");
|
|
|
+ if (QUICK.equals(type)) {//表示手机快捷登录 用code去微信服务器换取手机号
|
|
|
+ phone = this.getPhone(code);
|
|
|
+ //快捷登录没有手机号信息,需要把手机号存到request里面。让后面的过滤器能取到手机号
|
|
|
+ request.setAttribute("phone", phone);
|
|
|
+ } else if (CAPTCHA.equals(type)) {//表示手机验证码登录
|
|
|
+ Object redisCode = redisTemplate.opsForValue().get(phone);
|
|
|
+ if (StringUtils.isBlank(phone) || StringUtils.isBlank(code) || redisCode == null || !code.equals(redisCode.toString())) {
|
|
|
+ throw new CaptchaException("验证码错误");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- Object redisCode = redisTemplate.opsForValue().get(phone);
|
|
|
-
|
|
|
- if (redisCode == null || !code.equals(redisCode.toString())) {
|
|
|
- throw new CaptchaException("验证码错误");
|
|
|
- }
|
|
|
+ this.handlePhone(phone);
|
|
|
|
|
|
//把验证码从redis里面移除 让验证码失效
|
|
|
// TODO: 2022/4/19
|
|
|
//redisTemplate.delete(phone);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 处理手机号 如果用户表存在phone则不做处理,如果不存在phone则新增用户信息默认角色为来宾
|
|
|
+ *
|
|
|
+ * @param phone
|
|
|
+ */
|
|
|
+ private void handlePhone(String phone) {
|
|
|
+ SysUser sysUser = sysUserService.getByPhone(phone);
|
|
|
+ if (sysUser != null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //先添加用户信息
|
|
|
+ sysUser = new SysUser()
|
|
|
+ .setPhone(phone)
|
|
|
+ .setStatu(1)//表示可用
|
|
|
+ .setCreated(DateUtil.now());
|
|
|
+ Boolean result = sysUserService.save(sysUser);
|
|
|
+ //再添加用户角色
|
|
|
+ LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
|
|
|
+ wrapper.eq(SysRole::getCode, "GUEST");
|
|
|
+ SysRole sysRole = sysRoleService.getOne(wrapper);
|
|
|
+ SysUserRole sysUserRole = new SysUserRole()
|
|
|
+ .setRoleId(sysRole.getId())
|
|
|
+ .setUserId(sysUser.getId());
|
|
|
+ Boolean result1 = sysUserRoleService.save(sysUserRole);
|
|
|
+
|
|
|
+ if (!(result && result1)) {
|
|
|
+ throw new CaptchaException("系统异常,请联系管理员!");
|
|
|
+ }
|
|
|
+ log.debug("手机号登录未找到用户信息," + (result ? "新增用户成功。" : "新增用户失败。") + "phone=" + phone);
|
|
|
+ log.debug("手机号登录未找到用户信息," + (result1 ? "新增角色成功。" : "新增角色失败。") + "phone=" + phone);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据小程序拿到的动态令牌获取用户手机号
|
|
|
+ * @param code
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public String getPhone(String code) {
|
|
|
+ //先获取accessToken
|
|
|
+ String accessToken = this.getAccessToken();
|
|
|
+ //拿accessToken和动态令牌去微信获取用户手机号信息
|
|
|
+ JSONObject jsonObject = JSONUtil.createObj();
|
|
|
+ jsonObject.set("code", code);
|
|
|
+ String phoneUrl = String.format(PHONE_URL, accessToken);
|
|
|
+ String phoneResult = HttpUtil.createPost(phoneUrl)
|
|
|
+ .header("Content-Type", "application/json")
|
|
|
+ .body(jsonObject.toString())
|
|
|
+ .execute()
|
|
|
+ .body();
|
|
|
+ JSONObject result = JSONUtil.parseObj(phoneResult);
|
|
|
+ if (!"ok".equals(result.get("errmsg"))) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ JSONObject phoneInfo = result.getJSONObject("phone_info");
|
|
|
+ return phoneInfo.getStr("phoneNumber");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取accessToken
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String getAccessToken() {
|
|
|
+ //拼接access_token请求地址
|
|
|
+ String accessTokenUrl = String.format(ACCESS_TOKEN_URL, weChatConfig.getAppId(), weChatConfig.getAppSecret());
|
|
|
+ //先获取access_token
|
|
|
+ String accessTokenResult = HttpUtil.createGet(accessTokenUrl)
|
|
|
+ .execute()
|
|
|
+ .charset("UTF-8")
|
|
|
+ .body();
|
|
|
+ JSONObject result = JSONUtil.parseObj(accessTokenResult);
|
|
|
+ String accessToken = result.get("access_token").toString();
|
|
|
+ return accessToken;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|