From 1556d05f5e0afb857cc618bebff7d668578e64cd Mon Sep 17 00:00:00 2001 From: heminjian502 Date: Thu, 4 Aug 2022 14:31:41 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BE=AE=E4=BF=A1=E5=B0=8F=E7=A8=8B=E5=BA=8F?= =?UTF-8?q?=E7=99=BB=E5=BD=95=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 17 ++ .../system/WechatLoginController.java | 48 ++++ .../src/main/resources/application-druid.yml | 2 +- .../src/main/resources/application.yml | 4 + .../core/domain/entity/AccessTokenVo.java | 75 ++++++ .../ruoyi/common/utils/wechat/WechatKeys.java | 9 + .../common/utils/wechat/WechatUtils.java | 58 +++++ .../framework/config/SecurityConfig.java | 1 + ruoyi-system/pom.xml | 41 ++++ .../com/ruoyi/system/domain/TWechatUser.java | 125 ++++++++++ .../ruoyi/system/domain/req/GetOpenidReq.java | 41 ++++ .../system/domain/req/LoginForMpReq.java | 105 ++++++++ .../system/domain/resp/GetOpenidResp.java | 37 +++ .../ruoyi/system/mapper/TPatientMapper.java | 3 +- .../system/mapper/TWechatUserMapper.java | 18 ++ .../ruoyi/system/service/IWechatService.java | 14 ++ .../system/service/impl/UserTokenService.java | 226 ++++++++++++++++++ .../service/impl/WechatServiceImpl.java | 159 ++++++++++++ .../resources/generator/generatorConfig.xml | 43 ++++ .../mapper/system/TWechatUserMapper.xml | 180 ++++++++++++++ 20 files changed, 1204 insertions(+), 2 deletions(-) create mode 100644 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/WechatLoginController.java create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/AccessTokenVo.java create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/utils/wechat/WechatKeys.java create mode 100644 ruoyi-common/src/main/java/com/ruoyi/common/utils/wechat/WechatUtils.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/TWechatUser.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/req/GetOpenidReq.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/req/LoginForMpReq.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/resp/GetOpenidResp.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/mapper/TWechatUserMapper.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/IWechatService.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserTokenService.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WechatServiceImpl.java create mode 100644 ruoyi-system/src/main/resources/generator/generatorConfig.xml create mode 100644 ruoyi-system/src/main/resources/mapper/system/TWechatUserMapper.xml diff --git a/pom.xml b/pom.xml index 18a0aa4..edccf7e 100644 --- a/pom.xml +++ b/pom.xml @@ -38,6 +38,23 @@ + + + mysql + mysql-connector-java + 5.1.30 + + + + org.mybatis + mybatis + 3.4.5 + + + org.mybatis + mybatis-spring + 1.3.1 + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/WechatLoginController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/WechatLoginController.java new file mode 100644 index 0000000..987c582 --- /dev/null +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/WechatLoginController.java @@ -0,0 +1,48 @@ +package com.ruoyi.web.controller.system; + +import com.ruoyi.common.core.domain.AjaxResult; +import com.ruoyi.system.domain.req.GetOpenidReq; +import com.ruoyi.system.domain.req.LoginForMpReq; +import com.ruoyi.system.domain.resp.GetOpenidResp; +import com.ruoyi.system.service.IWechatService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; + +/** + * 微信登录相关接口 + */ +@RestController +@RequestMapping("/wechat/login") +public class WechatLoginController { + + private static final Logger logger = LoggerFactory.getLogger(WechatLoginController.class); + + @Resource + private IWechatService iWechatService; + + /** + * @param + * @return + */ + @PostMapping("/get/openid") + public AjaxResult getWechatLoginInfo(@RequestBody GetOpenidReq getOpenidReq, HttpServletRequest request) { + logger.info("mp获取openid, req = [{}]", getOpenidReq); + + GetOpenidResp resp = iWechatService.getOpenid(getOpenidReq, request); + return AjaxResult.success(resp); + } + + @PostMapping("/for/mp") + public AjaxResult loginForMp(@RequestBody @Validated LoginForMpReq req) { + String token = iWechatService.loginForMp(req); + return AjaxResult.success(token); + } +} diff --git a/ruoyi-admin/src/main/resources/application-druid.yml b/ruoyi-admin/src/main/resources/application-druid.yml index 2551d1c..b1bbcea 100644 --- a/ruoyi-admin/src/main/resources/application-druid.yml +++ b/ruoyi-admin/src/main/resources/application-druid.yml @@ -2,7 +2,7 @@ spring: datasource: type: com.alibaba.druid.pool.DruidDataSource - driverClassName: com.mysql.cj.jdbc.Driver + driverClassName: com.mysql.jdbc.Driver druid: # 主库数据源 master: diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index e6686d4..c4085c5 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -121,3 +121,7 @@ xss: excludes: /system/notice # 匹配链接 urlPatterns: /system/*,/monitor/*,/tool/* + +wx: + mpAppId: wxcf05e06d4ab81582 + mpSecret: 252594e6b980bc2bfc74bbaad92b5e7b \ No newline at end of file diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/AccessTokenVo.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/AccessTokenVo.java new file mode 100644 index 0000000..89324ee --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/AccessTokenVo.java @@ -0,0 +1,75 @@ +package com.ruoyi.common.core.domain.entity; + +import com.alibaba.fastjson.annotation.JSONField; + +import java.io.Serializable; + +public class AccessTokenVo implements Serializable { + private static final long serialVersionUID = -4331247900203620881L; + + @JSONField(name = "access_token") + private String accessToken; + + @JSONField(name = "expires_in") + private Integer expiresIn; + + @JSONField(name = "errcode") + private Integer errCode; + + @JSONField(name = "errmsg") + private String errMsg; + + @JSONField(name = "userid") + private String userId; + + public String getAccessToken() { + return accessToken; + } + + public void setAccessToken(String accessToken) { + this.accessToken = accessToken; + } + + public Integer getExpiresIn() { + return expiresIn; + } + + public void setExpiresIn(Integer expiresIn) { + this.expiresIn = expiresIn; + } + + public Integer getErrCode() { + return errCode; + } + + public void setErrCode(Integer errCode) { + this.errCode = errCode; + } + + public String getErrMsg() { + return errMsg; + } + + public void setErrMsg(String errMsg) { + this.errMsg = errMsg; + } + + public String getUserId() { + return userId; + } + + public void setUserId(String userId) { + this.userId = userId; + } + + @Override + public String toString() { + return "AccessTokenVo{" + + "accessToken='" + accessToken + '\'' + + ", expiresIn=" + expiresIn + + ", errCode=" + errCode + + ", errMsg='" + errMsg + '\'' + + ", userId='" + userId + '\'' + + '}'; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/wechat/WechatKeys.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/wechat/WechatKeys.java new file mode 100644 index 0000000..c87541d --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/wechat/WechatKeys.java @@ -0,0 +1,9 @@ +package com.ruoyi.common.utils.wechat; + +public class WechatKeys { + public static String ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s"; + + public static String MP_ACCESS_TOKEN_REDIS_KEY = "redis:mp:access:token:key"; + + public static String MP_CODE_TO_OPENID_URL = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code"; +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/wechat/WechatUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/wechat/WechatUtils.java new file mode 100644 index 0000000..a83fae0 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/wechat/WechatUtils.java @@ -0,0 +1,58 @@ +package com.ruoyi.common.utils.wechat; + +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.core.domain.entity.AccessTokenVo; +import com.ruoyi.common.core.redis.RedisCache; +import com.ruoyi.common.utils.http.HttpUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +@Component +public class WechatUtils { + + private static final Logger logger = LoggerFactory.getLogger(WechatUtils.class); + + /** + * 微信小程序AppID + */ + @Value("${wx.mpAppId}") + private String appId; + /** + * 微信小程序AppSecret + */ + @Value("${wx.mpSecret}") + private String appSecret; + + @Autowired + private RedisCache redisCache; + + /** + * 获取access_token + * @return + */ + public String getMpAccessToken() { + String accessToken = redisCache.getCacheObject(WechatKeys.MP_ACCESS_TOKEN_REDIS_KEY); + if (StringUtils.isBlank(accessToken)) { + String accessTokenUrl = String.format(WechatKeys.ACCESS_TOKEN_URL, appId, appSecret); + String result = HttpUtils.sendGet(accessTokenUrl); + JSONObject jsonObject = JSONObject.parseObject(result); + AccessTokenVo accessTokenVo = JSONObject.toJavaObject(jsonObject, AccessTokenVo.class); + if (Objects.nonNull(accessTokenVo) && StringUtils.isNotBlank(accessTokenVo.getAccessToken())) { + accessToken = accessTokenVo.getAccessToken(); + redisCache.setCacheObject(WechatKeys.MP_ACCESS_TOKEN_REDIS_KEY, accessTokenVo.getAccessToken(), accessTokenVo.getExpiresIn(), TimeUnit.SECONDS); + } + } + return accessToken; + } + + + + +} diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java index 35e9dee..6706dd8 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java @@ -112,6 +112,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter .antMatchers("/webjars/**").anonymous() .antMatchers("/*/api-docs").anonymous() .antMatchers("/druid/**").anonymous() + .antMatchers("/wechat/login/**").anonymous() // 除上面外的所有请求全部需要鉴权认证 .anyRequest().authenticated() .and() diff --git a/ruoyi-system/pom.xml b/ruoyi-system/pom.xml index e55e2a8..f6d547c 100644 --- a/ruoyi-system/pom.xml +++ b/ruoyi-system/pom.xml @@ -23,6 +23,47 @@ ruoyi-common + + tk.mybatis + mapper + 3.4.2 + + + + mysql + mysql-connector-java + 5.1.44 + + + + + + org.mybatis.generator + mybatis-generator-maven-plugin + 1.3.2 + + + mysql + mysql-connector-java + 5.1.44 + + + tk.mybatis + mapper + 3.4.2 + + + + + + src/main/resources/generator/generatorConfig.xml + true + true + + + + + \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/TWechatUser.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TWechatUser.java new file mode 100644 index 0000000..3b87838 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/TWechatUser.java @@ -0,0 +1,125 @@ +package com.ruoyi.system.domain; + +import java.util.Date; + +public class TWechatUser { + private Long id; + + private Date lastLoginTime; + + private String lastLoginIp; + + private String nickname; + + private String mobile; + + private String avatar; + + private String openid; + + private String unionid; + + private Byte status; + + private Date addTime; + + private Date updateTime; + + private Long userId; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Date getLastLoginTime() { + return lastLoginTime; + } + + public void setLastLoginTime(Date lastLoginTime) { + this.lastLoginTime = lastLoginTime; + } + + public String getLastLoginIp() { + return lastLoginIp; + } + + public void setLastLoginIp(String lastLoginIp) { + this.lastLoginIp = lastLoginIp == null ? null : lastLoginIp.trim(); + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickname) { + this.nickname = nickname == null ? null : nickname.trim(); + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile == null ? null : mobile.trim(); + } + + public String getAvatar() { + return avatar; + } + + public void setAvatar(String avatar) { + this.avatar = avatar == null ? null : avatar.trim(); + } + + public String getOpenid() { + return openid; + } + + public void setOpenid(String openid) { + this.openid = openid == null ? null : openid.trim(); + } + + public String getUnionid() { + return unionid; + } + + public void setUnionid(String unionid) { + this.unionid = unionid == null ? null : unionid.trim(); + } + + public Byte getStatus() { + return status; + } + + public void setStatus(Byte status) { + this.status = status; + } + + public Date getAddTime() { + return addTime; + } + + public void setAddTime(Date addTime) { + this.addTime = addTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + public Long getUserId() { + return userId; + } + + public void setUserId(Long userId) { + this.userId = userId; + } +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/req/GetOpenidReq.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/req/GetOpenidReq.java new file mode 100644 index 0000000..b009936 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/req/GetOpenidReq.java @@ -0,0 +1,41 @@ +package com.ruoyi.system.domain.req; + +import java.io.Serializable; + +/** + * @Description: 用户信息 + * @Author: chy + * @Date: 2022/5/24 + **/ +public class GetOpenidReq implements Serializable { + + private static final long serialVersionUID = -1185015143654744140L; + + private String nickName; + private String avatarUrl; + private String code; + + public String getNickName() { + return nickName; + } + + public void setNickName(String nickName) { + this.nickName = nickName; + } + + public String getAvatarUrl() { + return avatarUrl; + } + + public void setAvatarUrl(String avatarUrl) { + this.avatarUrl = avatarUrl; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/req/LoginForMpReq.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/req/LoginForMpReq.java new file mode 100644 index 0000000..f35a20e --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/req/LoginForMpReq.java @@ -0,0 +1,105 @@ +package com.ruoyi.system.domain.req; + +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +public class LoginForMpReq implements Serializable { + private static final long serialVersionUID = -5482485655738769622L; + + @NotBlank + private String openId; + + @NotBlank + private String name; + + @NotBlank + private String phone; + + @NotBlank + private String sex; + + /** + * 出生年月日 yyyy-MM-dd + */ + private String birth; + + private Integer height; + + private Integer weight; + + private String marriage; + + private String disease; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getSex() { + return sex; + } + + public void setSex(String sex) { + this.sex = sex; + } + + public String getBirth() { + return birth; + } + + public void setBirth(String birth) { + this.birth = birth; + } + + public Integer getHeight() { + return height; + } + + public void setHeight(Integer height) { + this.height = height; + } + + public Integer getWeight() { + return weight; + } + + public void setWeight(Integer weight) { + this.weight = weight; + } + + public String getMarriage() { + return marriage; + } + + public void setMarriage(String marriage) { + this.marriage = marriage; + } + + public String getDisease() { + return disease; + } + + public void setDisease(String disease) { + this.disease = disease; + } + + public String getOpenId() { + return openId; + } + + public void setOpenId(String openId) { + this.openId = openId; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/resp/GetOpenidResp.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/resp/GetOpenidResp.java new file mode 100644 index 0000000..f21eb35 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/resp/GetOpenidResp.java @@ -0,0 +1,37 @@ +package com.ruoyi.system.domain.resp; + +import java.io.Serializable; + +public class GetOpenidResp implements Serializable { + private static final long serialVersionUID = -8328911573370172974L; + + private String openid; + + private Boolean bindFlag = false; + + private String token; + + public String getOpenid() { + return openid; + } + + public void setOpenid(String openid) { + this.openid = openid; + } + + public Boolean getBindFlag() { + return bindFlag; + } + + public void setBindFlag(Boolean bindFlag) { + this.bindFlag = bindFlag; + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TPatientMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TPatientMapper.java index 821e729..23d86c2 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TPatientMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TPatientMapper.java @@ -2,6 +2,7 @@ package com.ruoyi.system.mapper; import java.util.List; import com.ruoyi.system.domain.TPatient; +import tk.mybatis.mapper.common.Mapper; /** * 患者信息Mapper接口 @@ -9,7 +10,7 @@ import com.ruoyi.system.domain.TPatient; * @author ruoyi * @date 2022-08-03 */ -public interface TPatientMapper +public interface TPatientMapper extends Mapper { /** * 查询患者信息 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TWechatUserMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TWechatUserMapper.java new file mode 100644 index 0000000..751de76 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/TWechatUserMapper.java @@ -0,0 +1,18 @@ +package com.ruoyi.system.mapper; + +import com.ruoyi.system.domain.TWechatUser; +import tk.mybatis.mapper.common.Mapper; + +public interface TWechatUserMapper extends Mapper { + int insert(TWechatUser record); + + int insertSelective(TWechatUser record); + + TWechatUser selectUserByPrimaryKey(Long id); + + TWechatUser selectWechatUserByOpenid(String openid); + + int updateByPrimaryKeySelective(TWechatUser record); + + int updateByPrimaryKey(TWechatUser record); +} \ No newline at end of file diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IWechatService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IWechatService.java new file mode 100644 index 0000000..966ddd2 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IWechatService.java @@ -0,0 +1,14 @@ +package com.ruoyi.system.service; + +import com.ruoyi.system.domain.req.GetOpenidReq; +import com.ruoyi.system.domain.req.LoginForMpReq; +import com.ruoyi.system.domain.resp.GetOpenidResp; + +import javax.servlet.http.HttpServletRequest; + +public interface IWechatService { + + GetOpenidResp getOpenid(GetOpenidReq req, HttpServletRequest request); + + String loginForMp(LoginForMpReq req); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserTokenService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserTokenService.java new file mode 100644 index 0000000..3a22965 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/UserTokenService.java @@ -0,0 +1,226 @@ +package com.ruoyi.system.service.impl; + +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.core.domain.model.LoginUser; +import com.ruoyi.common.core.redis.RedisCache; +import com.ruoyi.common.utils.ServletUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.ip.AddressUtils; +import com.ruoyi.common.utils.ip.IpUtils; +import com.ruoyi.common.utils.uuid.IdUtils; +import eu.bitwalker.useragentutils.UserAgent; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * token验证处理 + * + * @author ruoyi + */ +@Component +public class UserTokenService +{ + // 令牌自定义标识 + @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; + + private static final Long MILLIS_MINUTE_TEN = 20 * 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 uuid = (String) claims.get(Constants.LOGIN_USER_KEY); + String userKey = getTokenKey(uuid); + LoginUser user = redisCache.getCacheObject(userKey); + return user; + } + catch (Exception e) + { + } + } + return null; + } + + /** + * 设置用户身份信息 + */ + public void setLoginUser(LoginUser loginUser) + { + if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) + { + refreshToken(loginUser); + } + } + + /** + * 删除用户身份信息 + */ + public void delLoginUser(String token) + { + if (StringUtils.isNotEmpty(token)) + { + String userKey = getTokenKey(token); + redisCache.deleteObject(userKey); + } + } + + /** + * 创建令牌 + * + * @param loginUser 用户信息 + * @return 令牌 + */ + public String createToken(LoginUser loginUser) + { + String token = IdUtils.fastUUID(); + loginUser.setToken(token); + setUserAgent(loginUser); + refreshToken(loginUser); + + Map claims = new HashMap<>(); + claims.put(Constants.LOGIN_USER_KEY, token); + return createToken(claims); + } + + /** + * 验证令牌有效期,相差不足20分钟,自动刷新缓存 + * + * @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_MINUTE); + // 根据uuid将loginUser缓存 + String userKey = getTokenKey(loginUser.getToken()); + redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES); + } + + /** + * 设置用户代理信息 + * + * @param loginUser 登录信息 + */ + public void setUserAgent(LoginUser loginUser) + { + UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent")); + String ip = IpUtils.getIpAddr(ServletUtils.getRequest()); + loginUser.setIpaddr(ip); + loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip)); + loginUser.setBrowser(userAgent.getBrowser().getName()); + loginUser.setOs(userAgent.getOperatingSystem().getName()); + } + + /** + * 从数据声明生成令牌 + * + * @param claims 数据声明 + * @return 令牌 + */ + private String createToken(Map claims) + { + String token = Jwts.builder() + .setClaims(claims) + .signWith(SignatureAlgorithm.HS512, secret).compact(); + return token; + } + + /** + * 从令牌中获取数据声明 + * + * @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) + { + String token = request.getHeader(header); + if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX)) + { + token = token.replace(Constants.TOKEN_PREFIX, ""); + } + return token; + } + + private String getTokenKey(String uuid) + { + return Constants.LOGIN_TOKEN_KEY + uuid; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WechatServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WechatServiceImpl.java new file mode 100644 index 0000000..0e08733 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WechatServiceImpl.java @@ -0,0 +1,159 @@ +package com.ruoyi.system.service.impl; + +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.core.domain.model.LoginUser; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.http.HttpUtils; +import com.ruoyi.common.utils.ip.IpUtils; +import com.ruoyi.common.utils.wechat.WechatKeys; +import com.ruoyi.system.domain.TPatient; +import com.ruoyi.system.domain.TWechatUser; +import com.ruoyi.system.domain.req.GetOpenidReq; +import com.ruoyi.system.domain.req.LoginForMpReq; +import com.ruoyi.system.domain.resp.GetOpenidResp; +import com.ruoyi.system.mapper.TPatientMapper; +import com.ruoyi.system.mapper.TWechatUserMapper; +import com.ruoyi.system.service.IWechatService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import tk.mybatis.mapper.entity.Example; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.util.Date; +import java.util.List; +import java.util.Objects; + +@Service +public class WechatServiceImpl implements IWechatService { + private static final Logger logger = LoggerFactory.getLogger(WechatServiceImpl.class); + /** + * 微信小程序AppID + */ + @Value("${wx.mpAppId}") + private String appId; + /** + * 微信小程序AppSecret + */ + @Value("${wx.mpSecret}") + private String appSecret; + + @Resource + private TWechatUserMapper tWechatUserMapper; + + @Resource + private TPatientMapper tPatientMapper; + + @Resource + private UserTokenService userTokenService; + + @Override + public GetOpenidResp getOpenid(GetOpenidReq req, HttpServletRequest request) { + //查询openid + String openid = queryOpenid(req); + TWechatUser wechatUser = updateWechatUser(openid, req, request); + GetOpenidResp resp = new GetOpenidResp(); + if (Objects.isNull(wechatUser.getUserId())) { + resp.setBindFlag(false); + } else { + // 已绑定信息 直接登录 + resp.setBindFlag(true); + TPatient tPatient = tPatientMapper.selectTPatientById(wechatUser.getUserId()); + String token = buildTokenByPatient(tPatient); + resp.setToken(token); + } + resp.setOpenid(openid); + return resp; + } + + @Override + public String loginForMp(LoginForMpReq req) { + // 查询手机号是否存在患者信息 + TPatient tPatient = new TPatient(); + BeanUtils.copyProperties(req, tPatient); + Example examplePatient = new Example(TWechatUser.class); + Example.Criteria criteriaPatient = examplePatient.createCriteria(); + criteriaPatient.andEqualTo("phone", tPatient.getPhone()); + List tPatients = tPatientMapper.selectByExample(examplePatient); + TWechatUser wechatUser = new TWechatUser(); + if (!CollectionUtils.isEmpty(tPatients)) { + // 存在 需要把患者信息更新 并绑定openid + TPatient currentPatient = tPatients.get(0); + BeanUtils.copyProperties(req, currentPatient); + tPatientMapper.updateByPrimaryKeySelective(currentPatient); + wechatUser.setUserId(currentPatient.getId()); + tPatient.setId(currentPatient.getId()); + } else { + // 不存在 患者信息入库 + tPatient.setDelFlag("0"); + tPatient.setCreateTime(new Date()); + tPatient.setUpdateTime(new Date()); + tPatientMapper.insertTPatient(tPatient); + wechatUser.setUserId(tPatient.getId()); + } + // 绑定openid + wechatUser.setOpenid(req.getOpenId()); + Example example = new Example(TWechatUser.class); + Example.Criteria criteria = example.createCriteria(); + criteria.andEqualTo("openid", wechatUser.getOpenid()); + tWechatUserMapper.updateByExampleSelective(wechatUser, example); + // 登录获取token + String token = buildTokenByPatient(tPatient); + return token; + } + + private String queryOpenid(GetOpenidReq req){ + String url = String.format(WechatKeys.MP_CODE_TO_OPENID_URL, appId, appSecret, req.getCode()); + String json = HttpUtils.sendGet(url); + JSONObject jsonObject = JSONObject.parseObject(json); + String session_key = (String) jsonObject.get("session_key"); + String openid = (String) jsonObject.get("openid"); + logger.info("login openid:{},session_key:{}", openid, session_key); + if (StringUtils.isEmpty(openid)) { + throw new ServiceException("未获取到openid"); + } + return openid; + } + + private TWechatUser updateWechatUser(String openid, GetOpenidReq req, HttpServletRequest request){ + //查询当前微信用户是否存在 + TWechatUser wechatUser = tWechatUserMapper.selectWechatUserByOpenid(openid); + if (wechatUser == null){ + wechatUser = new TWechatUser(); + wechatUser.setOpenid(openid); + wechatUser.setAvatar(req.getAvatarUrl()); + wechatUser.setNickname(req.getNickName()); + wechatUser.setLastLoginTime(new Date()); + wechatUser.setLastLoginIp(IpUtils.getIpAddr(request)); + wechatUser.setStatus((byte) 0); + tWechatUserMapper.insert(wechatUser); + + } + wechatUser.setLastLoginTime(new Date()); + wechatUser.setLastLoginIp(IpUtils.getIpAddr(request)); + tWechatUserMapper.updateByPrimaryKeySelective(wechatUser); + return wechatUser; + } + + private String buildTokenByPatient(TPatient tPatient) { + if (Objects.isNull(tPatient)) { + return StringUtils.EMPTY; + } + LoginUser loginUser = new LoginUser(); + loginUser.setUserId(tPatient.getId()); + SysUser user = new SysUser(); + user.setUserId(tPatient.getId()); + user.setDelFlag(tPatient.getDelFlag()); + user.setSex(tPatient.getSex()); + user.setPhonenumber(tPatient.getPhone()); + loginUser.setUser(user); + String token = userTokenService.createToken(loginUser); + return token; + } +} diff --git a/ruoyi-system/src/main/resources/generator/generatorConfig.xml b/ruoyi-system/src/main/resources/generator/generatorConfig.xml new file mode 100644 index 0000000..9822b61 --- /dev/null +++ b/ruoyi-system/src/main/resources/generator/generatorConfig.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
\ No newline at end of file diff --git a/ruoyi-system/src/main/resources/mapper/system/TWechatUserMapper.xml b/ruoyi-system/src/main/resources/mapper/system/TWechatUserMapper.xml new file mode 100644 index 0000000..6a0a4c5 --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/system/TWechatUserMapper.xml @@ -0,0 +1,180 @@ + + + + + + + + + + + + + + + + + + + id, last_login_time, last_login_ip, nickname, mobile, avatar, openid, unionid, status, + add_time, update_time, user_id + + + + insert into t_wechat_user (id, last_login_time, last_login_ip, + nickname, mobile, avatar, + openid, unionid, status, + add_time, update_time, user_id + ) + values (#{id,jdbcType=BIGINT}, #{lastLoginTime,jdbcType=TIMESTAMP}, #{lastLoginIp,jdbcType=VARCHAR}, + #{nickname,jdbcType=VARCHAR}, #{mobile,jdbcType=VARCHAR}, #{avatar,jdbcType=VARCHAR}, + #{openid,jdbcType=VARCHAR}, #{unionid,jdbcType=VARCHAR}, #{status,jdbcType=TINYINT}, + #{addTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP}, #{userId,jdbcType=BIGINT} + ) + + + insert into t_wechat_user + + + id, + + + last_login_time, + + + last_login_ip, + + + nickname, + + + mobile, + + + avatar, + + + openid, + + + unionid, + + + status, + + + add_time, + + + update_time, + + + user_id, + + + + + #{id,jdbcType=BIGINT}, + + + #{lastLoginTime,jdbcType=TIMESTAMP}, + + + #{lastLoginIp,jdbcType=VARCHAR}, + + + #{nickname,jdbcType=VARCHAR}, + + + #{mobile,jdbcType=VARCHAR}, + + + #{avatar,jdbcType=VARCHAR}, + + + #{openid,jdbcType=VARCHAR}, + + + #{unionid,jdbcType=VARCHAR}, + + + #{status,jdbcType=TINYINT}, + + + #{addTime,jdbcType=TIMESTAMP}, + + + #{updateTime,jdbcType=TIMESTAMP}, + + + #{userId,jdbcType=BIGINT}, + + + + + update t_wechat_user + + + last_login_time = #{lastLoginTime,jdbcType=TIMESTAMP}, + + + last_login_ip = #{lastLoginIp,jdbcType=VARCHAR}, + + + nickname = #{nickname,jdbcType=VARCHAR}, + + + mobile = #{mobile,jdbcType=VARCHAR}, + + + avatar = #{avatar,jdbcType=VARCHAR}, + + + openid = #{openid,jdbcType=VARCHAR}, + + + unionid = #{unionid,jdbcType=VARCHAR}, + + + status = #{status,jdbcType=TINYINT}, + + + add_time = #{addTime,jdbcType=TIMESTAMP}, + + + update_time = #{updateTime,jdbcType=TIMESTAMP}, + + + user_id = #{userId,jdbcType=BIGINT}, + + + where id = #{id,jdbcType=BIGINT} + + + update t_wechat_user + set last_login_time = #{lastLoginTime,jdbcType=TIMESTAMP}, + last_login_ip = #{lastLoginIp,jdbcType=VARCHAR}, + nickname = #{nickname,jdbcType=VARCHAR}, + mobile = #{mobile,jdbcType=VARCHAR}, + avatar = #{avatar,jdbcType=VARCHAR}, + openid = #{openid,jdbcType=VARCHAR}, + unionid = #{unionid,jdbcType=VARCHAR}, + status = #{status,jdbcType=TINYINT}, + add_time = #{addTime,jdbcType=TIMESTAMP}, + update_time = #{updateTime,jdbcType=TIMESTAMP}, + user_id = #{userId,jdbcType=BIGINT} + where id = #{id,jdbcType=BIGINT} + + + + \ No newline at end of file