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;
+
+}