diff --git a/server/like-common/pom.xml b/server/like-common/pom.xml index 51d6ab22..cc752636 100644 --- a/server/like-common/pom.xml +++ b/server/like-common/pom.xml @@ -145,6 +145,12 @@ com.github.oshi oshi-core + + + com.github.binarywang + weixin-java-miniapp + 4.4.0 + \ No newline at end of file diff --git a/server/like-common/src/main/java/com/mdd/common/entity/user/User.java b/server/like-common/src/main/java/com/mdd/common/entity/user/User.java index 52ed3fac..e805f1ea 100644 --- a/server/like-common/src/main/java/com/mdd/common/entity/user/User.java +++ b/server/like-common/src/main/java/com/mdd/common/entity/user/User.java @@ -16,13 +16,14 @@ public class User implements Serializable { @TableId(value="id", type= IdType.AUTO) private Integer id; // 主键 - private String sn; // 编号 + private Integer sn; // 编号 private String avatar; // 用户头像 private String realName; // 真实姓名 private String nickname; // 用户昵称 private String username; // 用户账号 private String password; // 用户密码 private String mobile; // 用户电话 + private Integer channel; // 注册渠道 private String salt; // 加密盐巴 private Integer sex; // 用户性别: [1=男, 2=女] private Integer is_delete; // 是否删除: [0=否, 1=是] diff --git a/server/like-common/src/main/java/com/mdd/common/entity/user/UserAuth.java b/server/like-common/src/main/java/com/mdd/common/entity/user/UserAuth.java new file mode 100644 index 00000000..fd512596 --- /dev/null +++ b/server/like-common/src/main/java/com/mdd/common/entity/user/UserAuth.java @@ -0,0 +1,26 @@ +package com.mdd.common.entity.user; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; + +import java.io.Serializable; + +/** + * 用户授权实体 + */ +@Data +public class UserAuth implements Serializable { + + private static final long serialVersionUID = 1L; + + @TableId(value="id", type= IdType.AUTO) + private Integer id; // 主键 + private Integer userId; // 用户Id + private String openid; // Openid + private String unionid; // Unionid + private Integer client; // 客户端类型: [1=微信小程序, 2=微信公众号, 3=手机H5;4=电脑PC, 5=苹果APP, 6=安卓APP] + private Long createTime; // 创建时间 + private Long updateTime; // 更新时间 + +} diff --git a/server/like-common/src/main/java/com/mdd/common/enums/ClientEnum.java b/server/like-common/src/main/java/com/mdd/common/enums/ClientEnum.java new file mode 100644 index 00000000..4158689b --- /dev/null +++ b/server/like-common/src/main/java/com/mdd/common/enums/ClientEnum.java @@ -0,0 +1,79 @@ +package com.mdd.common.enums; + +/** + * 客户端枚举类 + */ +public enum ClientEnum { + + MNP(1, "微信小程序"), + OA(2, "微信公众号"), + H5(3, "手机H5"), + PC(4, "电脑PC"), + IOS(5, "苹果APP"), + APK(5, "安卓APP"); + + /** + * 构造方法 + */ + private final int code; + private final String msg; + ClientEnum(int code, String msg) { + this.code = code; + this.msg = msg; + } + + /** + * 根据类型获取Code + * + * @author fzr + * @param type 类型 + * @return Integer + */ + public static Integer getCodeByType(String type){ + for(ClientEnum enumItem: ClientEnum.values()) { + if (enumItem.toString().equals(type.toUpperCase())) { + return enumItem.getCode(); + } + } + return null; + } + + /** + * 根据类型获取Msg + * + * @author fzr + * @param type 类型 + * @return String + */ + public static String getMsgByType(String type){ + for(ClientEnum enumItem: ClientEnum.values()) { + if (enumItem.toString().equals(type)) { + return enumItem.getMsg(); + } + } + return null; + } + + + + /** + * 获取状态码 + * + * @author fzr + * @return Long + */ + public int getCode() { + return this.code; + } + + /** + * 获取提示 + * + * @author fzr + * @return String + */ + public String getMsg() { + return this.msg; + } + +} diff --git a/server/like-common/src/main/java/com/mdd/common/mapper/user/UserAuthMapper.java b/server/like-common/src/main/java/com/mdd/common/mapper/user/UserAuthMapper.java new file mode 100644 index 00000000..49b4511c --- /dev/null +++ b/server/like-common/src/main/java/com/mdd/common/mapper/user/UserAuthMapper.java @@ -0,0 +1,12 @@ +package com.mdd.common.mapper.user; + +import com.mdd.common.core.basics.IBaseMapper; +import com.mdd.common.entity.user.UserAuth; +import org.apache.ibatis.annotations.Mapper; + +/** + * 用户授权Mapper + */ +@Mapper +public interface UserAuthMapper extends IBaseMapper { +} diff --git a/server/like-common/src/main/java/com/mdd/common/plugin/wechat/WechatDriver.java b/server/like-common/src/main/java/com/mdd/common/plugin/wechat/WechatDriver.java deleted file mode 100644 index 22f76712..00000000 --- a/server/like-common/src/main/java/com/mdd/common/plugin/wechat/WechatDriver.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.mdd.common.plugin.wechat; - -public class WechatDriver { -} diff --git a/server/like-front/src/main/java/com/mdd/front/controller/LoginController.java b/server/like-front/src/main/java/com/mdd/front/controller/LoginController.java new file mode 100644 index 00000000..c5a8cc98 --- /dev/null +++ b/server/like-front/src/main/java/com/mdd/front/controller/LoginController.java @@ -0,0 +1,56 @@ +package com.mdd.front.controller; + +import com.baomidou.mybatisplus.core.toolkit.Assert; +import com.mdd.common.core.AjaxResult; +import com.mdd.common.enums.ClientEnum; +import com.mdd.front.service.ILoginService; +import com.mdd.front.validate.RegisterParam; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.LinkedHashMap; +import java.util.Map; + +@RestController +@RequestMapping("/api/login") +public class LoginController { + + @Resource + ILoginService iLoginService; + + /** + * 注册账号 + * + * @author fzr + * @param registerParam 参数 + * @return Object + */ + @PostMapping("/register") + public Object register(@Validated @RequestBody RegisterParam registerParam) { + iLoginService.register(registerParam); + return AjaxResult.success(); + } + + @PostMapping("/check") + public Object check(@RequestBody Map params) { + Assert.notNull(params.get("scene"), "scene参数缺失!"); + + Map map = new LinkedHashMap<>(); + switch (params.get("scene")) { + case "mnp": + map = iLoginService.mnpLogin(params); + break; + case "sms": + Assert.isNull(params.get("code"), "code参数缺失!"); + iLoginService.smsLogin(params); + break; + case "account": + iLoginService.accountLogin(params); + break; + } + + return AjaxResult.success(map); + } + +} diff --git a/server/like-front/src/main/java/com/mdd/front/service/ILoginService.java b/server/like-front/src/main/java/com/mdd/front/service/ILoginService.java new file mode 100644 index 00000000..36aafd20 --- /dev/null +++ b/server/like-front/src/main/java/com/mdd/front/service/ILoginService.java @@ -0,0 +1,34 @@ +package com.mdd.front.service; + +import com.mdd.front.validate.RegisterParam; + +import java.util.Map; + +/** + * 登录服务接口类 + */ +public interface ILoginService { + + /** + * 账号注册 + * + * @author fzr + * @param registerParam 参数 + */ + void register(RegisterParam registerParam); + + /** + * 微信小程序登录 + * + * @author fzr + * @param scene 场景 + * @param code 编码 + */ + Map mnpLogin(Map params); + + void smsLogin(Map params); + + void accountLogin(Map params); + + void forgotPassword(Map params); +} diff --git a/server/like-front/src/main/java/com/mdd/front/service/impl/LoginServiceImpl.java b/server/like-front/src/main/java/com/mdd/front/service/impl/LoginServiceImpl.java new file mode 100644 index 00000000..110a036c --- /dev/null +++ b/server/like-front/src/main/java/com/mdd/front/service/impl/LoginServiceImpl.java @@ -0,0 +1,210 @@ +package com.mdd.front.service.impl; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl; +import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult; +import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Assert; +import com.mdd.common.entity.user.User; +import com.mdd.common.entity.user.UserAuth; +import com.mdd.common.enums.ClientEnum; +import com.mdd.common.exception.OperateException; +import com.mdd.common.mapper.user.UserAuthMapper; +import com.mdd.common.mapper.user.UserMapper; +import com.mdd.common.utils.ConfigUtil; +import com.mdd.common.utils.IpUtil; +import com.mdd.common.utils.StringUtil; +import com.mdd.common.utils.ToolsUtil; +import com.mdd.front.service.ILoginService; +import com.mdd.front.validate.RegisterParam; +import me.chanjar.weixin.common.error.WxErrorException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * 登录服务实现类 + */ +@Service +public class LoginServiceImpl implements ILoginService { + + @Resource + UserMapper userMapper; + + @Resource + UserAuthMapper userAuthMapper; + + + /** + * 注册账号 + * + * @author fzr + * @param registerParam 参数 + */ + @Override + public void register(RegisterParam registerParam) { + User model = userMapper.selectOne(new QueryWrapper() + .select("id,sn,username") + .eq("username", registerParam.getUsername()) + .eq("is_delete", 0) + .last("limit 1")); + + Assert.isNull(model, "账号已存在,换一个吧!"); + + Integer sn = this.randMakeSn(); + String salt = ToolsUtil.randomString(5); + String pwd = ToolsUtil.makeMd5(registerParam.getPassword()+salt); + + User user = new User(); + user.setSn(sn); + user.setNickname("用户"+sn); + user.setUsername(registerParam.getUsername()); + user.setPassword(pwd); + user.setSalt(salt); + user.setChannel(0); + user.setCreateTime(System.currentTimeMillis() / 1000); + user.setUpdateTime(System.currentTimeMillis() / 1000); + userMapper.insert(user); + } + + /** + * 微信小程序登录 + * + * @author fzr + * @param params 参数 + * @return Map + */ + @Override + @Transactional + public Map mnpLogin(Map params) { + Assert.notNull(params.get("code"), "code参数缺失!"); + String scene = params.get("scene"); + String code = params.get("code"); + String avatarUrl = params.getOrDefault("avatarUrl", ""); + String nickName = params.getOrDefault("nickName", ""); + String gender = params.getOrDefault("gender", "0"); + Integer client = ClientEnum.getCodeByType(scene); + + Map config = ConfigUtil.get("mp_channel"); + WxMaService wxMaService = new WxMaServiceImpl(); + WxMaDefaultConfigImpl wxConfig = new WxMaDefaultConfigImpl(); + wxConfig.setAppid(config.getOrDefault("appId", "")); + wxConfig.setSecret(config.getOrDefault("appSecret", "")); + wxMaService.setWxMaConfig(wxConfig); + + try { + WxMaJscode2SessionResult sessionResult = wxMaService.getUserService().getSessionInfo(code); + String openId = sessionResult.getOpenid(); + String unionId = sessionResult.getUnionid(); + + UserAuth userAuth = userAuthMapper.selectOne(new QueryWrapper() + .eq("client", client) + .nested(wq->wq + .eq("openid", openId).or() + .eq("unionid", unionId) + ).last("limit 1")); + + User user = null; + Integer userId; + if (StringUtil.isNotNull(userAuth)) { + user = userMapper.selectOne(new QueryWrapper() + .eq("id", userAuth.getUserId()) + .eq("is_delete", 0) + .last("limit 1")); + } + + if (StringUtil.isNull(user)) { + Integer sn = this.randMakeSn(); + User model = new User(); + model.setSn(sn); + model.setAvatar(avatarUrl); + model.setNickname(nickName.equals("")?"用户"+sn:nickName); + model.setUsername("u"+sn); + model.setSex(Integer.parseInt(gender)); + model.setChannel(client); + model.setLastLoginIp(IpUtil.getHostIp()); + model.setLastLoginTime(System.currentTimeMillis() / 1000); + model.setCreateTime(System.currentTimeMillis() / 1000); + model.setUpdateTime(System.currentTimeMillis() / 1000); + userMapper.insert(model); + userId = model.getId(); + + UserAuth auth = new UserAuth(); + auth.setUserId(model.getId()); + auth.setOpenid(openId); + auth.setUnionid(unionId); + auth.setClient(client); + auth.setCreateTime(System.currentTimeMillis() / 1000); + auth.setUpdateTime(System.currentTimeMillis() / 1000); + userAuthMapper.insert(auth); + } else { + // 更新微信标识 + userId = user.getId(); + if (StringUtil.isEmpty(userAuth.getUnionid()) && StringUtil.isNotEmpty(sessionResult.getUnionid())) { + userAuth.setUnionid(sessionResult.getUnionid()); + userAuthMapper.updateById(userAuth); + } + + // 更新用户信息 + if (StringUtil.isEmpty(user.getAvatar()) && StringUtil.isNotEmpty(avatarUrl)) { + user.setAvatar(avatarUrl); + user.setNickname(nickName); + user.setSex(Integer.parseInt(gender)); + } + + // 更新登录信息 + user.setLastLoginIp(IpUtil.getHostIp()); + user.setLastLoginTime(System.currentTimeMillis() / 1000); + userMapper.updateById(user); + } + + String token = ToolsUtil.makeToken(); + Map response = new LinkedHashMap<>(); + response.put("id", userId); + response.put("token", token); + return response; + } catch (WxErrorException e) { + throw new OperateException(e.getError().getErrorCode() + ", " + e.getError().getErrorMsg()); + } + } + + @Override + public void smsLogin(Map params) { + + } + + @Override + public void accountLogin(Map params) { + + } + + @Override + public void forgotPassword(Map params) { + + } + + /** + * 生成用户编号 + * + * @author fzr + * @return Integer + */ + private Integer randMakeSn() { + Integer sn; + while (true) { + sn = Integer.parseInt(ToolsUtil.randomInt(8)); + User snModel = userMapper.selectOne(new QueryWrapper() + .select("id,sn,username") + .eq("sn", sn) + .last("limit 1")); + if (snModel == null) { + break; + } + } + return sn; + } +} diff --git a/server/like-front/src/main/java/com/mdd/front/validate/RegisterParam.java b/server/like-front/src/main/java/com/mdd/front/validate/RegisterParam.java new file mode 100644 index 00000000..6bd3358d --- /dev/null +++ b/server/like-front/src/main/java/com/mdd/front/validate/RegisterParam.java @@ -0,0 +1,35 @@ +package com.mdd.front.validate; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.experimental.Accessors; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import java.io.Serializable; + +/** + * 注册参数类 + */ +@Data +@EqualsAndHashCode(callSuper = false) +@Accessors(chain = true) +public class RegisterParam implements Serializable { + + private static final long serialVersionUID = 1L; + + @NotNull(message = "username参数缺失") + @NotEmpty(message = "账号不能为空") + @Length(min = 3, max = 12, message = "账号必须在3~12个字符内") + @Pattern(message = "账号只允许是字母和数字", regexp="^[A-Za-z0-9]+$") + @Pattern(message = "账号应该为3-12位字母、数字组合", regexp="^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{3,12}$") + private String username; + + @NotNull(message = "password参数缺失") + @NotEmpty(message = "密码不能为空") + @Length(min = 6, max = 12, message = "密码必须在6~12个字符内") + private String password; + +}