From e8e332b9b27a5c8a20dd0b9a9eb0d03a48fee45f Mon Sep 17 00:00:00 2001 From: feijinping Date: Tue, 28 Feb 2023 19:32:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E7=99=BB=E9=99=86=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/fjp/lc/test/service/WechatTest.java | 25 ++++++ .../web/service/SysLoginService.java | 8 +- ruoyi-mall/pom.xml | 4 + .../com/cyl/external/ExternalException.java | 13 ++++ .../java/com/cyl/external/WechatUtil.java | 41 ++++++++++ .../cyl/external/resp/AccessTokenResp.java | 19 +++++ .../java/com/cyl/external/resp/BaseResp.java | 9 +++ .../com/cyl/external/resp/UserInfoResp.java | 14 ++++ .../cyl/h5/controller/WechatController.java | 17 +++-- .../cyl/h5/pojo/vo/form/WechatLoginForm.java | 9 +++ .../cyl/ums/convert/MemberWechatConvert.java | 4 + .../cyl/ums/service/MemberWechatService.java | 76 +++++++++++++++++++ 12 files changed, 229 insertions(+), 10 deletions(-) create mode 100644 ruoyi-admin/src/test/java/com/fjp/lc/test/service/WechatTest.java create mode 100644 ruoyi-mall/src/main/java/com/cyl/external/ExternalException.java create mode 100644 ruoyi-mall/src/main/java/com/cyl/external/resp/AccessTokenResp.java create mode 100644 ruoyi-mall/src/main/java/com/cyl/external/resp/BaseResp.java create mode 100644 ruoyi-mall/src/main/java/com/cyl/external/resp/UserInfoResp.java create mode 100644 ruoyi-mall/src/main/java/com/cyl/h5/pojo/vo/form/WechatLoginForm.java diff --git a/ruoyi-admin/src/test/java/com/fjp/lc/test/service/WechatTest.java b/ruoyi-admin/src/test/java/com/fjp/lc/test/service/WechatTest.java new file mode 100644 index 0000000..a8ebdf0 --- /dev/null +++ b/ruoyi-admin/src/test/java/com/fjp/lc/test/service/WechatTest.java @@ -0,0 +1,25 @@ +package com.fjp.lc.test.service; + +import com.cyl.h5.pojo.vo.form.WechatLoginForm; +import com.cyl.ums.service.MemberWechatService; +import com.ruoyi.RuoYiApplication; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = RuoYiApplication.class) +@ActiveProfiles("dev") +public class WechatTest { + @Autowired + private MemberWechatService memberWechatService; + @Test + public void testAuth() { + WechatLoginForm f = new WechatLoginForm(); + f.setCode("081zPgHa1FbRQE0wGIIa1lgb1C1zPgHi"); + memberWechatService.login(f); + } +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java index 27b4237..2198fba 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java @@ -31,6 +31,8 @@ import org.springframework.security.core.Authentication; import org.springframework.stereotype.Component; import javax.annotation.Resource; +import java.util.Arrays; +import java.util.Collections; import java.util.Date; import java.util.List; @@ -209,13 +211,13 @@ public class SysLoginService { userService.registerUser(user); // 赋予角色 - SysRole vipRole = sysRoleService.selectRoleByKey("vip"); + SysRole role = sysRoleService.selectRoleByKey("common"); // 增加用户的权限,绑定角色 - sysRoleService.insertAuthUsers(vipRole.getRoleId(), new Long[]{user.getUserId()}); + sysRoleService.insertAuthUsers(role.getRoleId(), new Long[]{user.getUserId()}); AsyncManager.me().execute(AsyncFactory.recordLogininfor(body.getLogin(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.register.success"))); recordLoginInfo(user); - + user.setRoles(Collections.singletonList(role)); return user; } diff --git a/ruoyi-mall/pom.xml b/ruoyi-mall/pom.xml index 38db63a..08a3b55 100644 --- a/ruoyi-mall/pom.xml +++ b/ruoyi-mall/pom.xml @@ -77,5 +77,9 @@ + + com.ruoyi + ruoyi-framework + diff --git a/ruoyi-mall/src/main/java/com/cyl/external/ExternalException.java b/ruoyi-mall/src/main/java/com/cyl/external/ExternalException.java new file mode 100644 index 0000000..885a864 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/cyl/external/ExternalException.java @@ -0,0 +1,13 @@ +package com.cyl.external; + +import lombok.Data; + +@Data +public class ExternalException extends RuntimeException { + private String code; + + public ExternalException(String code, String message) { + super(message); + this.code = code; + } +} diff --git a/ruoyi-mall/src/main/java/com/cyl/external/WechatUtil.java b/ruoyi-mall/src/main/java/com/cyl/external/WechatUtil.java index da76b32..c6a1cdc 100644 --- a/ruoyi-mall/src/main/java/com/cyl/external/WechatUtil.java +++ b/ruoyi-mall/src/main/java/com/cyl/external/WechatUtil.java @@ -1,10 +1,29 @@ package com.cyl.external; +import cn.hutool.http.HttpUtil; +import com.alibaba.fastjson.JSON; +import com.cyl.external.resp.AccessTokenResp; +import com.cyl.external.resp.BaseResp; +import com.cyl.external.resp.UserInfoResp; +import com.ruoyi.common.exception.base.BaseException; import org.apache.commons.codec.digest.DigestUtils; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; import java.util.Arrays; +@Component +@ConfigurationProperties(prefix = "wechat") public class WechatUtil { + private static String appId; + private static String secret; + public void setAppId(String appId) { + WechatUtil.appId = appId; + } + public void setSecret(String secret) { + WechatUtil.secret = secret; + } public static boolean validParam(String signature, String... arr) { Arrays.sort(arr); StringBuilder sb = new StringBuilder(); @@ -18,4 +37,26 @@ public class WechatUtil { return signature.equals(DigestUtils.sha1Hex(sb.toString())); } + private static final String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; + private static final String USER_INFO_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN"; + public static AccessTokenResp getAccessToken(String code) { + String url = ACCESS_TOKEN_URL.replace("APPID", appId).replace("SECRET", secret).replace("CODE", code); + String res = HttpUtil.get(url); + AccessTokenResp resp = JSON.parseObject(res, AccessTokenResp.class); + validResp(resp); + return resp; + } + + public static UserInfoResp getUserInfo(String accessToken, String openid) { + String url = USER_INFO_URL.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openid); + String res = HttpUtil.get(url); + UserInfoResp resp = JSON.parseObject(res, UserInfoResp.class); + validResp(resp); + return resp; + } + public static void validResp(BaseResp resp) { + if (resp.getErrcode() != null) { + throw new ExternalException(resp.getErrcode() + "", resp.getErrmsg()); + } + } } diff --git a/ruoyi-mall/src/main/java/com/cyl/external/resp/AccessTokenResp.java b/ruoyi-mall/src/main/java/com/cyl/external/resp/AccessTokenResp.java new file mode 100644 index 0000000..9f8589f --- /dev/null +++ b/ruoyi-mall/src/main/java/com/cyl/external/resp/AccessTokenResp.java @@ -0,0 +1,19 @@ +package com.cyl.external.resp; + +import com.alibaba.fastjson.annotation.JSONField; +import lombok.Data; + +@Data +public class AccessTokenResp extends BaseResp { + @JSONField(name = "access_token") + private String accessToken; + @JSONField(name = "expires_in") + private Integer expiresIn; + @JSONField(name = "refresh_token") + private String refreshToken; + private String openid; + private String scope; + @JSONField(name = "is_snapshotuser") + private Integer snapshotuser; + private String unionid; +} diff --git a/ruoyi-mall/src/main/java/com/cyl/external/resp/BaseResp.java b/ruoyi-mall/src/main/java/com/cyl/external/resp/BaseResp.java new file mode 100644 index 0000000..751df98 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/cyl/external/resp/BaseResp.java @@ -0,0 +1,9 @@ +package com.cyl.external.resp; + +import lombok.Data; + +@Data +public class BaseResp { + private Integer errcode; + private String errmsg; +} diff --git a/ruoyi-mall/src/main/java/com/cyl/external/resp/UserInfoResp.java b/ruoyi-mall/src/main/java/com/cyl/external/resp/UserInfoResp.java new file mode 100644 index 0000000..929e321 --- /dev/null +++ b/ruoyi-mall/src/main/java/com/cyl/external/resp/UserInfoResp.java @@ -0,0 +1,14 @@ +package com.cyl.external.resp; + +import lombok.Data; + +@Data +public class UserInfoResp extends BaseResp { + private String openid; + private String nickname; + private Integer sex; + private String province; + private String city; + private String country; + private String headimgurl; +} diff --git a/ruoyi-mall/src/main/java/com/cyl/h5/controller/WechatController.java b/ruoyi-mall/src/main/java/com/cyl/h5/controller/WechatController.java index 3e1e38f..3827466 100644 --- a/ruoyi-mall/src/main/java/com/cyl/h5/controller/WechatController.java +++ b/ruoyi-mall/src/main/java/com/cyl/h5/controller/WechatController.java @@ -1,9 +1,11 @@ package com.cyl.h5.controller; import com.cyl.external.WechatUtil; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import com.cyl.h5.pojo.vo.form.WechatLoginForm; +import com.cyl.ums.service.MemberWechatService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; @@ -13,6 +15,8 @@ import javax.servlet.http.HttpServletRequest; @RestController @RequestMapping("") public class WechatController { + @Autowired + private MemberWechatService memberWechatService; /** * 微信公众号服务器认证 * @return @@ -32,9 +36,8 @@ public class WechatController { * 微信公众号服务器认证 * @return */ - @GetMapping("/no-auth/wechat/h5-login") - public String h5Login(HttpServletRequest request) { - // TODO - return "err"; + @PostMapping("/no-auth/wechat/h5-login") + public ResponseEntity h5Login(@RequestBody WechatLoginForm form) { + return ResponseEntity.ok(memberWechatService.login(form)); } } diff --git a/ruoyi-mall/src/main/java/com/cyl/h5/pojo/vo/form/WechatLoginForm.java b/ruoyi-mall/src/main/java/com/cyl/h5/pojo/vo/form/WechatLoginForm.java new file mode 100644 index 0000000..531d01c --- /dev/null +++ b/ruoyi-mall/src/main/java/com/cyl/h5/pojo/vo/form/WechatLoginForm.java @@ -0,0 +1,9 @@ +package com.cyl.h5.pojo.vo.form; + +import lombok.Data; + +@Data +public class WechatLoginForm { + private String code; + private String state; +} diff --git a/ruoyi-mall/src/main/java/com/cyl/ums/convert/MemberWechatConvert.java b/ruoyi-mall/src/main/java/com/cyl/ums/convert/MemberWechatConvert.java index f34840e..a33ccfd 100644 --- a/ruoyi-mall/src/main/java/com/cyl/ums/convert/MemberWechatConvert.java +++ b/ruoyi-mall/src/main/java/com/cyl/ums/convert/MemberWechatConvert.java @@ -1,5 +1,7 @@ package com.cyl.ums.convert; +import com.cyl.external.resp.AccessTokenResp; +import com.cyl.external.resp.UserInfoResp; import org.mapstruct.Mapper; import com.cyl.ums.domain.MemberWechat; import com.cyl.ums.pojo.vo.MemberWechatVO; @@ -13,4 +15,6 @@ import java.util.List; public interface MemberWechatConvert { List dos2vos(List list); + + MemberWechat info2do(AccessTokenResp info); } diff --git a/ruoyi-mall/src/main/java/com/cyl/ums/service/MemberWechatService.java b/ruoyi-mall/src/main/java/com/cyl/ums/service/MemberWechatService.java index 062d27b..b6d7289 100644 --- a/ruoyi-mall/src/main/java/com/cyl/ums/service/MemberWechatService.java +++ b/ruoyi-mall/src/main/java/com/cyl/ums/service/MemberWechatService.java @@ -1,11 +1,31 @@ package com.cyl.ums.service; import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; import java.util.Arrays; import java.util.List; import java.time.LocalDateTime; +import java.util.concurrent.TimeUnit; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.RandomUtil; +import cn.hutool.core.util.StrUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.cyl.external.WechatUtil; +import com.cyl.external.resp.AccessTokenResp; +import com.cyl.external.resp.UserInfoResp; +import com.cyl.h5.pojo.vo.form.WechatLoginForm; +import com.cyl.ums.convert.MemberWechatConvert; import com.github.pagehelper.PageHelper; +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.core.domain.model.ExtraUserBody; +import com.ruoyi.framework.web.service.SysLoginService; +import com.ruoyi.system.mapper.SysUserMapper; +import com.ruoyi.system.service.ISysUserService; +import lombok.extern.java.Log; +import lombok.extern.log4j.Log4j; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; import org.apache.commons.lang3.StringUtils; @@ -20,10 +40,19 @@ import com.cyl.ums.pojo.query.MemberWechatQuery; * * @author zcc */ +@Slf4j @Service public class MemberWechatService { @Autowired private MemberWechatMapper memberWechatMapper; + @Autowired + private MemberWechatConvert memberWechatConvert; + @Autowired + private SysUserMapper sysUserMapper; + @Autowired + private ISysUserService userService; + @Autowired + private SysLoginService loginService; /** * 查询用户微信信息 @@ -132,4 +161,51 @@ public class MemberWechatService { public int deleteById(Long id) { return memberWechatMapper.deleteById(id); } + + public String login(WechatLoginForm form) { + // 1. code -> token + AccessTokenResp tokenResp = WechatUtil.getAccessToken(form.getCode()); + // 2. token -> user_info + UserInfoResp info = null; + try { + info = WechatUtil.getUserInfo(tokenResp.getAccessToken(), tokenResp.getOpenid()); + } catch (Exception e) { + log.error("form: {}", form.getCode(), e); + } + // 3. 查找用户是否存在, 若没有则创建 + LambdaQueryWrapper qw = new LambdaQueryWrapper<>(); + qw.eq(MemberWechat::getOpenid, tokenResp.getOpenid()); + MemberWechat m = memberWechatMapper.selectOne(qw); + SysUser u; + if (m != null) { + SysUser update = new SysUser(); + if (info != null) { + if (StrUtil.isNotEmpty(info.getNickname())) { + update.setNickName(info.getNickname()); + } + if (info.getSex() != null) { + update.setSex(info.getSex() + ""); + } + if (StrUtil.isNotEmpty(info.getHeadimgurl())) { + update.setAvatar(info.getHeadimgurl()); + } + sysUserMapper.updateUser(update); + } + u = sysUserMapper.selectUserById(m.getMemberId()); + } else { + ExtraUserBody body = ExtraUserBody.builder() + .nickname(info == null ? "" : info.getNickname()) + .avatar(info == null ? "" : info.getHeadimgurl()) + .login(RandomUtil.randomNumbers(9)) + .sex(info == null ? null : info.getSex()) + .build(); + u = loginService.initVipUser(body); + MemberWechat w = memberWechatConvert.info2do(tokenResp); + w.setMemberId(u.getUserId()); + w.setExpireTime(LocalDateTime.now().plus(tokenResp.getExpiresIn(), ChronoUnit.SECONDS)); + memberWechatMapper.insert(w); + } + // 4. 生成token + return loginService.createToken(u); + } }