Commit 9f09b5c2 by weisong
parents 7038be6d 8143c904
......@@ -106,6 +106,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>
</dependencies>
......
package com.cnooc.expert.auth.service;
import com.cnooc.expert.system.entity.vo.LoginVO;
import com.cnooc.expert.system.entity.vo.VerifyCodeVO;
public interface LoginService {
String login(LoginVO loginVO);
String sendPhoneCode(LoginVO vo);
String changePass(LoginVO loginVO);
String verifyCode(VerifyCodeVO codeVO);
}
package com.cnooc.expert.auth.service;
public interface SmsService {
/**
* 校验短信验证码
*
* @param phone 手机号
* @param code 验证码
* @return 是否校验通过
*/
boolean verifySmsCode(String phone, String code);
/**
* 发送短信验证码
*
* @param phone 手机号
* @return 是否发送成功
*/
boolean sendSmsCode(String phone);
boolean sendMasSmsCode(String phone);
boolean sendMasSmsContent(String phone, String content);
void asyncSendMasSmsContent(String phone, String content);
}
package com.cnooc.expert.auth.service;
import com.cnooc.expert.system.entity.vo.SysCaptchaVO;
public interface SysCaptchaService {
/**
* 生成验证码
* @return 验证码captcha vo
*/
SysCaptchaVO generate();
/**
* 验证码效验
*
* @param key key
* @param code 验证码
* @return true:成功 false:失败
*/
boolean validate(String key, String code);
/**
* 是否开启登录验证码
*
* @return true:开启 false:关闭
*/
boolean isCaptchaEnabled();
}
package com.cnooc.expert.auth.service.impl;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.IdcardUtil;
import com.cnooc.expert.common.constant.TokenConstants;
import com.cnooc.expert.common.exception.BusinessException;
import com.cnooc.expert.common.utils.JwtUtils;
import com.cnooc.expert.common.utils.Sm2Util;
import com.cnooc.expert.common.utils.ValidUtils;
import com.cnooc.expert.external.expert.auth.service.LoginServicesClient;
import com.cnooc.expert.system.entity.vo.LoginVO;
import com.cnooc.expert.system.entity.vo.VerifyCodeVO;
import com.cnooc.expert.system.entity.vo.ZhuanJiaInfoAppVo;
import com.cnooc.expert.system.entity.vo.ZhuanJiaInfoVo;
import com.cnooc.expert.auth.service.LoginService;
import com.cnooc.expert.auth.service.SmsService;
import com.cnooc.expert.auth.service.SysCaptchaService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.time.Duration;
import java.util.UUID;
/**
* @Author: songYuHang
* @CreateTime: 2025-09-18 15:23
*/
@Service
@Slf4j
public class LoginServiceImpl implements LoginService {
@Autowired
private StringRedisTemplate redisTemplate;
@Autowired
private SmsService smsService;
@Autowired
private SysCaptchaService sysCaptchaService;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private LoginServicesClient loginServicesClient;
/** 身份证密码登录 */
private static final int ID_NUMBER_PASSWORD = 1;
/** 手机验证码登录 */
private static final int PHONE_CODE = 2;
/**
* 登录逻辑
* @param loginVO 登录
* @return Result<String> token
*/
@Override
public String login(LoginVO loginVO) {
log.info("开始执行登录逻辑");
String token;
switch (loginVO.getLoginType()) {
case ID_NUMBER_PASSWORD:
token = idNumberLogin(loginVO);
break;
case PHONE_CODE:
token = phoneCodeLogin(loginVO);
break;
default:
throw new BusinessException("请选择登录类型");
}
return token;
}
/**
* 获取验证码逻辑
* @param vo 手机号等信息
* @return Result<String> token
*/
@Override
public String sendPhoneCode(LoginVO vo) {
log.info("开始执行获取验证码逻辑");
ValidUtils.isText(vo.getPhoneNumber(), "请输入手机号");
ValidUtils.isTrue(Validator.isMobile(vo.getPhoneNumber()), "请输入正确的手机号");
//待确认,验证码下发是调用第三方平台吗
//return Result.success("验证码已发送");
boolean flag = sysCaptchaService.validate(vo.getKey(), vo.getCaptcha());
if(!flag){
return "验证码错误";
}else{
boolean smsfalg = smsService.sendSmsCode(vo.getPhoneNumber());
if(!smsfalg) {
return "短信验证码发送失败";
} else {
return "短信验证码发送成功";
}
}
}
@Override
public String changePass(LoginVO loginVO) {
log.info("开始执行修改密码逻辑");
ValidUtils.isText(loginVO.getPhoneNumber(), "请输入手机号");
ValidUtils.isText(loginVO.getPhoneCode(), "请输入验证码");
ValidUtils.isTrue(Validator.isMobile(loginVO.getPhoneNumber()), "请输入正确格式的手机号");
ValidUtils.isText(loginVO.getPassword(), "请输入密码");
//1.根据手机号去库中查询是否存在
ZhuanJiaInfoVo zhuanJiaInfoVo = new ZhuanJiaInfoVo();
zhuanJiaInfoVo.setMobile(loginVO.getPhoneNumber());
zhuanJiaInfoVo = loginServicesClient.querySingleByShengFenZhengOrMobile(zhuanJiaInfoVo);
if(zhuanJiaInfoVo == null){
return "用户信息不存在";
}
//2.判断密码是否存在
ZhuanJiaInfoAppVo zhuanJiaInfoAppVo = new ZhuanJiaInfoAppVo();
zhuanJiaInfoAppVo.setBaseGuid(zhuanJiaInfoVo.getBaseGuid());
zhuanJiaInfoAppVo = loginServicesClient.getZhuanJiaInfoAppById(zhuanJiaInfoAppVo);
String pwd = Sm2Util.decrypt(loginVO.getPassword());
if(zhuanJiaInfoAppVo == null){
//没有记录的话就是新建记录
zhuanJiaInfoAppVo = new ZhuanJiaInfoAppVo();
zhuanJiaInfoAppVo.setPassword(passwordEncoder.encode(pwd));
loginServicesClient.saveZhuanJiaInfoApp(zhuanJiaInfoAppVo);
}else{
//否则更新密码
zhuanJiaInfoAppVo.setPassword(passwordEncoder.encode(pwd));
loginServicesClient.updateZhuanJiaInfoApp(zhuanJiaInfoAppVo);
}
//手机号,验证码,图形验证码都需要判断
//判断密码是否符合规则
//进行解密处理
//调用数据库更新密码
return "ok";
}
@Override
public String verifyCode(VerifyCodeVO codeVO) {
log.info("手机验证码验证逻辑");
boolean smsfalg = smsService.verifySmsCode(codeVO.getPhoneNumber(),codeVO.getPhoneCode());
if(!smsfalg){
return "短信验证码验证失败";
}else{
return "短信验证码验证成功";
}
}
/**
* 身份证密码登录
* @param loginVO 登录参数
* @return token
*/
private String idNumberLogin(LoginVO loginVO) {
log.info("开始执行身份证登录逻辑");
ValidUtils.isText(loginVO.getIdNumber(), "请输入身份证号");
ValidUtils.isText(loginVO.getPassword(), "请输入密码");
ValidUtils.isTrue(IdcardUtil.isValidCard(loginVO.getIdNumber()), "请输入正确的身份证号");
ZhuanJiaInfoVo zhuanJiaInfoVo = new ZhuanJiaInfoVo();
zhuanJiaInfoVo.setShengfenzheng(loginVO.getIdNumber());
zhuanJiaInfoVo = loginServicesClient.querySingleByShengFenZhengOrMobile(zhuanJiaInfoVo);
if(zhuanJiaInfoVo == null){
return "用户信息不存在";
}
ZhuanJiaInfoAppVo zhuanJiaInfoAppVo = new ZhuanJiaInfoAppVo();
zhuanJiaInfoAppVo.setBaseGuid(zhuanJiaInfoVo.getBaseGuid());
zhuanJiaInfoAppVo = loginServicesClient.getZhuanJiaInfoAppById(zhuanJiaInfoAppVo);
if(zhuanJiaInfoAppVo == null){
return "该用户还没有设置密码";
}
// 验证码效验
boolean flag = sysCaptchaService.validate(loginVO.getKey(), loginVO.getCaptcha());
if (!flag) {
// 保存登录日志
//sysLogLoginService.save(login.getUsername(), Constant.FAIL, LoginOperationEnum.CAPTCHA_FAIL.getValue());
throw new BusinessException("图形验证码错误");
}
//1.需要去库中查询,是否存在
//2.存在校验密码
//解密
String pwd = Sm2Util.decrypt(loginVO.getPassword());
flag = passwordEncoder.matches(pwd, zhuanJiaInfoAppVo.getPassword());
if (!flag) {
// 登录日志
//sysLogLoginService.savePortal(login.getAccountName(), Constant.FAIL, LoginOperationEnum.ACCOUNT_FAIL.getValue(), 1);
throw new IllegalArgumentException("密码错误");
}
//3.生成相应的uuid作为redis的key
// // todo userid
String uuidKey = UUID.randomUUID().toString();
String token = JwtUtils.createToken(1,uuidKey);
tokenSetRedis(token, uuidKey);
//6.返回token
return token;
}
/**
* 手机验证码登录
* @param loginVO 手机号登录参数
* @return token
*/
private String phoneCodeLogin(LoginVO loginVO) {
log.info("开始执行手机验证码登录逻辑");
ValidUtils.isText(loginVO.getPhoneNumber(), "请输入手机号");
ValidUtils.isText(loginVO.getPhoneCode(), "请输入验证码");
ValidUtils.isTrue(Validator.isMobile(loginVO.getPhoneNumber()), "请输入正确格式的手机号");
//1.根据手机号去库中查询是否存在
ZhuanJiaInfoVo zhuanJiaInfoVo = new ZhuanJiaInfoVo();
zhuanJiaInfoVo.setMobile(loginVO.getPhoneNumber());
zhuanJiaInfoVo = loginServicesClient.querySingleByShengFenZhengOrMobile(zhuanJiaInfoVo);
if(zhuanJiaInfoVo == null){
return "用户信息不存在";
}
//2.存在校验验证码
if (!smsService.verifySmsCode(loginVO.getPhoneNumber(), loginVO.getPhoneCode())) {
//登录日志
//sysLogLoginService.savePortal(login.getPhone(), Constant.FAIL, LoginOperationEnum.CAPTCHA_FAIL.getValue(), 1);
throw new IllegalArgumentException("手机验证码错误");
}
//3.生成相应的uuid作为redis的key
// todo userid
String uuidKey = UUID.randomUUID().toString();
String token = JwtUtils.createToken(1,uuidKey);
tokenSetRedis(token, uuidKey);
return token;
}
/**
* 缓存存入token
* @param token token
* @param uuidKey uuidKey
*/
private void tokenSetRedis(String token, String uuidKey) {
String redisTokenKey = TokenConstants.TOKEN_KEY_ + uuidKey;
redisTemplate.opsForValue().set(redisTokenKey, token, Duration.ofHours(24));
}
}
package com.cnooc.expert.auth.service.impl;
import cn.hutool.core.util.RandomUtil;
import com.cnooc.expert.common.constant.TokenConstants;
import com.cnooc.expert.common.utils.SmsHttpUtil;
import com.cnooc.expert.common.utils.SmsUtil;
import com.cnooc.expert.system.entity.vo.SmsConfig;
import com.cnooc.expert.auth.service.SmsService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
@Service
@AllArgsConstructor
@Slf4j
public class SmsServiceImpl implements SmsService {
public static final String SMS_CODE_CONTENT = "福建通信行业融合创新服务平台,您的验证码是:%s(有效期为2分钟),请勿泄露给他人,如非本人操作,请忽略此消息。";
@Autowired
private StringRedisTemplate redisTemplate;
private final SmsConfig smsConfig;
/**
* 校验短信验证码
*
* @param phone 手机号
* @param code 用户输入的验证码
* @return 是否校验通过
*/
@Override
public boolean verifySmsCode(String phone, String code) {
String key = "sms:code:" + phone;
String storedCode = redisTemplate.opsForValue().get(key);
if (storedCode != null && storedCode.equals(code)) {
// 验证码正确,删除缓存中的验证码
// smsCodeRedisCache.delete(key);
return true;
}
return false;
}
/**
* 发送短信验证码(可选方法)
*
* @param phone 手机号
* @return 是否发送成功
*/
public boolean sendSmsCode(String phone) {
// 生成6位验证码
//String code = RandomUtil.randomNumbers(6);
String code = "666666";
String key = "sms:code:" + phone;
//redisTemplate.opsForValue().set(key, code, 60 * 60 * 1L);// 存入 Redis,设置过期时间为5分钟
System.out.println("发送短信验证码:" + phone + " -> " + code);// 模拟发送短信,实际应调用第三方短信服务
return true;
//return sendMasSmsCode(phone);
}
@Override
public boolean sendMasSmsCode(String phone) {
// 生成验证码并构建缓存键
String code = SmsUtil.generateVerificationCode();
System.out.println("发送短信验证码:" + phone + " -> " + code);
String key = SmsUtil.buildCacheKey(phone);
try {
// 构建短信内容
String content = String.format(SMS_CODE_CONTENT, code);
System.out.println("发送短信验证码:" + phone + " -> " + code);
log.info("云MAS业务平台 发送手机号: {},短信验证码:{}", phone, code);
System.out.println("云MAS业务平台 短信内容: " + content);
boolean result = sendMasSmsContent(phone, content);
if(result){
redisTemplate.opsForValue().set(key, code, 2 * 60); // 存入 Redis,设置过期时间为2分钟
}
return result;
} catch (Exception e) {
log.error("云MAS业务平台短信验证码发送失败: {}", e.getMessage(), e);
return false;
}
}
@Override
public boolean sendMasSmsContent(String phone, String content) {
try {
log.info("云MAS业务平台 短信内容: {}", content);
log.info("云MAS业务平台 发送手机号: {},短信内容:{}", phone, content);
// 生成 MAC 签名
String mac = SmsUtil.calculateMac(smsConfig.getEcName(), smsConfig.getApId(), smsConfig.getSecretKey(),
phone, content, smsConfig.getSign(), smsConfig.getAddSerial());
System.out.println("云MAS业务平台 mac签名: " + mac);
log.info("云MAS业务平台 mac签名: {}", mac);
// 构建请求体并转换为 Base64 编码的 JSON 字符串
String encodedJson = SmsUtil.encodeRequestBodyToBase64(buildRequestBody(phone, content, mac));
System.out.println("云MAS业务平台 请求体Base64编码: " + encodedJson);
log.info("云MAS业务平台 请求体Base64编码: {}", encodedJson);
// 设置请求头并发送 POST 请求
String response = SmsHttpUtil.sendPostRequest(smsConfig.getApiUrl(), encodedJson);
System.out.println("云MAS业务平台 响应体: " + response);
log.info("云MAS业务平台 响应体response: {}", response);
// 解析响应并处理结果
return SmsUtil.handleResponse(response);
} catch (Exception e) {
log.error("云MAS业务平台短信发送失败: {}", e.getMessage(), e);
return false;
}
}
@Override
public void asyncSendMasSmsContent(String phone, String content){
CompletableFuture.runAsync(() -> {
try {
System.out.println("======开始发送短信======");
sendMasSmsContent(phone, content);
System.out.println("======发送短信结束======");
} catch (Exception e) {
log.error("asyncSendMasSmsContent异步执行失败", e);
}
}
);
}
/**
* 构建请求体
*/
private Map<String, String> buildRequestBody(String phone, String content, String mac) {
Map<String, String> requestBody = new HashMap<>();
requestBody.put("ecName", smsConfig.getEcName());
requestBody.put("apId", smsConfig.getApId());
requestBody.put("mobiles", phone);
requestBody.put("content", content);
requestBody.put("secretKey", smsConfig.getSecretKey());
requestBody.put("sign", smsConfig.getSign());
requestBody.put("addSerial", smsConfig.getAddSerial());
requestBody.put("mac", mac);
return requestBody;
}
}
package com.cnooc.expert.auth.service.impl;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import com.cnooc.expert.common.cache.RedisKeys;
import com.cnooc.expert.auth.service.SysCaptchaService;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import com.cnooc.expert.system.entity.vo.SysCaptchaVO;
import com.wf.captcha.SpecCaptcha;
import com.wf.captcha.base.Captcha;
import java.util.concurrent.TimeUnit;
@Service
public class SysCaptchaServiceImpl implements SysCaptchaService {
private static final int EXPIRE_MINUTES = 5;
@Autowired
private StringRedisTemplate redisTemplate;
@Override
public SysCaptchaVO generate() {
// 生成验证码key
String key = UUID.randomUUID().toString();
// 生成验证码
SpecCaptcha captcha = new SpecCaptcha(150, 40);
captcha.setLen(4);
captcha.setCharType(Captcha.TYPE_DEFAULT);
String image = captcha.toBase64();
// 保存到缓存
String redisKey = RedisKeys.getCaptchaKey(key);
//redisTemplate.opsForValue().set(redisKey, captcha.text(), EXPIRE_MINUTES, TimeUnit.MINUTES);
// 封装返回数据
SysCaptchaVO captchaVO = new SysCaptchaVO();
captchaVO.setKey(key);
captchaVO.setImage(image);
return captchaVO;
}
@Override
public boolean validate(String key, String code) {
// 如果关闭了验证码,则直接效验通过
if (!isCaptchaEnabled()) {
return true;
}
if (StrUtil.isBlank(key) || StrUtil.isBlank(code)) {
return false;
}
// 获取验证码
String captcha = getCache(key);
// 效验成功
return code.equalsIgnoreCase(captcha);
}
@Override
public boolean isCaptchaEnabled() {
return true;
}
private String getCache(String key) {
key = RedisKeys.getCaptchaKey(key);
String captcha = redisTemplate.opsForValue().get(key);
// 删除验证码
if (captcha != null) {
redisTemplate.delete(key);
}
return captcha;
}
}
package com.cnooc.expert.external.expert.api;
import com.cnooc.expert.external.expert.model.request.ExpertInfoGetReq;
import com.cnooc.expert.external.expert.model.response.ExpertInfoGetResp;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.HeaderMap;
import retrofit2.http.POST;
import java.util.Map;
public interface LoginServiceApi {
@POST("/")
Call<ExpertInfoGetResp> expertDetailUpDate(@HeaderMap Map<String, Object> headers, @Body ExpertInfoGetReq user);
}
package com.cnooc.expert.external.expert.auth.service;
import com.cnooc.expert.external.common.AbstractRetrofitManager;
import com.cnooc.expert.system.entity.vo.ZhuanJiaInfoVo;
import com.cnooc.expert.system.entity.vo.ZhuanJiaInfoAppVo;
import org.springframework.stereotype.Service;
@Service
public class LoginServicesClient extends AbstractRetrofitManager {
public ZhuanJiaInfoVo querySingleByShengFenZhengOrMobile(ZhuanJiaInfoVo zhuanJiaInfoVo){
ZhuanJiaInfoVo res = new ZhuanJiaInfoVo();
/* String jsonString = JsonUtils.toJsonString(zhuanJiaInfoVo);
res = RestUtils.sendPostRequest2Expert("/zjfw/zggrxxgl/querySingleByShengFenZhengOrMobile",jsonString,null);
*/ return res;
}
public ZhuanJiaInfoAppVo getZhuanJiaInfoAppById(ZhuanJiaInfoAppVo zhuanJiaInfoAppVo){
ZhuanJiaInfoAppVo res = new ZhuanJiaInfoAppVo();
/* String jsonString = JsonUtils.toJsonString(zhuanJiaInfoAppVo);
res = RestUtils.sendPostRequest2Expert("/zjfw/zggrxxgl/getZhuanJiaInfoAppById",jsonString,null);*/
return res;
}
public ZhuanJiaInfoAppVo saveZhuanJiaInfoApp(ZhuanJiaInfoAppVo zhuanJiaInfoAppVo){
ZhuanJiaInfoAppVo res = new ZhuanJiaInfoAppVo();
/* String jsonString = JsonUtils.toJsonString(zhuanJiaInfoAppVo);
res = RestUtils.sendPostRequest2Expert("/zjfw/zggrxxgl/saveZhuanJiaInfoApp",jsonString,null);*/
return res;
}
public ZhuanJiaInfoAppVo updateZhuanJiaInfoApp(ZhuanJiaInfoAppVo zhuanJiaInfoAppVo){
ZhuanJiaInfoAppVo res = new ZhuanJiaInfoAppVo();
/* String jsonString = JsonUtils.toJsonString(zhuanJiaInfoAppVo);
res = RestUtils.sendPostRequest2Expert("/zjfw/zggrxxgl/updateZhuanJiaInfoApp",jsonString,null);*/
return res;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment