|
@@ -0,0 +1,238 @@
|
|
|
|
|
+package com.fenzhitech.crrc.service;
|
|
|
|
|
+
|
|
|
|
|
+import com.fenzhitech.crrc.entity.SysUser;
|
|
|
|
|
+import com.fenzhitech.crrc.entity.UserIdentity;
|
|
|
|
|
+import com.fenzhitech.crrc.mapper.SysUserMapper;
|
|
|
|
|
+import com.fenzhitech.crrc.mapper.UserIdentityMapper;
|
|
|
|
|
+import com.fenzhitech.crrc.util.JwtUtil;
|
|
|
|
|
+import com.fenzhitech.crrc.util.AesUtil;
|
|
|
|
|
+import com.fenzhitech.crrc.util.Sha256Util;
|
|
|
|
|
+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.Service;
|
|
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
+
|
|
|
|
|
+import java.util.*;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * 认证服务
|
|
|
|
|
+ */
|
|
|
|
|
+@Service
|
|
|
|
|
+public class AuthService {
|
|
|
|
|
+
|
|
|
|
|
+ private static final Logger logger = LoggerFactory.getLogger(AuthService.class);
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private SysUserMapper sysUserMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private UserIdentityMapper userIdentityMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private JwtUtil jwtUtil;
|
|
|
|
|
+
|
|
|
|
|
+ @Autowired
|
|
|
|
|
+ private AesUtil aesUtil;
|
|
|
|
|
+
|
|
|
|
|
+ @Value("${auth.max-login-fail:5}")
|
|
|
|
|
+ private int maxLoginFail;
|
|
|
|
|
+
|
|
|
|
|
+ @Value("${auth.lock-duration:30}")
|
|
|
|
|
+ private int lockDuration;
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 微信登录
|
|
|
|
|
+ */
|
|
|
|
|
+ @Transactional
|
|
|
|
|
+ public Map<String, Object> wxLogin(String code) {
|
|
|
|
|
+ // TODO: 调用微信接口换取openid
|
|
|
|
|
+ String openid = getOpenidFromWechat(code);
|
|
|
|
|
+
|
|
|
|
|
+ // 查询用户
|
|
|
|
|
+ SysUser user = sysUserMapper.selectByOpenid(openid);
|
|
|
|
|
+ if (user == null) {
|
|
|
|
|
+ throw new RuntimeException("1001:未找到用户信息,请联系村委会");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查用户状态
|
|
|
|
|
+ if (user.getStatus() == 1) {
|
|
|
|
|
+ throw new RuntimeException("1004:账号已禁用");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (user.getStatus() == 2) {
|
|
|
|
|
+ throw new RuntimeException("1005:账号已锁定");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 查询用户身份
|
|
|
|
|
+ List<UserIdentity> identities = userIdentityMapper.selectByUserId(user.getId());
|
|
|
|
|
+
|
|
|
|
|
+ // 生成Token
|
|
|
|
|
+ String token = jwtUtil.generateToken(user.getId(), null, null);
|
|
|
|
|
+
|
|
|
|
|
+ // 返回结果
|
|
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
|
|
+ result.put("token", token);
|
|
|
|
|
+ result.put("userId", user.getId());
|
|
|
|
|
+ result.put("identities", convertIdentities(identities));
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 后台登录
|
|
|
|
|
+ */
|
|
|
|
|
+ @Transactional
|
|
|
|
|
+ public Map<String, Object> adminLogin(String username, String password) {
|
|
|
|
|
+ // 查询用户
|
|
|
|
|
+ SysUser user = sysUserMapper.selectByUsername(username);
|
|
|
|
|
+ if (user == null) {
|
|
|
|
|
+ throw new RuntimeException("1003:用户名或密码错误");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 检查用户状态
|
|
|
|
|
+ if (user.getStatus() == 1) {
|
|
|
|
|
+ throw new RuntimeException("1004:账号已禁用");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (user.getStatus() == 2) {
|
|
|
|
|
+ // 检查锁定时间
|
|
|
|
|
+ if (user.getLockTime() != null) {
|
|
|
|
|
+ long lockTime = user.getLockTime().getTime();
|
|
|
|
|
+ long now = System.currentTimeMillis();
|
|
|
|
|
+ if (now - lockTime < lockDuration * 60 * 1000) {
|
|
|
|
|
+ throw new RuntimeException("1005:账号已锁定,请" + lockDuration + "分钟后重试");
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 解锁
|
|
|
|
|
+ sysUserMapper.resetLoginFailCount(user.getId());
|
|
|
|
|
+ sysUserMapper.updateStatus(user.getId(), 0, null);
|
|
|
|
|
+ user.setStatus(0);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 验证密码
|
|
|
|
|
+ if (!verifyPassword(password, user.getPassword())) {
|
|
|
|
|
+ // 增加失败次数
|
|
|
|
|
+ int failCount = user.getLoginFailCount() == null ? 0 : user.getLoginFailCount();
|
|
|
|
|
+ failCount++;
|
|
|
|
|
+ sysUserMapper.updateLoginFailCount(user.getId(), failCount);
|
|
|
|
|
+
|
|
|
|
|
+ // 检查是否需要锁定
|
|
|
|
|
+ if (failCount >= maxLoginFail) {
|
|
|
|
|
+ sysUserMapper.updateStatus(user.getId(), 2, "连续登录失败" + maxLoginFail + "次");
|
|
|
|
|
+ throw new RuntimeException("1005:账号已锁定,请" + lockDuration + "分钟后重试");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ throw new RuntimeException("1003:用户名或密码错误");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 重置失败次数
|
|
|
|
|
+ sysUserMapper.resetLoginFailCount(user.getId());
|
|
|
|
|
+
|
|
|
|
|
+ // 生成Token
|
|
|
|
|
+ String token = jwtUtil.generateToken(user.getId(), username, null);
|
|
|
|
|
+
|
|
|
|
|
+ // 返回结果
|
|
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
|
|
+ result.put("token", token);
|
|
|
|
|
+ result.put("userId", user.getId());
|
|
|
|
|
+ result.put("username", user.getUsername());
|
|
|
|
|
+ result.put("realName", user.getRealName());
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 选择身份
|
|
|
|
|
+ */
|
|
|
|
|
+ public Map<String, Object> selectIdentity(Long userId, Long identityId) {
|
|
|
|
|
+ // 查询身份
|
|
|
|
|
+ UserIdentity identity = userIdentityMapper.selectById(identityId);
|
|
|
|
|
+ if (identity == null || !identity.getUserId().equals(userId)) {
|
|
|
|
|
+ throw new RuntimeException("1006:身份不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 生成新Token
|
|
|
|
|
+ String token = jwtUtil.generateToken(userId, null, identity.getId());
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
|
|
+ result.put("token", token);
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取用户信息
|
|
|
|
|
+ */
|
|
|
|
|
+ public Map<String, Object> getUserInfo(Long userId) {
|
|
|
|
|
+ SysUser user = sysUserMapper.selectById(userId);
|
|
|
|
|
+ if (user == null) {
|
|
|
|
|
+ throw new RuntimeException("用户不存在");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ List<UserIdentity> identities = userIdentityMapper.selectByUserId(userId);
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
|
|
+ result.put("userId", user.getId());
|
|
|
|
|
+ result.put("realName", user.getRealName());
|
|
|
|
|
+ result.put("phone", maskPhone(user.getPhone()));
|
|
|
|
|
+ result.put("identities", convertIdentities(identities));
|
|
|
|
|
+
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 从微信获取openid
|
|
|
|
|
+ */
|
|
|
|
|
+ private String getOpenidFromWechat(String code) {
|
|
|
|
|
+ // TODO: 实现微信接口调用
|
|
|
|
|
+ // 临时返回测试openid
|
|
|
|
|
+ return "test_openid_" + code;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 验证密码
|
|
|
|
|
+ */
|
|
|
|
|
+ private boolean verifyPassword(String rawPassword, String encodedPassword) {
|
|
|
|
|
+ // TODO: 使用BCrypt验证
|
|
|
|
|
+ return rawPassword.equals(encodedPassword);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 手机号脱敏
|
|
|
|
|
+ */
|
|
|
|
|
+ private String maskPhone(String phone) {
|
|
|
|
|
+ if (phone == null || phone.length() < 7) {
|
|
|
|
|
+ return phone;
|
|
|
|
|
+ }
|
|
|
|
|
+ return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 转换身份列表
|
|
|
|
|
+ */
|
|
|
|
|
+ private List<Map<String, Object>> convertIdentities(List<UserIdentity> identities) {
|
|
|
|
|
+ List<Map<String, Object>> list = new ArrayList<>();
|
|
|
|
|
+ for (UserIdentity identity : identities) {
|
|
|
|
|
+ Map<String, Object> map = new HashMap<>();
|
|
|
|
|
+ map.put("identityId", identity.getId());
|
|
|
|
|
+ map.put("identityType", identity.getIdentityType());
|
|
|
|
|
+ map.put("identityName", getIdentityName(identity.getIdentityType()));
|
|
|
|
|
+ list.add(map);
|
|
|
|
|
+ }
|
|
|
|
|
+ return list;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取身份名称
|
|
|
|
|
+ */
|
|
|
|
|
+ private String getIdentityName(String identityType) {
|
|
|
|
|
+ switch (identityType) {
|
|
|
|
|
+ case "GROWER": return "果农";
|
|
|
|
|
+ case "WORKER": return "工人";
|
|
|
|
|
+ case "BUYER": return "客商";
|
|
|
|
|
+ case "SUPPLIER": return "农资商";
|
|
|
|
|
+ default: return identityType;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|