Commit 92205ca3 authored by 技术部-任文超's avatar 技术部-任文超

回归到merge前代码版本后,重新整合成功(本地简单测试登录服务OK)

parent 0938421b
......@@ -145,7 +145,7 @@ public class CaptchaFiniteValidateAdvisor {
if(StringUtils.isBlank(phoneNo)){
return null;
}
return Constants.REDIS_PASSWORD_ERROR_COUNT_FOR_PHONE + phoneNo;
return Constants.REDIS_PASSWORD_ERROR_COUNT + phoneNo;
}
/**
......
package cn.quantgroup.xyqb.controller.internal.user;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.aspect.captcha.CaptchaFineteValidator;
import cn.quantgroup.xyqb.aspect.captcha.PasswordFineteValidator;
import cn.quantgroup.xyqb.aspect.logcaller.LogHttpCaller;
import cn.quantgroup.xyqb.controller.IBaseController;
......@@ -8,7 +9,9 @@ import cn.quantgroup.xyqb.entity.Merchant;
import cn.quantgroup.xyqb.entity.User;
import cn.quantgroup.xyqb.entity.UserDetail;
import cn.quantgroup.xyqb.entity.WechatUserInfo;
import cn.quantgroup.xyqb.exception.PasswordErrorLimitException;
import cn.quantgroup.xyqb.exception.UserNotExistException;
import cn.quantgroup.xyqb.exception.VerificationCodeErrorException;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.model.UserModel;
import cn.quantgroup.xyqb.model.UserRegisterMqMessage;
......@@ -39,6 +42,7 @@ import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* Http服务接口:用户注册、登录、重置密码
* Created by FrankChow on 15/7/5.
*/
@RestController
......@@ -69,9 +73,11 @@ public class UserController implements IBaseController {
@Autowired
private IWechatService wechatService;
private static final char[] PWD_BASE = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
private static final char[] PWD_BASE = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
};
@RequestMapping("/test")
public JsonResult test() {
......@@ -122,12 +128,70 @@ public class UserController implements IBaseController {
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)",null);
}
/**
* 登录(账号 + 密码)
* 密码错误达到限定次数时执行图形验证码校验
* 图形验证码累计错误达到限定次数时须重新获取
*
* @param channelId
* @param appChannel
* @param createdFrom
* @param userId
* @param key
* @param request
* @param openId
* @param dimension
* @return
*/
@CaptchaFineteValidator
@RequestMapping("/loginV1")
public JsonResult loginV1(
@RequestParam(required = false, defaultValue = "1") Long channelId, String appChannel,
@RequestParam(required = false, defaultValue = "1") Long createdFrom,
@RequestParam(required = false, defaultValue = "") String userId,
@RequestParam(required = false,defaultValue = "xyqb") String key,
HttpServletRequest request, String openId,
@RequestParam(required = false) String dimension) {
LOGGER.info("loginV1 -> channelId:{},appChennel:{},createdFrom:{},userId:{},key:{},openId:{},dimension:{}",channelId, appChannel, createdFrom, userId, key, openId, dimension);
return login(channelId, appChannel, createdFrom, userId, key, request, openId, dimension);
}
/**
* 快速登录(手机号 + 短信验证码),H5专用入口
* 短信验证码错误达到限定次数时执行图形验证码校验
* 图形验证码累计错误达到限定次数时须重新获取
*
* @param channelId
* @param appChannel
* @param createdFrom
* @param key
* @param btRegisterChannelId
* @param dimension
* @param request
* @return
*/
// Todo @OneTimeTokenValidator
@RequestMapping("/login/fastV1")
public JsonResult loginFastV1(
@RequestParam(required = false, defaultValue = "1") Long channelId, String appChannel,
@RequestParam(required = false, defaultValue = "1") Long createdFrom,
@RequestParam(required = false,defaultValue = "xyqb") String key,
@RequestParam(required = false)Long btRegisterChannelId,
@RequestParam(required = false) String dimension ,HttpServletRequest request) {
LOGGER.info("login/fastV1 -> channelId:{},appChennel:{},createdFrom:{},key:{},btRegisterChannelId:{},dimension:{}",channelId, appChannel, createdFrom, key, btRegisterChannelId, dimension);
return loginFast(channelId, appChannel, createdFrom, key, btRegisterChannelId, dimension, request);
}
@LogHttpCaller
@PasswordFineteValidator
@RequestMapping("/login")
public JsonResult login(
@RequestParam(required = false, defaultValue = "1") Long channelId, String appChannel,
@RequestParam(required = false, defaultValue = "1") Long createdFrom,
@RequestParam(required = false, defaultValue = "") String userId, @RequestParam(required = false,defaultValue = "xyqb") String key, HttpServletRequest request, String openId,@RequestParam(required = false) String dimension) {
@RequestParam(required = false, defaultValue = "1") Long channelId, String appChannel,
@RequestParam(required = false, defaultValue = "1") Long createdFrom,
@RequestParam(required = false, defaultValue = "") String userId,
@RequestParam(required = false,defaultValue = "xyqb") String key,
HttpServletRequest request, String openId,
@RequestParam(required = false) String dimension) {
LOGGER.info("user/login,请求参数channelId:{},appChannel:{},createdFrom:{},userId:{},key:{},openId:{},dimension:{},",channelId,appChannel,createdFrom,userId,key,openId,dimension);
Merchant merchant = merchantService.findMerchantByName(key);
if (merchant == null) {
......@@ -143,11 +207,13 @@ public class UserController implements IBaseController {
@RequestMapping("/login/fast")
public JsonResult loginFast(
@RequestParam(required = false, defaultValue = "1") Long channelId, String appChannel,
@RequestParam(required = false, defaultValue = "1") Long createdFrom, @RequestParam(required = false,defaultValue = "xyqb") String key,@RequestParam(required = false)Long btRegisterChannelId,@RequestParam(required = false) String dimension ,HttpServletRequest request) {
Map<String, JsonResult> validMap = getHeaderParam(request);
@RequestParam(required = false, defaultValue = "1") Long channelId, String appChannel,
@RequestParam(required = false, defaultValue = "1") Long createdFrom,
@RequestParam(required = false,defaultValue = "xyqb") String key,
@RequestParam(required = false)Long btRegisterChannelId,
@RequestParam(required = false) String dimension ,HttpServletRequest request) {
Map<String, JsonResult> validMap = getHeaderParam(request);
LOGGER.info("user/login/fast,请求参数channelId:{},appChannel:{},createdFrom:{},btRegisterChannelId:{},key:{},dimension:{},",channelId,appChannel,createdFrom,btRegisterChannelId,key,dimension);
if (null != validMap.get("fail")) {
return validMap.get("fail");
}
......@@ -157,6 +223,9 @@ public class UserController implements IBaseController {
}
JsonResult successResult = validMap.get("success");
String phoneNo = successResult.getData().toString();
String verificationCode = successResult.getMsg();
// 执行短信验证码检查
smsValidForFastLogin(phoneNo, verificationCode);
User user = userService.findByPhoneWithCache(phoneNo);
if (user != null && !user.getEnable()) {
LOGGER.error("用户不存在,或者已经注销,phoneNo:{}",phoneNo);
......@@ -177,7 +246,7 @@ public class UserController implements IBaseController {
private User registerFastWhenLogin(String phoneNo, Long channelId, Long registerFrom, String appChannel, Long btRegisterChannelId,String dimension) {
String password = genRandomPwd();
LOGGER.info("用户快速注册, phoneNo:{}, verificationCode:{}, channelId:{}, registerFrom:{},appChannel:{},btRegisterChannelId", phoneNo, channelId, registerFrom, appChannel,btRegisterChannelId);
LOGGER.info("用户快速注册, phoneNo:{}, channelId:{}, registerFrom:{},appChannel:{},btRegisterChannelId", phoneNo, channelId, registerFrom, appChannel,btRegisterChannelId);
if (!ValidationUtil.validatePhoneNo(phoneNo)) {
LOGGER.info("用户快速注册失败,手机号错误, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
throw new UserNotExistException("手机号错误");
......@@ -201,14 +270,16 @@ public class UserController implements IBaseController {
* @return
*/
private Map<String, JsonResult> getHeaderParam(HttpServletRequest request) {
Map<String, JsonResult> result = new HashMap<>();
Map<String, JsonResult> result = new HashMap<String, JsonResult>();
String verificationHeader = "Verification ";
String credential = request.getHeader("authorization");
if (StringUtils.isBlank(credential)) {
result.put("fail", JsonResult.buildErrorStateResult("登录失败", null));
return result;
}
if (!credential.startsWith(verificationHeader)) {
result.put("fail", JsonResult.buildErrorStateResult("登录失败", null));
return result;
}
credential = credential.substring(verificationHeader.length(), credential.length());
byte[] buf = Base64.decodeBase64(credential);
......@@ -216,17 +287,18 @@ public class UserController implements IBaseController {
String[] credentialArr = credential.split(":");
if (credentialArr.length != 2) {
result.put("fail", JsonResult.buildErrorStateResult("登录失败", null));
return result;
}
String phoneNo = credentialArr[0];
String verificationCode = credentialArr[1];
LOGGER.info("用户快速登录,phoneNo:{} , verificationCode:{}", phoneNo, verificationCode);
if (!ValidationUtil.validatePhoneNo(phoneNo)) {
if (!ValidationUtil.validatePhoneNo(phoneNo) || StringUtils.isBlank(verificationCode)) {
result.put("fail", JsonResult.buildErrorStateResult("登录失败", null));
return result;
}
// 校验短信密码
validateFastLoginVerificationCode(result, phoneNo, verificationCode);
result.put("success", JsonResult.buildSuccessResult("", phoneNo));
result.put("success", JsonResult.buildSuccessResult(verificationCode, phoneNo));
return result;
}
......@@ -241,6 +313,16 @@ public class UserController implements IBaseController {
return;
}
// 短信密码错误时,给该账号添加计数器
countErrorForPhoneNo(result, phoneNo, verificationCode);
}
/**
* 短信密码错误时,给该账号添加计数器
* @param result Map
* @param phoneNo 登录手机号
* @param verificationCode 短信密码
*/
private void countErrorForPhoneNo(Map<String, JsonResult> result, String phoneNo, String verificationCode) {
String passwordErrorCountKey = Constants.REDIS_PASSWORD_ERROR_COUNT + phoneNo;
if (!stringRedisTemplate.hasKey(passwordErrorCountKey)) {
stringRedisTemplate.opsForValue().set(passwordErrorCountKey, String.valueOf(0), Constants.ONE_DAY, TimeUnit.SECONDS);
......@@ -269,6 +351,7 @@ public class UserController implements IBaseController {
* @param channelId
* @return
*/
@LogHttpCaller
@RequestMapping("/register/fast")
public JsonResult registerFast(@RequestParam String phoneNo, @RequestParam String verificationCode, @RequestParam(required = false) Long channelId,
@RequestParam(required = false) Long registerFrom, @RequestParam(required = false, defaultValue = "") String appChannel,
......@@ -290,27 +373,22 @@ public class UserController implements IBaseController {
if (null == registerFrom) {
registerFrom = 1L;
}
smsValidForFastLogin(phoneNo, verificationCode);
if (userService.exist(phoneNo)) {
LOGGER.info("用户快速注册失败,该手机号已经被注册, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildErrorStateResult("该手机号已经被注册", null);
}
if (!smsService.validRegisterOrResetPasswdVerificationCode(phoneNo, verificationCode)) {
LOGGER.info("用户快速注册失败,短信验证码错误, registerFrom:{}, phoneNo:{}, verificationCode:{}", registerFrom, phoneNo, verificationCode);
return JsonResult.buildErrorStateResult("短信验证码错误", null);
}
if (!userService.register(phoneNo, password, registerFrom, getIp(), channelId,btRegisterChannelId,dimension)) {
LOGGER.info("用户快速注册失败,请稍后重试, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildErrorStateResult("注册失败,请稍后重试", null);
}
LOGGER.info("用户快速注册成功, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildSuccessResult(null, null);
}
/**
* 用户注册
* 用户注册
*
* @param phoneNo
* @param password
......@@ -339,34 +417,28 @@ public class UserController implements IBaseController {
if (null == registerFrom) {
registerFrom = 1L;
}
smsValidForRegister(phoneNo, verificationCode);
if (userService.exist(phoneNo)) {
LOGGER.info("用户注册失败,该手机号已经被注册, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildErrorStateResult("该手机号已经被注册", null);
}
if (!smsService.validRegisterOrResetPasswdVerificationCode(phoneNo, verificationCode)) {
LOGGER.info("用户注册失败,短信验证码错误, registerFrom:{}, phoneNo:{}, verificationCode:{}", registerFrom, phoneNo, verificationCode);
return JsonResult.buildErrorStateResult("短信验证码错误", null);
}
if (!userService.register(phoneNo, password, registerFrom, getIp(), channelId,btRegisterChannelId,dimension)) {
LOGGER.info("用户快速注册失败,请稍后重试, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildErrorStateResult("注册失败,请稍后重试", null);
}
LOGGER.info("用户注册成功, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildSuccessResult(null, null);
}
/**
* 检查用户是否存在
*
* @param phoneNo
* @param phoneNo 手机号
* @return
*/
@RequestMapping("/exist")
public JsonResult exist(@RequestParam String phoneNo) {
LOGGER.info("检查用户是否存在, phoneNo:{}", phoneNo);
if (userService.exist(phoneNo)) {
LOGGER.info("该手机号已经注册, phoneNo:{}", phoneNo);
return JsonResult.buildErrorStateResult("该手机号已经注册", null);
......@@ -374,11 +446,10 @@ public class UserController implements IBaseController {
return JsonResult.buildSuccessResult(null, null);
}
/**
* 检查用户是否存在
*
* @param phoneNo
* @param phoneNo 手机号
* @return
*/
@RequestMapping("/exist_check")
......@@ -395,6 +466,7 @@ public class UserController implements IBaseController {
* @param verificationCode
* @return
*/
@LogHttpCaller
@RequestMapping("/reset_password")
public JsonResult resetPassword(@RequestParam String phoneNo,
@RequestParam String password,
......@@ -409,13 +481,10 @@ public class UserController implements IBaseController {
if (password.length() < 6 || password.length() > 12) {
return JsonResult.buildErrorStateResult("密码应为6-12位", null);
}
if (!smsService.validRegisterOrResetPasswdVerificationCode(phoneNo, verificationCode)) {
if(needRetSendCode(phoneNo)){
String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo;
stringRedisTemplate.delete(key);
return JsonResult.buildErrorStateResult("错误次数过多,请重新获取短信验证码", null);
}
return JsonResult.buildErrorStateResult("短信验证码错误", null);
smsValidForRegister(phoneNo, verificationCode);
if (!userService.exist(phoneNo)) {
LOGGER.info("修改密码失败,该手机号尚未注册, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildErrorStateResult("该手机号尚未注册", null);
}
if (!userService.resetPassword(phoneNo, password)) {
return JsonResult.buildErrorStateResult("修改密码失败", null);
......@@ -426,23 +495,6 @@ public class UserController implements IBaseController {
return JsonResult.buildSuccessResult(null, null);
}
/**
* 是否需要重新发送短信验证码
* @param phoneNo
* @return
*/
private boolean needRetSendCode(@RequestParam String phoneNo) {
boolean needRetSend=false;
String verificationCountKey = Constants.REDIS_VERIFICATION_COUNT+phoneNo;
Long getVerificationCount = stringRedisTemplate.opsForHash().increment(verificationCountKey, Constants.REDIS_VERIFICATION_COUNT, 1);
//已经存在删除操作增加过期时间防止意外
stringRedisTemplate.expire(verificationCountKey, DateUtils.getSeconds(), TimeUnit.SECONDS);
if(getVerificationCount>5){
return needRetSend=true;
}
return needRetSend;
}
/**
* 检查token是否已经过期不存在了
*
......@@ -503,13 +555,13 @@ public class UserController implements IBaseController {
if (null == registerFrom) {
registerFrom = 1L;
}
LOGGER.info("用户快速注册成功, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return userService.registerAndReturn(phoneNo, password, registerFrom);
User newUser = userService.registerAndReturn(phoneNo, password, registerFrom);
if(newUser != null && newUser.getId() != null && newUser.getId() > 0){
LOGGER.info("用户快速注册成功, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
}
return newUser;
}
private JsonResult loginWithHttpBasic(Long channelId, String appChannel, Long createdFrom, Merchant merchant, HttpServletRequest request, String openId,String dimension) {
User user = verificateUserNameAndPassword(request, openId);
if (user == null) {
......@@ -537,20 +589,26 @@ public class UserController implements IBaseController {
}
String[] credentialArr = bufStr.split(":");
if (credentialArr.length != 2) {
LOGGER.info("用户登录失败:{}", bufStr);
// 向该ipv4添加错误计数器
countErrorByIpv4();
return null;
}
String userName = credentialArr[0];
LOGGER.info("用户正在登录... [{}]", credentialArr);
String phoneNo = credentialArr[0];
String pass = credentialArr[1];
User user = userService.findByPhoneWithCache(userName);
User user = userService.findByPhoneWithCache(phoneNo);
if (user == null || !user.getEnable()) {
// 向该phoneNo添加错误计数器
countErrorByPhoneNo(phoneNo);
// 向该ipv4添加错误计数器
countErrorByIpv4();
return null;
}
//验证密码
if (!validatePassword(pass, user.getPassword())) {
// 向该phoneNo添加错误计数器
countErrorByPhoneNo(phoneNo);
// 向该ipv4添加错误计数器
countErrorByIpv4();
return null;
......@@ -558,13 +616,34 @@ public class UserController implements IBaseController {
return user;
}
/**
* 向该phoneNo添加错误计数器
* @param phoneNo
*/
private void countErrorByPhoneNo(String phoneNo) {
// 密码错误时,给该账号添加计数器
String key = Constants.REDIS_PASSWORD_ERROR_COUNT + phoneNo;
if (!stringRedisTemplate.hasKey(key)) {
LOGGER.info("添加错误计数器,key={}", key);
stringRedisTemplate.opsForValue().set(key, String.valueOf(0), DateUtils.getSeconds(), TimeUnit.SECONDS);
}
// 密码错误计数
Long errorCount = stringRedisTemplate.opsForValue().increment(key, 1L);
if (errorCount > Constants.Image_Need_Count) {
throw new PasswordErrorLimitException("用户名或密码不正确");
} else if (Objects.equals(errorCount, Constants.Image_Need_Count)) {
throw new PasswordErrorLimitException("请输入图形验证码");
}
}
/**
* 向该ipv4添加错误计数器
*/
private void countErrorByIpv4() {
// if(!ValidationUtil.isAtDangerousTime()){
// return;
// }
// Todo -- 全天候开放监控
/*if(!ValidationUtil.isAtDangerousTime()){
return;
}*/
String ipv4 = getIp();
if (StringUtils.isNotBlank(ipv4) && !ValidationUtil.validateLocalIpv4(ipv4)) {
String ipv4Key = getIpKey(getIp());
......@@ -639,4 +718,53 @@ public class UserController implements IBaseController {
return JsonResult.buildSuccessResult(null, null);
}
/**
* 注册时校验短信验证码
* @param phoneNo
* @param verificationCode
*/
private void smsValidForRegister(String phoneNo, String verificationCode) {
if (!smsService.validRegisterOrResetPasswdVerificationCode(phoneNo, verificationCode)) {
smsReSendOrNot(phoneNo);
LOGGER.info("用户快速注册,验证码校验失败,phoneNo:{} , verificationCode:{}", phoneNo, verificationCode);
throw new VerificationCodeErrorException("短信验证码错误");
}
}
/**
* 登录时校验短信验证码
* @param phoneNo
* @param verificationCode
*/
private void smsValidForFastLogin(String phoneNo, String verificationCode) {
if (!smsService.validateFastLoginVerificationCode(phoneNo, verificationCode)) {
smsReSendOrNot(phoneNo);
LOGGER.info("用户快速登录,验证码校验失败,phoneNo:{} , verificationCode:{}", phoneNo, verificationCode);
throw new VerificationCodeErrorException("短信验证码错误");
}
}
/**
* 是否需要重新获取短信验证码
* @param phoneNo
*/
private void smsReSendOrNot(String phoneNo) {
if(needRetSendCode(phoneNo)){
String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo;
stringRedisTemplate.delete(key);
throw new VerificationCodeErrorException("验证码失效,请重新获取");
}
}
/**
* 是否需要重新发送短信验证码
* @param phoneNo
* @return
*/
private boolean needRetSendCode(String phoneNo) {
String verificationCountKey = Constants.REDIS_VERIFICATION_COUNT + phoneNo;
Long getVerificationCount = stringRedisTemplate.opsForHash().increment(verificationCountKey, Constants.REDIS_VERIFICATION_COUNT, 1);
return (getVerificationCount >= 5);
}
}
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