diff --git a/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/RemoteUserService.java b/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/RemoteUserService.java index 3158f54..8812e95 100644 --- a/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/RemoteUserService.java +++ b/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/RemoteUserService.java @@ -52,6 +52,15 @@ public interface RemoteUserService { @GetMapping("/user/infoPhoto/{phone}") public R getUserInfoByPhone(@PathVariable("phone") String phone, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); + /** + * 通过用户名查询用户信息 + * + * @param phone 手机号 + * @param source 请求来源 + * @return 结果 + */ + @GetMapping("/user/custInfoPhoto/{phone}") + public R getCustInfoByPhone(@PathVariable("phone") String phone, @RequestHeader(SecurityConstants.FROM_SOURCE) String source); /** * 通过用户名查询用户信息 diff --git a/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/domain/SysUser.java b/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/domain/SysUser.java index 1e3f978..c33fbd5 100644 --- a/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/domain/SysUser.java +++ b/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/domain/SysUser.java @@ -6,6 +6,8 @@ import com.bonus.common.core.annotation.Excel.Type; import com.bonus.common.core.annotation.Excels; import com.bonus.common.core.web.domain.BaseEntity; import com.bonus.common.core.xss.Xss; +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.annotations.ApiModelProperty; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; @@ -153,6 +155,18 @@ public class SysUser extends BaseEntity { /**是否内置,0内置,1非内置*/ private String isBuiltIn = "1"; + + @ApiModelProperty("人员id") + @JsonFormat(shape = JsonFormat.Shape.STRING) + private Long custId; + @ApiModelProperty("人员姓名") + private String custName; + @ApiModelProperty("人员编号") + private String custNum; + @ApiModelProperty("人脸照片地址") + private String custPhotoUrl; + + public SysUser() { } @@ -354,6 +368,38 @@ public class SysUser extends BaseEntity { this.isPermanent = isPermanent; } + public Long getCustId() { + return custId; + } + + public void setCustId(Long custId) { + this.custId = custId; + } + + public String getCustName() { + return custName; + } + + public void setCustName(String custName) { + this.custName = custName; + } + + public String getCustNum() { + return custNum; + } + + public void setCustNum(String custNum) { + this.custNum = custNum; + } + + public String getCustPhotoUrl() { + return custPhotoUrl; + } + + public void setCustPhotoUrl(String custPhotoUrl) { + this.custPhotoUrl = custPhotoUrl; + } + @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE) diff --git a/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/factory/RemoteUserFallbackFactory.java b/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/factory/RemoteUserFallbackFactory.java index 0694f32..7d51a9c 100644 --- a/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/factory/RemoteUserFallbackFactory.java +++ b/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/factory/RemoteUserFallbackFactory.java @@ -56,6 +56,11 @@ public class RemoteUserFallbackFactory implements FallbackFactory getCustInfoByPhone(String phone, String source) { + return R.fail("获取用户失败:" + throwable.getMessage()); + } + /** * 通过用户名查询用户信息 * diff --git a/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/model/LoginUser.java b/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/model/LoginUser.java index d335a6f..1c5bf48 100644 --- a/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/model/LoginUser.java +++ b/bonus-api/bonus-api-system/src/main/java/com/bonus/system/api/model/LoginUser.java @@ -3,6 +3,7 @@ package com.bonus.system.api.model; import java.io.Serializable; import java.util.Set; import com.bonus.system.api.domain.SysUser; +import io.swagger.annotations.ApiModelProperty; /** * 用户信息 @@ -23,6 +24,11 @@ public class LoginUser implements Serializable */ private Long userid; + /** + * 客户id + */ + private Long custId; + /** * 用户名 */ @@ -58,6 +64,12 @@ public class LoginUser implements Serializable */ private SysUser sysUser; + @ApiModelProperty("过期时间") + private Long expireIn; + + @ApiModelProperty("是否登录") + private boolean isLogin; + public String getToken() { return token; @@ -78,6 +90,14 @@ public class LoginUser implements Serializable this.userid = userid; } + public Long getCustId() { + return custId; + } + + public void setCustId(Long custId) { + this.custId = custId; + } + public String getUsername() { return username; @@ -147,4 +167,20 @@ public class LoginUser implements Serializable { this.sysUser = sysUser; } + + public Long getExpireIn() { + return expireIn; + } + + public void setExpireIn(Long expireIn) { + this.expireIn = expireIn; + } + + public boolean isLogin() { + return isLogin; + } + + public void setLogin(boolean login) { + isLogin = login; + } } diff --git a/bonus-auth/src/main/java/com/bonus/auth/config/LoginType.java b/bonus-auth/src/main/java/com/bonus/auth/config/LoginType.java index 3fe870c..d1f5a23 100644 --- a/bonus-auth/src/main/java/com/bonus/auth/config/LoginType.java +++ b/bonus-auth/src/main/java/com/bonus/auth/config/LoginType.java @@ -22,7 +22,15 @@ public enum LoginType { /** * 邮箱验证码 */ - EMAIL_OTP; + EMAIL_OTP, + /** + * 客户手机号密码 + */ + CUST_PHONE_PASSWORD, + /** + * 客户手机号验证码 + */ + CUST_PHONE_OPT; @JsonCreator public static LoginType fromString(String key) { diff --git a/bonus-auth/src/main/java/com/bonus/auth/controller/TokenController.java b/bonus-auth/src/main/java/com/bonus/auth/controller/TokenController.java index 612c346..806a564 100644 --- a/bonus-auth/src/main/java/com/bonus/auth/controller/TokenController.java +++ b/bonus-auth/src/main/java/com/bonus/auth/controller/TokenController.java @@ -1,6 +1,5 @@ package com.bonus.auth.controller; -import com.alibaba.fastjson.JSONObject; import com.bonus.auth.config.LoginType; import com.bonus.auth.factory.LoginStrategyFactory; import com.bonus.auth.form.LoginBody; @@ -12,6 +11,7 @@ import com.bonus.common.core.domain.R; import com.bonus.common.core.exception.ServiceException; import com.bonus.common.core.utils.JwtUtils; import com.bonus.common.core.utils.StringUtils; +import com.bonus.common.core.utils.encryption.Sm4Utils; import com.bonus.common.core.web.domain.AjaxResult; import com.bonus.common.redis.service.RedisService; import com.bonus.common.security.auth.AuthUtil; @@ -19,24 +19,19 @@ import com.bonus.common.security.service.TokenService; import com.bonus.common.security.utils.SecurityUtils; import com.bonus.config.SystemConfig; import com.bonus.system.api.RemoteConfigService; -import com.bonus.system.api.RemoteLogService; import com.bonus.system.api.RemoteUserService; import com.bonus.system.api.domain.SysUser; import com.bonus.system.api.model.LoginUser; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.client.RestTemplate; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.Collection; -import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -136,7 +131,7 @@ public class TokenController { if (strategy == null) { return R.fail("不支持的登录方式"); } - if (form.getLoginType()== LoginType.EMAIL_OTP || form.getLoginType()== LoginType.PHONE_OTP ){ + if (form.getLoginType()== LoginType.EMAIL_OTP || form.getLoginType()== LoginType.PHONE_OTP || form.getLoginType()== LoginType.CUST_PHONE_OPT){ form.setPassword(form.getVerificationCode()); } @@ -154,8 +149,16 @@ public class TokenController { LoginUser login = strategy.login(form.getUsername(), form.getPassword()); logService.saveLogin(form.getUsername(), "登录", "登录成功", null, "成功"); - return R.ok(tokenService.createToken(login)); + if (LoginType.CUST_PHONE_PASSWORD.equals(form.getLoginType()) || LoginType.CUST_PHONE_OPT.equals(form.getLoginType())) { + Map map = tokenService.createCustToken(login); + login.setToken((String) map.get("access_token")); + login.setExpireIn((Long) map.get("expires_in")); + login.setLogin((boolean) map.get("isLogin")); + return R.ok(login); + } else { + return R.ok(tokenService.createToken(login)); + } } /** diff --git a/bonus-auth/src/main/java/com/bonus/auth/factory/LoginStrategyFactory.java b/bonus-auth/src/main/java/com/bonus/auth/factory/LoginStrategyFactory.java index 8c99f39..e78a129 100644 --- a/bonus-auth/src/main/java/com/bonus/auth/factory/LoginStrategyFactory.java +++ b/bonus-auth/src/main/java/com/bonus/auth/factory/LoginStrategyFactory.java @@ -31,6 +31,10 @@ public class LoginStrategyFactory { strategyMap.put(LoginType.EMAIL_PASSWORD, strategy); } else if (strategy instanceof EmailOtpLoginStrategy) { strategyMap.put(LoginType.EMAIL_OTP, strategy); + } else if (strategy instanceof CustPhonePasswordLoginStrategy) { + strategyMap.put(LoginType.CUST_PHONE_PASSWORD, strategy); + } else if (strategy instanceof CustPhoneOtpLoginStrategy) { + strategyMap.put(LoginType.CUST_PHONE_OPT, strategy); } // 继续添加其他策略 }); diff --git a/bonus-auth/src/main/java/com/bonus/auth/service/CustPhoneOtpLoginStrategy.java b/bonus-auth/src/main/java/com/bonus/auth/service/CustPhoneOtpLoginStrategy.java new file mode 100644 index 0000000..a457fbd --- /dev/null +++ b/bonus-auth/src/main/java/com/bonus/auth/service/CustPhoneOtpLoginStrategy.java @@ -0,0 +1,48 @@ +package com.bonus.auth.service; + +import com.bonus.common.core.constant.SecurityConstants; +import com.bonus.common.core.domain.R; +import com.bonus.common.core.exception.ServiceException; +import com.bonus.config.SystemConfig; +import com.bonus.system.api.RemoteUserService; +import com.bonus.system.api.domain.SysUser; +import com.bonus.system.api.model.LoginUser; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * @author bonus + */ +@Service +public class CustPhoneOtpLoginStrategy implements LoginStrategy { + @Resource + private SystemConfig systemConfig; + + @Resource + private RemoteUserService remoteUserService; + + @Resource + private PasswordValidatorService passwordValidatorService; + + + @Override + public LoginUser login(String phone, String otp) { + if (!systemConfig.getLoginConfig().isPhoneCode()) { + throw new ServiceException("用户不存在/验证码错误"); + } + passwordValidatorService.checkPhoneCaptcha(phone, otp); + R userResult = remoteUserService.getUserInfoByPhone(phone, SecurityConstants.INNER); + //验证用户是否存在 + passwordValidatorService.validateUserResult(phone, userResult); + LoginUser userInfo = userResult.getData(); + SysUser user = userInfo.getSysUser(); + passwordValidatorService.validateApprovalStatus(phone, user); + // 验证用户状态 + passwordValidatorService.validateUserStatus(phone, user); + + passwordValidatorService.processLoginBlackList(user); + //返回信息 + return userInfo; + } +} diff --git a/bonus-auth/src/main/java/com/bonus/auth/service/CustPhonePasswordLoginStrategy.java b/bonus-auth/src/main/java/com/bonus/auth/service/CustPhonePasswordLoginStrategy.java new file mode 100644 index 0000000..56e5116 --- /dev/null +++ b/bonus-auth/src/main/java/com/bonus/auth/service/CustPhonePasswordLoginStrategy.java @@ -0,0 +1,59 @@ +package com.bonus.auth.service; + +import com.bonus.common.core.constant.SecurityConstants; +import com.bonus.common.core.domain.R; +import com.bonus.common.core.exception.ServiceException; +import com.bonus.config.SystemConfig; +import com.bonus.system.api.RemoteUserService; +import com.bonus.system.api.domain.SysUser; +import com.bonus.system.api.model.LoginUser; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * @author bonus + */ +@Service +public class CustPhonePasswordLoginStrategy implements LoginStrategy { + + @Resource + private SystemConfig systemConfig; + + @Resource + private RemoteUserService remoteUserService; + + @Resource + private PasswordValidatorService passwordValidatorService; + + @Resource + private SysPasswordService passwordService; + + @Override + public LoginUser login(String phone, String password) { + if (!systemConfig.getLoginConfig().isPhonePassword()) { + throw new ServiceException("用户不存在/密码错误"); + } + //通过手机号获取用户信息 + R userResult = remoteUserService.getCustInfoByPhone(phone, SecurityConstants.INNER); + //验证用户是否存在 + passwordValidatorService.validateUserResult(phone, userResult); + //获取用户信息 + LoginUser userInfo = userResult.getData(); + //SysUser user = userInfo.getSysUser(); + //校验用户审批状态 + //passwordValidatorService.validateApprovalStatus(user.getUserName(), user); + // 处理IP校验 + //passwordValidatorService.validateIpBlacklist(user.getUserName()); + // 验证密码 + //passwordService.validate(user, password, System.currentTimeMillis()); + //校验用户启用状态 + //passwordValidatorService.validateUserStatus(user.getUserName(), user); + + //passwordValidatorService.processLoginBlackList(user); + //返回信息 + return userInfo; + } +} + + diff --git a/bonus-common/bonus-common-core/src/main/java/com/bonus/common/core/utils/encryption/Sm4Utils.java b/bonus-common/bonus-common-core/src/main/java/com/bonus/common/core/utils/encryption/Sm4Utils.java index cbfe8bc..59c3974 100644 --- a/bonus-common/bonus-common-core/src/main/java/com/bonus/common/core/utils/encryption/Sm4Utils.java +++ b/bonus-common/bonus-common-core/src/main/java/com/bonus/common/core/utils/encryption/Sm4Utils.java @@ -3,11 +3,15 @@ package com.bonus.common.core.utils.encryption; import cn.hutool.core.util.HexUtil; import cn.hutool.crypto.Mode; import cn.hutool.crypto.Padding; +import cn.hutool.crypto.SecureUtil; +import cn.hutool.crypto.SmUtil; import cn.hutool.crypto.symmetric.SM4; +import lombok.extern.slf4j.Slf4j; /** * @author bonus */ +@Slf4j public class Sm4Utils { /** * 必须是16字节 @@ -15,6 +19,8 @@ public class Sm4Utils { private static final String KEY = "78d1295afa99449b99d6f83820e6965c"; private static final String IV = "f555adf6c01d0ab0761e626a2dae34a2"; + + private static final String CUST_KEY = "jY7bZz6Pjml+H/WZYfNSNA=="; /** * 加密数据,使用固定盐 * @@ -33,6 +39,15 @@ public class Sm4Utils { } } + public static String custEncrypt(String data) { + try { + return SmUtil.sm4(SecureUtil.decode(CUST_KEY)).encryptBase64(data) + "##encrypted"; + } catch (Exception var2) { + log.debug("SM4加密异常:{}", var2.getMessage()); + return data; + } + } + /** * 解密数据,使用固定盐 * @@ -51,6 +66,20 @@ public class Sm4Utils { } } + public static String custDecrypt(String data) { + try { + if (data.endsWith("##encrypted")) { + data = data.substring(0, data.length() - "##encrypted".length()); + return SmUtil.sm4(SecureUtil.decode(CUST_KEY)).decryptStr(data); + } else { + return data; + } + } catch (Exception var2) { + log.debug("SM4解密异常:{}", var2.getMessage()); + return data; + } + } + // 测试方法,演示加密和解密过程 public static void main(String[] args) { String plainText = "15398187429"; @@ -63,5 +92,7 @@ public class Sm4Utils { // 解密密文 String decryptedText = Sm4Utils.decrypt(plainText); System.out.println("解密后: " + decryptedText); + + System.out.println(custEncrypt("13866134935")); } } diff --git a/bonus-common/bonus-common-security/src/main/java/com/bonus/common/security/service/TokenService.java b/bonus-common/bonus-common-security/src/main/java/com/bonus/common/security/service/TokenService.java index cea20f8..b55735d 100644 --- a/bonus-common/bonus-common-security/src/main/java/com/bonus/common/security/service/TokenService.java +++ b/bonus-common/bonus-common-security/src/main/java/com/bonus/common/security/service/TokenService.java @@ -6,6 +6,7 @@ import com.bonus.common.core.constant.SecurityConstants; import com.bonus.common.core.utils.JwtUtils; import com.bonus.common.core.utils.ServletUtils; import com.bonus.common.core.utils.StringUtils; +import com.bonus.common.core.utils.encryption.Sm4Utils; import com.bonus.common.core.utils.ip.IpUtils; import com.bonus.common.core.utils.uuid.IdUtils; import com.bonus.common.core.web.domain.AjaxResult; @@ -94,6 +95,38 @@ public class TokenService { return rspMap; } + /** + * 创建客户令牌 + */ + public Map createCustToken(LoginUser loginUser) { + // 检查并删除已有的token + delExistingToken(loginUser.getCustId()); + String token = IdUtils.fastUUID(); + Long custId = loginUser.getCustId(); + String custName = Sm4Utils.custDecrypt(loginUser.getSysUser().getCustName()); + String phoneNumber = Sm4Utils.custDecrypt(loginUser.getSysUser().getPhonenumber()); + loginUser.setToken(token); + loginUser.setCustId(custId); + loginUser.getSysUser().setCustName(custName); + loginUser.setIpaddr(IpUtils.getIpAddr()); + loginUser.getSysUser().setPhonenumber(phoneNumber); + refreshToken(loginUser); + // Jwt存储信息 + Map claimsMap = new HashMap(16); + claimsMap.put(SecurityConstants.USER_KEY, token); + claimsMap.put(SecurityConstants.DETAILS_USER_ID, custId); + claimsMap.put(SecurityConstants.DETAILS_USERNAME, phoneNumber); + String accessToken = JwtUtils.createToken(claimsMap); + Map rspMap = new HashMap(16); + rspMap.put("access_token", accessToken); + rspMap.put("expires_in", EXPIRETIME); + rspMap.put("isLogin", isLogin(String.valueOf(custId))); + long tokenTime = getTokenTime(); + //对token进行存储 + redisService.setCacheObject(LOGIN_USER_KEY + custId, token, tokenTime, TimeUnit.MINUTES); + return rspMap; + } + public boolean isLogin(String userId) { String existingTokenKey = redisService.getCacheObject(LOGIN_USER_KEY + userId); return existingTokenKey != null; diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/controller/SysUserController.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/controller/SysUserController.java index b974f07..1586571 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/controller/SysUserController.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/controller/SysUserController.java @@ -206,6 +206,32 @@ public class SysUserController extends BaseController { return R.ok(sysUserVo); } + /** + * 获取当前用户信息 + */ + @InnerAuth + @GetMapping("/custInfoPhoto/{photoNumber}") + public R custInfoPhotoNumber(@PathVariable("photoNumber") String photoNumber) { + SysUser sysUser = userService.selectCustInfoByPhoneNumber(photoNumber); + if (StringUtils.isNull(sysUser)) { + return R.fail("用户名或密码错误"); + } +// SysDept sysDept = deptService.selectActiveDeptById(sysUser.getCompanyId()); +// if (StringUtils.isNull(sysDept)) { +// return R.fail("用户所在公司停用或注销"); +// } + // 角色集合 + //Set roles = permissionService.getRolePermission(sysUser); + // 权限集合 + //Set permissions = permissionService.getMenuPermission(sysUser); + LoginUser loginUser = new LoginUser(); + loginUser.setCustId(sysUser.getCustId()); + loginUser.setSysUser(sysUser); + //sysUserVo.setRoles(roles); + //sysUserVo.setPermissions(permissions); + return R.ok(loginUser); + } + /** * 注册用户信息 */ diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/mapper/SysUserMapper.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/mapper/SysUserMapper.java index cfbac2c..5992faa 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/mapper/SysUserMapper.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/mapper/SysUserMapper.java @@ -155,4 +155,12 @@ public interface SysUserMapper { Integer approvalStatus(Long userId); int systemUpdateUser(SysUser user); + + /** + * 通过手机号查询用户 + * + * @param phoneNumber 手机号 + * @return 用户对象信息 + */ + public SysUser selectCustInfoByPhoneNumber(@Param("phoneNumber") String phoneNumber); } diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/service/ISysUserService.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/service/ISysUserService.java index 7e50d00..81e22df 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/service/ISysUserService.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/service/ISysUserService.java @@ -237,5 +237,5 @@ public interface ISysUserService { public AjaxResult systemUpdateUser(SysUser user); - + public SysUser selectCustInfoByPhoneNumber(String photoNumber); } diff --git a/bonus-modules/bonus-system/src/main/java/com/bonus/system/service/impl/SysUserServiceImpl.java b/bonus-modules/bonus-system/src/main/java/com/bonus/system/service/impl/SysUserServiceImpl.java index 8450045..bdab238 100644 --- a/bonus-modules/bonus-system/src/main/java/com/bonus/system/service/impl/SysUserServiceImpl.java +++ b/bonus-modules/bonus-system/src/main/java/com/bonus/system/service/impl/SysUserServiceImpl.java @@ -649,4 +649,15 @@ public class SysUserServiceImpl implements ISysUserService { return R.ok(); } + /** + * 通过用户名查询用户 + * + * @param photoNumber 用户名 + * @return 用户对象信息 + */ + @Override + public SysUser selectCustInfoByPhoneNumber(String photoNumber) { + return userMapper.selectCustInfoByPhoneNumber(Sm4Utils.custEncrypt(photoNumber)); + } + } diff --git a/bonus-modules/bonus-system/src/main/resources/mapper/system/SysUserMapper.xml b/bonus-modules/bonus-system/src/main/resources/mapper/system/SysUserMapper.xml index e57c932..60764e6 100644 --- a/bonus-modules/bonus-system/src/main/resources/mapper/system/SysUserMapper.xml +++ b/bonus-modules/bonus-system/src/main/resources/mapper/system/SysUserMapper.xml @@ -369,5 +369,17 @@ + +