package com.project.framework.web.service;
|
|
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSONObject;
|
import com.aliyuncs.CommonRequest;
|
import com.aliyuncs.CommonResponse;
|
import com.aliyuncs.DefaultAcsClient;
|
import com.aliyuncs.IAcsClient;
|
import com.aliyuncs.exceptions.ClientException;
|
import com.aliyuncs.http.MethodType;
|
import com.aliyuncs.profile.DefaultProfile;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.project.common.constant.AliyunSmsConstants;
|
import com.project.common.constant.CacheConstants;
|
import com.project.common.constant.Constants;
|
import com.project.common.core.domain.entity.SysUser;
|
import com.project.common.core.domain.model.LoginUser;
|
import com.project.common.core.redis.RedisCache;
|
import com.project.common.exception.ServiceException;
|
import com.project.common.exception.base.BaseException;
|
import com.project.common.exception.user.CaptchaException;
|
import com.project.common.exception.user.CaptchaExpireException;
|
import com.project.common.exception.user.UserPasswordNotMatchException;
|
import com.project.common.utils.DateUtils;
|
import com.project.common.utils.MessageUtils;
|
import com.project.common.utils.ServletUtils;
|
import com.project.common.utils.StringUtils;
|
import com.project.common.utils.ip.IpUtils;
|
import com.project.framework.manager.AsyncManager;
|
import com.project.framework.manager.factory.AsyncFactory;
|
import com.project.framework.security.context.AuthenticationContextHolder;
|
import com.project.system.domain.bo.editBo.UserPhoneLoginBo;
|
import com.project.system.mapper.SysUserMapper;
|
import com.project.system.service.ISysConfigService;
|
import com.project.system.service.ISysUserService;
|
import com.project.system.sms.YPSmsApi;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.security.authentication.AuthenticationManager;
|
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.core.Authentication;
|
import org.springframework.stereotype.Component;
|
|
import java.util.Random;
|
import java.util.concurrent.TimeUnit;
|
|
/**
|
* 登录校验方法
|
*
|
* @author project
|
*/
|
@Component
|
@Slf4j
|
@RequiredArgsConstructor
|
public class SysLoginService
|
{
|
private final TokenService tokenService;
|
private final AuthenticationManager authenticationManager;
|
private final RedisCache redisCache;
|
private final ISysUserService userService;
|
private final SysUserMapper userMapper;
|
private final ISysConfigService configService;
|
private final YPSmsApi smsApi;
|
|
|
/**
|
* 登录验证
|
*
|
* @param username 用户名
|
* @param password 密码
|
* @param code 验证码
|
* @param uuid 唯一标识
|
* @return 结果
|
*/
|
public String login(String username, String password, String code, String uuid)
|
{
|
boolean captchaEnabled = configService.selectCaptchaEnabled();
|
// 验证码开关
|
if (captchaEnabled)
|
{
|
validateCaptcha(username, code, uuid);
|
}
|
// 用户验证
|
Authentication authentication;
|
try
|
{
|
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
|
AuthenticationContextHolder.setContext(authenticationToken);
|
// 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
|
authentication = authenticationManager.authenticate(authenticationToken);
|
}
|
catch (Exception e)
|
{
|
if (e instanceof BadCredentialsException)
|
{
|
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
|
throw new UserPasswordNotMatchException();
|
}
|
else
|
{
|
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
|
throw new ServiceException(e.getMessage());
|
}
|
}
|
finally
|
{
|
AuthenticationContextHolder.clearContext();
|
}
|
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
|
LoginUser loginUser = (LoginUser) authentication.getPrincipal();
|
recordLoginInfo(loginUser.getUserId());
|
|
// 生成token
|
return tokenService.createToken(loginUser);
|
}
|
|
/**
|
* 新注册获取验证码
|
* @param phone 手机
|
* @return 验证码
|
*/
|
public Boolean getVerifyCodeNew(String phone) {
|
// 生成4位随机数
|
String code = "";
|
Random ran = new Random();
|
int randomNum = ran.nextInt(10000);
|
code = String.format("%04d", randomNum);
|
log.info("手机号:"+phone+"->验证码:"+code);
|
boolean send = sendYp(phone, code);
|
if (send){
|
redisCache.setCacheObject(getCacheKey(phone), code, Constants.PHONE_EXPIRATION, TimeUnit.MINUTES);
|
return true;
|
}
|
redisCache.setCacheObject(getCacheKey(phone), code, Constants.PHONE_EXPIRATION, TimeUnit.MINUTES);
|
return false;
|
}
|
|
/**
|
* 获取验证码
|
* @param phone 手机号
|
* @return 验证码
|
*/
|
public Boolean getVerifyCode(String phone)
|
{
|
SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getPhonenumber,phone));
|
if (user==null){
|
throw new BaseException("您手机号尚未注册!");
|
}
|
return getVerifyCodeNew(phone);
|
}
|
|
/**
|
* 云片验证码
|
* @param phone 手机
|
* @param code 验证码
|
* @return 结果
|
*/
|
private boolean sendYp(String phone, String code)
|
{
|
String result = smsApi.sendSms(phone, StringUtils.format(YPSmsApi.CODE_TMP, code, Constants.PHONE_EXPIRATION));
|
if (result.contains("\"code\":0,\"msg\":\"OK\"")){
|
log.info("发送成功 ->验证码:"+code);
|
return true;
|
}
|
return false;
|
}
|
|
/**
|
* 阿里验证码
|
* @param phone 手机
|
* @param code 验证码
|
* @return 结果
|
*/
|
private boolean sendAl(String phone, String code )
|
{
|
DefaultProfile profile = DefaultProfile.getProfile("cn-beijing", AliyunSmsConstants.SMS_APPID, AliyunSmsConstants.SMS_SECRET);
|
IAcsClient client = new DefaultAcsClient(profile);
|
CommonRequest request = new CommonRequest();
|
request.setMethod(MethodType.POST);
|
request.setDomain("dysmsapi.aliyuncs.com");
|
request.setVersion("2017-05-25");
|
request.setAction("SendSms");
|
request.putQueryParameter("PhoneNumbers", phone);
|
request.putQueryParameter("SignName", "盛商珠宝");
|
request.putQueryParameter("TemplateCode", "SMS_460945884");
|
request.putQueryParameter("TemplateParam", "{code:" + code + "}");
|
try {
|
CommonResponse response = client.getCommonResponse(request);
|
JSONObject jsonObject = JSON.parseObject(response.getData());
|
if ("OK".equals(jsonObject.get("Code"))) {
|
log.info("发送成功 ->验证码:"+code);
|
return true;
|
}
|
} catch (ClientException e) {
|
e.printStackTrace();
|
}
|
return false;
|
}
|
|
/**
|
* 验证码登录
|
* @param bo 参数
|
* @return 结果
|
*/
|
public String phoneLogin(UserPhoneLoginBo bo)
|
{
|
String phone = bo.getPhone();
|
// Boolean verified = verifyPhone(phone, bo.getCode());
|
// if (!verified){
|
// throw new BaseException("手机号验证码校验失败!");
|
// }
|
SysUser user = null;
|
if ("01".equals(bo.getUserType())){
|
user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
|
.eq(SysUser::getPhonenumber,bo.getPhone())
|
.and(wrapper->wrapper.eq(SysUser::getUserType,"00").or().eq(SysUser::getUserType, "01")));
|
} else {
|
user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
|
.eq(SysUser::getPhonenumber,bo.getPhone())
|
.eq(SysUser::getUserType,bo.getUserType())
|
);
|
}
|
if (user==null){
|
throw new BaseException("您手机号尚未注册或您选择登录类型有误!");
|
}
|
if (!"0".equals(user.getStatus())){
|
throw new BaseException("您账号已停用或待审批,请联系营商办管理人员!");
|
}
|
return this.login(user.getUserName(), user.getRecommendUser(), null, null);
|
}
|
|
/**
|
* 校验验证码
|
*
|
* @param username 用户名
|
* @param code 验证码
|
* @param uuid 唯一标识
|
*/
|
public void validateCaptcha(String username, String code, String uuid)
|
{
|
String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
|
String captcha = redisCache.getCacheObject(verifyKey);
|
redisCache.deleteObject(verifyKey);
|
if (captcha == null)
|
{
|
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
|
throw new CaptchaExpireException();
|
}
|
if (!code.equalsIgnoreCase(captcha))
|
{
|
AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
|
throw new CaptchaException();
|
}
|
}
|
|
/**
|
* 记录登录信息
|
*
|
* @param userId 用户ID
|
*/
|
public void recordLoginInfo(Long userId)
|
{
|
SysUser sysUser = new SysUser();
|
sysUser.setUserId(userId);
|
sysUser.setLoginIp(IpUtils.getIpAddr(ServletUtils.getRequest()));
|
sysUser.setLoginDate(DateUtils.getNowDate());
|
userService.updateUserProfile(sysUser);
|
}
|
|
|
/**
|
* 获取验证码前缀
|
* @param phone 手机号
|
* @return 验证码
|
*/
|
private String getCacheKey(String phone)
|
{
|
return CacheConstants.PHONE_CODE_KEY + phone;
|
}
|
|
/**
|
* 校验验证码
|
* @param phone 手机号
|
* @param code 验证码
|
* @return 校验结果
|
*/
|
public Boolean verifyPhone(String phone, String code)
|
{
|
String key = getCacheKey(phone);
|
if (!redisCache.hasKey(key)) {
|
return false;
|
}
|
String redisCode = redisCache.getCacheObject(key);
|
|
boolean verify = redisCode.equals(code);
|
if (verify){
|
redisCache.deleteObject(getCacheKey(phone));
|
}
|
|
return verify;
|
}
|
|
|
}
|