Commit bae2a1c5 authored by Java—KA—李 青's avatar Java—KA—李 青

Merge branch 'master' into 20171127_remove_channelIdInterceptor

parents bc3a341f 39b1973c
...@@ -35,17 +35,18 @@ public interface Constants { ...@@ -35,17 +35,18 @@ public interface Constants {
String REDIS_VOICE_DEVICE_COUNT = "Voice_Device_verification_code_count:"; String REDIS_VOICE_DEVICE_COUNT = "Voice_Device_verification_code_count:";
String REDIS_VERIFICATION_COUNT = "verification_code_count:"; String REDIS_VERIFICATION_COUNT = "verification_code_count:";
Long Image_Need_Count=3L; Long Image_Need_Count = 3L;
Long VERIFICATION_CODE_FINITE_COUNT = 3L;
String X_AUTH_TOKEN = "x-auth-token";
String ONE_TIME_TOKEN = "oneTimeToken";
String REDIS_PASSWORD_ERROR_COUNT = "password_error_count:"; String REDIS_PASSWORD_ERROR_COUNT = "password_error_count:";
String REDIS_PASSWORD_ERROR_COUNT_FOR_IPV4 = "password_error_count_4_ipv4:"; String REDIS_PASSWORD_ERROR_COUNT_FOR_IPV4 = "password_error_count_4_ipv4:";
String IPV4_LOCK_WHITE = "lock_ipv4:white:";
String IPV4_LOCK_BLACK = "lock_ipv4:black:";
String IPV4_LOCK_MINUTES_REDIS = "lock_ipv4:minutes:";
String IPV4_LOCK_ON_COUNTS_REDIS = "lock_ipv4:on_counts:";
String IPV4_LOCK = "lock_ipv4:"; String IPV4_LOCK = "lock_ipv4:";
Long IPV4_LOCK_MINUTES = 3 * 60L; Long IPV4_LOCK_MINUTES = 6 * 60L;
Long IPV4_COUNT_MINUTES = 1L; Long IPV4_COUNT_MINUTES = 1L;
Long IPV4_LOCK_ON_COUNTS = 60L; Long IPV4_LOCK_ON_COUNTS = 200L;
int DANGEROUS_TIME_START = 22; int DANGEROUS_TIME_START = 22;
int DANGEROUS_TIME_END = 6; int DANGEROUS_TIME_END = 6;
String CLEAR_LOCK_FOR_IPV4 = "x-clear-lock-11241842-y"; String CLEAR_LOCK_FOR_IPV4 = "x-clear-lock-11241842-y";
......
package cn.quantgroup.xyqb.aspect.captcha;
import java.lang.annotation.*;
/**
* 限次的图形验证码校验标记
* @author 任文超
* @version 1.0.0
* @since 2017-11-07
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CaptchaFineteValidator {
}
package cn.quantgroup.xyqb.aspect.captcha;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.thirdparty.jcaptcha.AbstractManageableImageCaptchaService;
import cn.quantgroup.xyqb.util.ValidationUtil;
import com.octo.captcha.service.CaptchaServiceException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* 限次图形验证码校验标记
* @author 任文超
* @version 1.0.0
* @since 2017-11-07
*/
@Aspect
@Component
public class CaptchaFiniteValidateAdvisor {
private static final Logger LOGGER = LoggerFactory.getLogger(CaptchaFiniteValidateAdvisor.class);
private static final String SUPER_CAPTCHA_ID = UUID.nameUUIDFromBytes("__QG_APPCLIENT_AGENT__".getBytes(Charset.forName("UTF-8"))).toString();
private static final String SUPER_CAPTCHA = "__SUPERQG__";
/**
* 图形验证码错误计数器生命周期,与图形验证码生命周期保持一致
* 参照点:cn.quantgroup.xyqb.config.captcha.RedisCaptchaStore{
* DEFAULT_EXPIRED_IN = 120L;
* DEFAULT_EXPIRED_TIMEUNIT = TimeUnit.SECONDS;
* }
*/
private static final Long SECONDS = 2 * 60L;
@Autowired
@Qualifier("stringRedisTemplate")
private RedisTemplate<String, String> redisTemplate;
@Autowired
@Qualifier("customCaptchaService")
private AbstractManageableImageCaptchaService imageCaptchaService;
/**
* 自动化测试忽略验证码
*/
@Value("${xyqb.auth.captcha.autotest.enable:false}")
private boolean autoTestCaptchaEnabled;
/**
* 限次图形验证码切面
*/
@Pointcut("@annotation(cn.quantgroup.xyqb.aspect.captcha.CaptchaFineteValidator)")
private void needCaptchaFiniteValidate() {
}
/**
* 在受保护的接口方法执行前, 执行限次图形验证码校验
*
* @param pjp
* @return
* @throws Throwable
*/
@Around("needCaptchaFiniteValidate()")
private Object doCapchaValidate(ProceedingJoinPoint pjp) throws Throwable {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
Map<String, String> phonePasswordMap = getHeaderParam(request);
if(phonePasswordMap == null || phonePasswordMap.isEmpty()){
return false;
}
// 当前用户手机号
String phoneNo = phonePasswordMap.get("phoneNo");
Long countErrorByPhone = getCount(phoneNo);
if(countErrorByPhone == null){
LOGGER.info("用户名或密码不正确, phoneNo={}, countErrorByPhone={}, clientIp={}", phoneNo, countErrorByPhone, request.getRemoteAddr());
return JsonResult.buildErrorStateResult("用户名或密码不正确", null);
}
if (countErrorByPhone > Constants.Image_Need_Count) {
String registerFrom = Optional.ofNullable(request.getParameter("registerFrom")).orElse("");
String captchaId = Optional.ofNullable(request.getParameter("captchaId")).orElse("");
String captchaValue = request.getParameter("captchaValue");
if (shouldSkipCaptchaValidate(registerFrom, captchaId, captchaValue)) {
LOGGER.info("使用超级图形验证码校验, registerFrom={}, clientIp={}", registerFrom, request.getRemoteAddr());
return pjp.proceed();
}
if (StringUtils.isNotBlank(captchaValue)) {
// 忽略用户输入的大小写
String captcha = StringUtils.lowerCase(captchaValue);
// 验证码校验
Boolean validCaptcha = false;
try {
validCaptcha = imageCaptchaService.validateResponseForID(Constants.IMAGE_CAPTCHA_KEY + captchaId, captcha);
} catch (CaptchaServiceException ex) {
LOGGER.error("验证码校验异常, {}, {}", ex.getMessage(), ex);
}
if (validCaptcha) {
return pjp.proceed();
}
return JsonResult.buildSuccessResult("图形验证码不正确", "", 2L);
}
return JsonResult.buildSuccessResult("请输入图形验证码", "", 2L);
}
return pjp.proceed();
}
private boolean shouldSkipCaptchaValidate(String registerFrom, String captchaId, Object captchaValue) {
// 如果启用了超级验证码功能, 检查超级验证码, 超级验证码区分大小写
if (autoTestCaptchaEnabled) {
return true;
}
return StringUtils.equals(SUPER_CAPTCHA_ID, String.valueOf(captchaId)) && StringUtils.equals(SUPER_CAPTCHA, String.valueOf(captchaValue));
}
// 获取该账号密码错误计数器
private Long getCount(String phoneNo) {
String key = getKey(phoneNo);
if (StringUtils.isBlank(key)) {
return null;
}
String countString = redisTemplate.opsForValue().get(key);
if (StringUtils.isBlank(countString)) {
return 0L;
}
return Long.valueOf(countString);
}
private final static String getKey(String phoneNo){
if(StringUtils.isBlank(phoneNo)){
return null;
}
return Constants.REDIS_PASSWORD_ERROR_COUNT + phoneNo;
}
/**
* 单次令牌参数解析
*
* @param request 当前请求,其首部行必须包含形如【SingleToken 13461067662:0123456789abcdef】的UTF-8编码的Base64加密参数
* @return 令牌参数Map 或 null
*/
private Map<String, String> getHeaderParam(HttpServletRequest request) {
String verificationHeader = "Basic ";
String credential = request.getHeader("authorization");
if (StringUtils.isBlank(credential) || !credential.startsWith(verificationHeader)) {
LOGGER.info("参数无效, credential:{}", credential);
return null;
}
credential = credential.substring(verificationHeader.length(), credential.length());
byte[] buf = Base64.decodeBase64(credential);
credential = new String(buf, Charset.forName("UTF-8"));
String[] credentialArr = credential.split(":");
boolean headerParamValid = credentialArr.length==2;
if (!headerParamValid) {
LOGGER.info("参数无效, credential:{}", credential);
return null;
}
// 当前用户手机号
String phoneNo = credentialArr[0];
// 当前请求的SingleToken
String password = credentialArr[1];
headerParamValid = headerParamValid && ValidationUtil.validatePhoneNo(phoneNo) && StringUtils.isNotBlank(password);
if (!headerParamValid) {
LOGGER.info("参数无效, credential:{}, phoneNo:{}, password:{}", credential, phoneNo, password);
return null;
}
LOGGER.info("账密登录, phoneNo:{}, password:{}", phoneNo, password);
Map<String, String> phonePasswordMap = new HashMap<String, String>(2);
phonePasswordMap.put("phoneNo", phoneNo);
phonePasswordMap.put("password", password);
return phonePasswordMap;
}
}
...@@ -72,6 +72,8 @@ public class CaptchaNewValidateAdvisor { ...@@ -72,6 +72,8 @@ public class CaptchaNewValidateAdvisor {
/** /**
* 在受图形验证码保护的接口方法执行前, 执行图形验证码校验 * 在受图形验证码保护的接口方法执行前, 执行图形验证码校验
* captchaId 图形验证码key
* captchaValue 图形验证码value
* *
* @throws Throwable * @throws Throwable
*/ */
...@@ -81,7 +83,7 @@ public class CaptchaNewValidateAdvisor { ...@@ -81,7 +83,7 @@ public class CaptchaNewValidateAdvisor {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String registerFrom = Optional.ofNullable(request.getParameter("registerFrom")).orElse(""); String registerFrom = Optional.ofNullable(request.getParameter("registerFrom")).orElse("");
String captchaId = Optional.ofNullable(request.getParameter("captchaId")).orElse(""); String captchaId = Optional.ofNullable(request.getParameter("captchaId")).orElse("");
Object captchaValue = request.getParameter("captchaValue"); String captchaValue = request.getParameter("captchaValue");
String phoneNo = request.getParameter("phoneNo"); String phoneNo = request.getParameter("phoneNo");
String deviceId = Optional.ofNullable(request.getParameter("deviceId")).orElse(""); String deviceId = Optional.ofNullable(request.getParameter("deviceId")).orElse("");
String clientIp = getIp(); String clientIp = getIp();
...@@ -98,10 +100,9 @@ public class CaptchaNewValidateAdvisor { ...@@ -98,10 +100,9 @@ public class CaptchaNewValidateAdvisor {
JsonResult result = JsonResult.buildSuccessResult("图形验证码不正确", ""); JsonResult result = JsonResult.buildSuccessResult("图形验证码不正确", "");
result.setBusinessCode("0002"); result.setBusinessCode("0002");
if (captchaValue != null && StringUtils.isNotEmpty(String.valueOf(captchaValue))) { if (StringUtils.isNotBlank(captchaValue)) {
String captcha = String.valueOf(captchaValue);
// 忽略用户输入的大小写 // 忽略用户输入的大小写
captcha = StringUtils.lowerCase(captcha); String captcha = StringUtils.lowerCase(captchaValue);
// 验证码校验 // 验证码校验
Boolean validCaptcha = false; Boolean validCaptcha = false;
try { try {
...@@ -109,7 +110,6 @@ public class CaptchaNewValidateAdvisor { ...@@ -109,7 +110,6 @@ public class CaptchaNewValidateAdvisor {
} catch (CaptchaServiceException ex) { } catch (CaptchaServiceException ex) {
LOGGER.error("验证码校验异常, {}, {}", ex.getMessage(), ex); LOGGER.error("验证码校验异常, {}, {}", ex.getMessage(), ex);
} }
if (validCaptcha) { if (validCaptcha) {
return pjp.proceed(); return pjp.proceed();
} }
...@@ -118,19 +118,15 @@ public class CaptchaNewValidateAdvisor { ...@@ -118,19 +118,15 @@ public class CaptchaNewValidateAdvisor {
LOGGER.info("使用错误图形验证码, registerFrom={}, clientIp={},手机号次数:{},设备次数:{},ip次数:{},phone:{}", registerFrom, clientIp,countPhone,countDeviceId,countIP,phoneNo); LOGGER.info("使用错误图形验证码, registerFrom={}, clientIp={},手机号次数:{},设备次数:{},ip次数:{},phone:{}", registerFrom, clientIp,countPhone,countDeviceId,countIP,phoneNo);
result.setMsg("请输入图形验证码"); result.setMsg("请输入图形验证码");
return result; return result;
} }
return pjp.proceed(); return pjp.proceed();
} }
private boolean shouldSkipCaptchaValidate(String registerFrom, String captchaId, Object captchaValue) { private boolean shouldSkipCaptchaValidate(String registerFrom, String captchaId, Object captchaValue) {
// 如果启用了超级验证码功能, 检查超级验证码, 超级验证码区分大小写 // 如果启用了超级验证码功能, 检查超级验证码, 超级验证码区分大小写
if (autoTestCaptchaEnabled) { if (autoTestCaptchaEnabled) {
return true; return true;
} }
return StringUtils.equals(SUPER_CAPTCHA_ID, String.valueOf(captchaId)) && StringUtils.equals(SUPER_CAPTCHA, String.valueOf(captchaValue)); return StringUtils.equals(SUPER_CAPTCHA_ID, String.valueOf(captchaId)) && StringUtils.equals(SUPER_CAPTCHA, String.valueOf(captchaValue));
} }
...@@ -189,30 +185,25 @@ public class CaptchaNewValidateAdvisor { ...@@ -189,30 +185,25 @@ public class CaptchaNewValidateAdvisor {
private String getIp() { private String getIp() {
HttpServletRequest request = getRequest(); HttpServletRequest request = getRequest();
String ip = request.getHeader("x-real-ip"); String ip = request.getHeader("x-real-ip");
if (StringUtils.isEmpty(ip)) { if (StringUtils.isEmpty(ip)) {
ip = request.getRemoteAddr(); ip = request.getRemoteAddr();
} }
//过滤反向代理的ip //过滤反向代理的ip
String[] stemps = ip.split(","); String[] stemps = ip.split(",");
if (stemps.length >= 1) { if (stemps.length >= 1) {
//得到第一个IP,即客户端真实IP //得到第一个IP,即客户端真实IP
ip = stemps[0]; ip = stemps[0];
} }
ip = ip.trim(); ip = ip.trim();
if (ip.length() > 23) { if (ip.length() > 23) {
ip = ip.substring(0, 23); ip = ip.substring(0, 23);
} }
return ip; return ip;
} }
private HttpServletRequest getRequest() { private HttpServletRequest getRequest() {
ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder ServletRequestAttributes attrs = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
.getRequestAttributes();
return attrs.getRequest(); return attrs.getRequest();
} }
} }
...@@ -103,19 +103,15 @@ public class CaptchaValidateAdvisor { ...@@ -103,19 +103,15 @@ public class CaptchaValidateAdvisor {
return pjp.proceed(); return pjp.proceed();
} }
} }
return result; return result;
} }
private boolean shouldSkipCaptchaValidate(String registerFrom, String captchaId, Object captchaValue) { private boolean shouldSkipCaptchaValidate(String registerFrom, String captchaId, Object captchaValue) {
// 如果启用了超级验证码功能, 检查超级验证码, 超级验证码区分大小写 // 如果启用了超级验证码功能, 检查超级验证码, 超级验证码区分大小写
if (autoTestCaptchaEnabled) { if (autoTestCaptchaEnabled) {
return true; return true;
} }
return StringUtils.equals(SUPER_CAPTCHA_ID, String.valueOf(captchaId)) && StringUtils.equals(SUPER_CAPTCHA, String.valueOf(captchaValue)); return StringUtils.equals(SUPER_CAPTCHA_ID, String.valueOf(captchaId)) && StringUtils.equals(SUPER_CAPTCHA, String.valueOf(captchaValue));
} }
} }
...@@ -52,6 +52,7 @@ public class PasswordErrorFiniteValidateAdvisor { ...@@ -52,6 +52,7 @@ public class PasswordErrorFiniteValidateAdvisor {
*/ */
@Around("passwordErrorFiniteValidate()") @Around("passwordErrorFiniteValidate()")
private Object doFiniteValidate(ProceedingJoinPoint pjp) throws Throwable { private Object doFiniteValidate(ProceedingJoinPoint pjp) throws Throwable {
// Todo -- 全天候开放监控
/*if(!ValidationUtil.isAtDangerousTime()){ /*if(!ValidationUtil.isAtDangerousTime()){
return pjp.proceed(); return pjp.proceed();
}*/ }*/
......
package cn.quantgroup.xyqb.aspect.token;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.model.JsonResult;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
/**
* 一次性令牌校验切面
*
* @author 任文超
* @version 1.0.0
* @since 2017-10-31
*/
@Aspect
@Component
public class OneTimeTokenValidateAdvisor {
private static final Logger LOGGER = LoggerFactory.getLogger(OneTimeTokenValidateAdvisor.class);
@Autowired
@Qualifier("stringRedisTemplate")
private RedisTemplate<String, String> redisTemplate;
/**
* 一次性令牌校验切面
*/
@Pointcut("@annotation(cn.quantgroup.xyqb.aspect.token.OneTimeTokenValidator)")
private void needOneTimeToken() {}
/**
* 在受一次性令牌保护的接口方法执行前, 执行一次性令牌校验
*
* @throws Throwable
*/
@Around("needOneTimeToken()")
private Object checkOneTimeToken(ProceedingJoinPoint pjp) throws Throwable {
boolean valid = oneTimeTokenValid();
if (valid) {
return pjp.proceed();
}
return JsonResult.buildSuccessResult("操作失败,请重新提交", "", 2L);
}
/**
* 校验一次性令牌
* @return True or False
*/
private boolean oneTimeTokenValid() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
// 当前请求的OneTimeToken
String oneTimeToken = request.getParameter(Constants.ONE_TIME_TOKEN);
if (StringUtils.isBlank(oneTimeToken)){
return false;
}
String oneTimeToken_value = redisTemplate.opsForValue().get(oneTimeToken);
// OneTimeToken再Redis中值不应为空值(空白、空格、null)
if (StringUtils.isBlank(oneTimeToken_value)) {
return false;
}
boolean valid = Objects.equals(Boolean.TRUE.toString(), oneTimeToken_value);
// OneTimeToken校验正确时删除key
if(valid) {
redisTemplate.delete(oneTimeToken);
}else {
LOGGER.info("令牌已失效,请重新请求, oneTimeToken={}, clientIp={}", oneTimeToken, request.getRemoteAddr());
}
return valid;
}
}
package cn.quantgroup.xyqb.aspect.token;
import java.lang.annotation.*;
/**
* 一次性令牌校验标记
* @author 任文超
* @version 1.0.0
* @since 2017-10-31
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OneTimeTokenValidator {
}
...@@ -101,7 +101,9 @@ public class RedisCaptchaStore implements CaptchaStore { ...@@ -101,7 +101,9 @@ public class RedisCaptchaStore implements CaptchaStore {
private Captcha getFromRedisThenDel(String captchaId) { private Captcha getFromRedisThenDel(String captchaId) {
String captcharKey = buildCaptcharKey(captchaId); String captcharKey = buildCaptcharKey(captchaId);
Long expire = stringRedisTemplate.getExpire(captcharKey, TimeUnit.SECONDS);
Object value = stringRedisTemplate.opsForValue().get(captcharKey); Object value = stringRedisTemplate.opsForValue().get(captcharKey);
LOGGER.info("captchaId={},captchaCode={},expire={}秒", captcharKey, value, expire);
stringRedisTemplate.delete(captcharKey); stringRedisTemplate.delete(captcharKey);
return value != null ? new SimpleCaptcha(captchaId, String.valueOf(value)) : null; return value != null ? new SimpleCaptcha(captchaId, String.valueOf(value)) : null;
} }
......
package cn.quantgroup.xyqb.controller; package cn.quantgroup.xyqb.controller;
import cn.quantgroup.xyqb.exception.NullUserException; import cn.quantgroup.xyqb.exception.NullUserException;
import cn.quantgroup.xyqb.exception.PasswordErrorLimitException;
import cn.quantgroup.xyqb.exception.UserNotExistException; import cn.quantgroup.xyqb.exception.UserNotExistException;
import cn.quantgroup.xyqb.exception.VerificationCodeErrorException; import cn.quantgroup.xyqb.exception.VerificationCodeErrorException;
import cn.quantgroup.xyqb.model.JsonResult; import cn.quantgroup.xyqb.model.JsonResult;
...@@ -34,19 +35,33 @@ public class ExceptionHandlingController implements IBaseController { ...@@ -34,19 +35,33 @@ public class ExceptionHandlingController implements IBaseController {
} }
/** /**
* 验证码登陆异常 * 密码错误次数达到上限异常
*
* @param vce
* @return
*/
@ExceptionHandler(PasswordErrorLimitException.class)
public JsonResult passwordErrorLimitException(PasswordErrorLimitException vce) {
LOGGER.info("throw PasswordErrorLimitException,msg={},businessCode={}", vce.getMessage(), 2L);
return JsonResult.buildErrorStateResult(vce.getMessage(), null, 2L);
}
/**
* 密码错误次数过多异常,提升验证级别
* *
* @param vce * @param vce
* @return * @return
*/ */
@ExceptionHandler(VerificationCodeErrorException.class) @ExceptionHandler(VerificationCodeErrorException.class)
public JsonResult verificationCodeErrorException(VerificationCodeErrorException vce) { public JsonResult verificationCodeErrorException(VerificationCodeErrorException vce) {
LOGGER.info("throw VerificationCodeErrorException,msg={},businessCode={}", vce.getMessage(), 1L);
return JsonResult.buildErrorStateResult(vce.getMessage(), null, 1L); return JsonResult.buildErrorStateResult(vce.getMessage(), null, 1L);
} }
@ExceptionHandler(UserNotExistException.class) @ExceptionHandler(UserNotExistException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED) @ResponseStatus(HttpStatus.UNAUTHORIZED)
public JsonResult userNotExistException(UserNotExistException unee) { public JsonResult userNotExistException(UserNotExistException unee) {
LOGGER.info("throw UserNotExistException,msg={},businessCode={},code={}", unee.getMessage(), 1L, 401L);
return new JsonResult(unee.getMessage(), 401L, null); return new JsonResult(unee.getMessage(), 401L, null);
} }
......
...@@ -679,7 +679,7 @@ public class MotanUserServiceImpl implements UserMotanService { ...@@ -679,7 +679,7 @@ public class MotanUserServiceImpl implements UserMotanService {
return returnErrorValue("用户未登录"); return returnErrorValue("用户未登录");
} }
String checkUrl = xyqbAuthUrl+"/innerapi/is_login"; String checkUrl = xyqbAuthUrl+"/innerapi/is_login";
ImmutableMap<String, String> headMap = ImmutableMap.of("x-auth-token", token); ImmutableMap<String, String> headMap = ImmutableMap.of(Constants.X_AUTH_TOKEN, token);
String response = httpService.get(checkUrl, headMap, null); String response = httpService.get(checkUrl, headMap, null);
log.info("去向函谷关查询用户信息,response:[{}]",response); log.info("去向函谷关查询用户信息,response:[{}]",response);
JsonResult result = JSONObject.parseObject(response, JsonResult.class); JsonResult result = JSONObject.parseObject(response, JsonResult.class);
...@@ -722,7 +722,7 @@ public class MotanUserServiceImpl implements UserMotanService { ...@@ -722,7 +722,7 @@ public class MotanUserServiceImpl implements UserMotanService {
}else { }else {
log.info("去向函谷关查询用户信息"); log.info("去向函谷关查询用户信息");
String checkUrl = xyqbAuthUrl+"/innerapi/is_login"; String checkUrl = xyqbAuthUrl+"/innerapi/is_login";
ImmutableMap<String, String> headMap = ImmutableMap.of("x-auth-token", token); ImmutableMap<String, String> headMap = ImmutableMap.of(Constants.X_AUTH_TOKEN, token);
String response = httpService.get(checkUrl, headMap, null); String response = httpService.get(checkUrl, headMap, null);
log.info("去向函谷关查询用户信息,response:[{}]",response); log.info("去向函谷关查询用户信息,response:[{}]",response);
JsonResult result = JSONObject.parseObject(response, JsonResult.class); JsonResult result = JSONObject.parseObject(response, JsonResult.class);
......
package cn.quantgroup.xyqb.controller.external.queryLog; package cn.quantgroup.xyqb.controller.external.queryLog;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.entity.Address; import cn.quantgroup.xyqb.entity.Address;
import cn.quantgroup.xyqb.entity.UserDetail; import cn.quantgroup.xyqb.entity.UserDetail;
import cn.quantgroup.xyqb.entity.UserQueryLog; import cn.quantgroup.xyqb.entity.UserQueryLog;
...@@ -75,7 +76,7 @@ public class UserQueryLogController { ...@@ -75,7 +76,7 @@ public class UserQueryLogController {
public JsonResult queryLog(HttpServletRequest request,@RequestParam(required=false) String beginDate,@RequestParam(required=false) String endDate, Integer pageId, Integer pageSize) { public JsonResult queryLog(HttpServletRequest request,@RequestParam(required=false) String beginDate,@RequestParam(required=false) String endDate, Integer pageId, Integer pageSize) {
LOGGER.info("查询日期:beginDate{},endDate{}",beginDate,endDate); LOGGER.info("查询日期:beginDate{},endDate{}",beginDate,endDate);
String token=request.getHeader("x-auth-token"); String token=request.getHeader(Constants.X_AUTH_TOKEN);
if(token==null||token.equals("")){ if(token==null||token.equals("")){
LOGGER.info("token为空,非法查询"); LOGGER.info("token为空,非法查询");
return JsonResult.buildErrorStateResult("缺少授权信息",null); return JsonResult.buildErrorStateResult("缺少授权信息",null);
...@@ -142,7 +143,7 @@ public class UserQueryLogController { ...@@ -142,7 +143,7 @@ public class UserQueryLogController {
public JsonResult queryForResult(HttpServletRequest request,String key,String keyValues, String columns,Integer pageId,Integer pageSize) { public JsonResult queryForResult(HttpServletRequest request,String key,String keyValues, String columns,Integer pageId,Integer pageSize) {
LOGGER.info("查询条件:key{},columns{}",key,columns); LOGGER.info("查询条件:key{},columns{}",key,columns);
String token=request.getHeader("x-auth-token"); String token=request.getHeader(Constants.X_AUTH_TOKEN);
if(token==null||token.equals("")){ if(token==null||token.equals("")){
LOGGER.info("token为空,非法查询"); LOGGER.info("token为空,非法查询");
return JsonResult.buildErrorStateResult("缺少授权信息",null); return JsonResult.buildErrorStateResult("缺少授权信息",null);
...@@ -372,7 +373,7 @@ public class UserQueryLogController { ...@@ -372,7 +373,7 @@ public class UserQueryLogController {
public JsonResult exportExcel(final HttpServletResponse response, HttpServletRequest request,String key,String keyValues, String columns){ public JsonResult exportExcel(final HttpServletResponse response, HttpServletRequest request,String key,String keyValues, String columns){
String token=request.getHeader("x-auth-token"); String token=request.getHeader(Constants.X_AUTH_TOKEN);
if(token==null||token.equals("")){ if(token==null||token.equals("")){
LOGGER.info("token为空,非法查询"); LOGGER.info("token为空,非法查询");
return JsonResult.buildErrorStateResult("缺少授权信息",null); return JsonResult.buildErrorStateResult("缺少授权信息",null);
......
package cn.quantgroup.xyqb.controller.internal.login; package cn.quantgroup.xyqb.controller.internal.login;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.controller.IBaseController; import cn.quantgroup.xyqb.controller.IBaseController;
import cn.quantgroup.xyqb.entity.User; import cn.quantgroup.xyqb.entity.User;
import cn.quantgroup.xyqb.entity.UserBtRegister; import cn.quantgroup.xyqb.entity.UserBtRegister;
...@@ -15,9 +16,7 @@ import com.google.common.collect.ImmutableMap; ...@@ -15,9 +16,7 @@ import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
...@@ -67,12 +66,12 @@ public class AuthInfoController implements IBaseController { ...@@ -67,12 +66,12 @@ public class AuthInfoController implements IBaseController {
// 函谷关去查token 返回值高仿 // 函谷关去查token 返回值高仿
log.info("去向函谷关查询用户信息"); log.info("去向函谷关查询用户信息");
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("x-auth-token"); String token = request.getHeader(Constants.X_AUTH_TOKEN);
if(StringUtils.isBlank(token) ||token.length() != 36){ if(StringUtils.isBlank(token) ||token.length() != 36){
return JsonResult.buildErrorStateResult("用户未登录",null); return JsonResult.buildErrorStateResult("用户未登录",null);
} }
String checkUrl = xyqbAuthUrl+"/innerapi/is_login"; String checkUrl = xyqbAuthUrl+"/innerapi/is_login";
ImmutableMap<String, String> headMap = ImmutableMap.of("x-auth-token", token); ImmutableMap<String, String> headMap = ImmutableMap.of(Constants.X_AUTH_TOKEN, token);
String response = httpService.get(checkUrl, headMap, null); String response = httpService.get(checkUrl, headMap, null);
log.info("去向函谷关查询用户信息,response:[{}]",response); log.info("去向函谷关查询用户信息,response:[{}]",response);
JsonResult result = JSONObject.parseObject(response, JsonResult.class); JsonResult result = JSONObject.parseObject(response, JsonResult.class);
......
...@@ -138,7 +138,7 @@ public class SmsController implements IBaseController { ...@@ -138,7 +138,7 @@ public class SmsController implements IBaseController {
String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo; String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo;
long expire = redisTemplate.getExpire(key, TimeUnit.MINUTES); long expire = redisTemplate.getExpire(key, TimeUnit.MINUTES);
if (expire >= EXPIRE_MINUTES - 1) { if (expire >= EXPIRE_MINUTES - 1) {
return JsonResult.buildSuccessResult("发送成功", null); return JsonResult.buildErrorStateResult("1分钟内不能重复获取验证码", null);
} }
String randomCode = smsIsDebug ? "0000" : String.valueOf(random.nextInt(8999) + 1000); String randomCode = smsIsDebug ? "0000" : String.valueOf(random.nextInt(8999) + 1000);
String uniqueId = phoneNo + UUID.randomUUID().toString().replaceAll("-", ""); String uniqueId = phoneNo + UUID.randomUUID().toString().replaceAll("-", "");
...@@ -153,7 +153,6 @@ public class SmsController implements IBaseController { ...@@ -153,7 +153,6 @@ public class SmsController implements IBaseController {
smsService.getSmsSender().sendMsg(message); smsService.getSmsSender().sendMsg(message);
redisTemplate.opsForValue().set(key, uniqueId + ":" + randomCode, EXPIRE_MINUTES, TimeUnit.MINUTES); redisTemplate.opsForValue().set(key, uniqueId + ":" + randomCode, EXPIRE_MINUTES, TimeUnit.MINUTES);
deleteRetSendCode(phoneNo);//删除用户重置密码,多次错误逻辑 deleteRetSendCode(phoneNo);//删除用户重置密码,多次错误逻辑
return JsonResult.buildSuccessResult("发送成功", uniqueId); return JsonResult.buildSuccessResult("发送成功", uniqueId);
} catch (Exception e) { } catch (Exception e) {
LOGGER.error("发送短信验证码失败"); LOGGER.error("发送短信验证码失败");
...@@ -175,7 +174,7 @@ public class SmsController implements IBaseController { ...@@ -175,7 +174,7 @@ public class SmsController implements IBaseController {
String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo; String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo;
long expire = redisTemplate.getExpire(key, TimeUnit.MINUTES); long expire = redisTemplate.getExpire(key, TimeUnit.MINUTES);
if (expire >= EXPIRE_MINUTES - 1) { if (expire >= EXPIRE_MINUTES - 1) {
return JsonResult.buildSuccessResult("发送成功", null); return JsonResult.buildErrorStateResult("1分钟内不能重复获取验证码", null);
} }
String randomCode = smsIsDebug ? "0000" : String.valueOf(random.nextInt(8999) + 1000); String randomCode = smsIsDebug ? "0000" : String.valueOf(random.nextInt(8999) + 1000);
String uniqueId = phoneNo + UUID.randomUUID().toString().replaceAll("-", ""); String uniqueId = phoneNo + UUID.randomUUID().toString().replaceAll("-", "");
...@@ -196,7 +195,7 @@ public class SmsController implements IBaseController { ...@@ -196,7 +195,7 @@ public class SmsController implements IBaseController {
*/ */
@CaptchaNewValidator @CaptchaNewValidator
@RequestMapping("/send_login_code_voice_new") @RequestMapping("/send_login_code_voice_new")
public JsonResult sendLoginSmsCodeNew(@RequestParam String phoneNo, @RequestParam(required = false) String registerFrom, public JsonResult sendLoginCodeVoiceNew(@RequestParam String phoneNo, @RequestParam(required = false) String registerFrom,
String usage, @RequestParam(required = false) String deviceId) { String usage, @RequestParam(required = false) String deviceId) {
if (StringUtils.isEmpty(usage) || !"6".equals(usage)) { if (StringUtils.isEmpty(usage) || !"6".equals(usage)) {
LOGGER.error("参数校验失败,用户登录语音验证码usage参数为{}", usage); LOGGER.error("参数校验失败,用户登录语音验证码usage参数为{}", usage);
...@@ -212,39 +211,51 @@ public class SmsController implements IBaseController { ...@@ -212,39 +211,51 @@ public class SmsController implements IBaseController {
*/ */
@CaptchaNewValidator @CaptchaNewValidator
@RequestMapping("/send_login_code_new") @RequestMapping("/send_login_code_new")
public JsonResult sendLoginCodeVoiceNew(@RequestParam String phoneNo, @RequestParam(required = false) String registerFrom, @RequestParam(required = false) String deviceId) { public JsonResult sendLoginSmsCodeNew(@RequestParam String phoneNo, @RequestParam(required = false) String registerFrom, @RequestParam(required = false) String deviceId) {
LOGGER.info("快速登陆-发送验证码, phoneNo:{}, registerFrom:{}", phoneNo, registerFrom);
return sendVerificationCode2New(phoneNo, deviceId, true);
}
/**
* 快速登陆发送短信验证码
*/
@CaptchaNewValidator
@RequestMapping("/send_login_code_new_forH5")
public JsonResult sendLoginSmsCodeNewForH5(@RequestParam String phoneNo, @RequestParam(required = false) String registerFrom, @RequestParam(required = false) String deviceId) {
LOGGER.info("快速登陆-发送验证码, phoneNo:{}, registerFrom:{}", phoneNo, registerFrom); LOGGER.info("快速登陆-发送验证码, phoneNo:{}, registerFrom:{}", phoneNo, registerFrom);
return sendVerificationCode2New(phoneNo, deviceId); return sendVerificationCode2New(phoneNo, deviceId, false);
} }
/** /**
* 新版本验证码 * 新版本验证码
*/ */
private JsonResult sendVerificationCode2New(String phoneNo, String deviceId) { private JsonResult sendVerificationCode2New(String phoneNo, String deviceId, boolean isApp) {
if (!ValidationUtil.validatePhoneNo(phoneNo)) { if (!ValidationUtil.validatePhoneNo(phoneNo)) {
return JsonResult.buildErrorStateResult("手机号格式有误", null); return JsonResult.buildErrorStateResult("手机号格式有误", null);
} }
String verificationPhoneCountKey = Constants.REDIS_SMS_CODE_COUNT + phoneNo; String verificationPhoneCountKey = Constants.REDIS_SMS_CODE_COUNT + phoneNo;
Long getPhoneVerificationCount = redisTemplate.opsForHash().increment(verificationPhoneCountKey, Constants.REDIS_SMS_CODE_COUNT, 1); Long getPhoneVerificationCount = redisTemplate.opsForHash().increment(verificationPhoneCountKey, Constants.REDIS_SMS_CODE_COUNT, 1);
redisTemplate.expire(verificationPhoneCountKey, Constants.ONE_DAY,TimeUnit.SECONDS); redisTemplate.expire(verificationPhoneCountKey, DateUtils.getSeconds(), TimeUnit.SECONDS);
if (getPhoneVerificationCount > PHONE_MAX_PER_DAY) { if (getPhoneVerificationCount > PHONE_MAX_PER_DAY) {
LOGGER.info("您手机号已经达到获取今天短信验证码上限:phoneNo:{},deviceId:{},ip:{}",phoneNo,deviceId,getIp()); LOGGER.info("您手机号已经达到获取今天短信验证码上限:phoneNo:{},deviceId:{},ip:{}",phoneNo,deviceId,getIp());
return JsonResult.buildErrorStateResult("今天已获取20次短信验证码,请使用语音验证码或明天再试", null); return JsonResult.buildErrorStateResult("今天已获取20次短信验证码,请使用语音验证码或明天再试", null);
} }
String verificationIPCountKey = getIp(); String verificationIPCountKey = getIp();
//if (!StringUtils.isEmpty(verificationIPCountKey)) { // Todo - 运维解决真实IP获取问题后,打开这段代码,实现按IP限制短信验证码获取量
// verificationIPCountKey=Constants.REDIS_SMS_IP_COUNT+verificationIPCountKey; // Todo - 另:当前的计数器计数方式为乐观累加,而且还是提前计数,会导致边界值问题,即临界次数会提前一次记满,并且在后续请求到达时计数器会继续计数
// Long getIPVerificationCount = redisTemplate.opsForHash().increment(verificationIPCountKey, Constants.REDIS_SMS_IP_COUNT, 1); /*
// //if (getIPVerificationCount > IP_MAX_PER_DAY) { if (!StringUtils.isEmpty(verificationIPCountKey)) {
// // return JsonResult.buildErrorStateResult("您当前ip已经达到获取今天验证码上限", null); verificationIPCountKey=Constants.REDIS_SMS_IP_COUNT+verificationIPCountKey;
// //} Long getIPVerificationCount = redisTemplate.opsForHash().increment(verificationIPCountKey, Constants.REDIS_SMS_IP_COUNT, 1);
//} if (getIPVerificationCount > IP_MAX_PER_DAY) {
return JsonResult.buildErrorStateResult("您当前ip已经达到获取今天验证码上限", null);
}
}*/
LOGGER.info("请求短信新版本接口:phoneNo:{},deviceId:{},IP:{}",phoneNo,deviceId,getIp()); LOGGER.info("请求短信新版本接口:phoneNo:{},deviceId:{},IP:{}",phoneNo,deviceId,getIp());
if (!StringUtils.isEmpty(deviceId)) { if (!StringUtils.isEmpty(deviceId)) {
String verificationDeviceCountKey = Constants.REDIS_SMS_DEVICE_COUNT + deviceId; String verificationDeviceCountKey = Constants.REDIS_SMS_DEVICE_COUNT + deviceId;
Long getDeviceVerificationCount = redisTemplate.opsForHash().increment(verificationDeviceCountKey, Constants.REDIS_SMS_DEVICE_COUNT, 1); Long getDeviceVerificationCount = redisTemplate.opsForHash().increment(verificationDeviceCountKey, Constants.REDIS_SMS_DEVICE_COUNT, 1);
redisTemplate.expire(verificationDeviceCountKey, Constants.ONE_DAY,TimeUnit.SECONDS); redisTemplate.expire(verificationDeviceCountKey, DateUtils.getSeconds(), TimeUnit.SECONDS);
if (getDeviceVerificationCount > DEVICE_MAX_PER_DAY) { if (getDeviceVerificationCount > DEVICE_MAX_PER_DAY) {
LOGGER.info("您设备已经达到获取今天短信验证码上限:phoneNo:{},deviceId:{},ip:{}",phoneNo,verificationDeviceCountKey,getIp()); LOGGER.info("您设备已经达到获取今天短信验证码上限:phoneNo:{},deviceId:{},ip:{}",phoneNo,verificationDeviceCountKey,getIp());
return JsonResult.buildErrorStateResult("您设备已经达到获取今天短信验证码上限", null); return JsonResult.buildErrorStateResult("您设备已经达到获取今天短信验证码上限", null);
...@@ -254,23 +265,19 @@ public class SmsController implements IBaseController { ...@@ -254,23 +265,19 @@ public class SmsController implements IBaseController {
String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo; String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo;
long expire = redisTemplate.getExpire(key, TimeUnit.MINUTES); long expire = redisTemplate.getExpire(key, TimeUnit.MINUTES);
if (expire >= EXPIRE_MINUTES - 1) { if (expire >= EXPIRE_MINUTES - 1) {
LOGGER.info("sendVerificationCode2New一分钟内重复获取:phoneNo:{},deviceId:{},ip:{}",phoneNo,deviceId,getIp()); LOGGER.info("sendVerificationCode2New1分钟内不能重复获取验证码:phoneNo:{},deviceId:{},ip:{}",phoneNo,deviceId,getIp());
return JsonResult.buildSuccessResult("发送成功", null); return JsonResult.buildErrorStateResult("1分钟内不能重复获取验证码", null);
} }
String randomCode = smsIsDebug ? "0000" : String.valueOf(random.nextInt(8999) + 1000); String randomCode = smsIsDebug ? "0000" : String.valueOf(random.nextInt(8999) + 1000);
String uniqueId = phoneNo + UUID.randomUUID().toString().replaceAll("-", ""); String uniqueId = phoneNo + UUID.randomUUID().toString().replaceAll("-", "");
List<String> newList = new ArrayList<>(); List<String> newList = new ArrayList<>();
newList.add(randomCode); newList.add(randomCode);
/*ConfirmableMsg confirmableMsg = new ConfirmableMsg(
uniqueId, newList, "1", "1", phoneNo
);*/
MsgParams message = new MsgParams(Collections.singletonList(2), phoneNo, "1", "1", Collections.singletonList(randomCode), uniqueId); MsgParams message = new MsgParams(Collections.singletonList(2), phoneNo, "1", "1", Collections.singletonList(randomCode), uniqueId);
try { try {
//smsService.getSmsSender().sendConfirmableMessage(confirmableMsg);
smsService.getSmsSender().sendMsg(message); smsService.getSmsSender().sendMsg(message);
redisTemplate.opsForValue().set(key, uniqueId + ":" + randomCode, EXPIRE_MINUTES, TimeUnit.MINUTES); redisTemplate.opsForValue().set(key, uniqueId + ":" + randomCode, EXPIRE_MINUTES, TimeUnit.MINUTES);
deleteRetSendCode(phoneNo);//删除用户重置密码,多次错误逻辑 deleteRetSendCode(phoneNo);//删除用户重置密码,多次错误逻辑
if(needImageVlidate(verificationIPCountKey,deviceId,phoneNo)){ if(isApp && needImageVlidate(verificationIPCountKey,deviceId,phoneNo)){
return JsonResult.buildSuccessResult("发送成功", uniqueId,0003L); return JsonResult.buildSuccessResult("发送成功", uniqueId,0003L);
} }
LOGGER.info("sendVerificationCode2New获取短信成功:phone:{},deviceId:{},ip:{}",phoneNo,deviceId,getIp()); LOGGER.info("sendVerificationCode2New获取短信成功:phone:{},deviceId:{},ip:{}",phoneNo,deviceId,getIp());
...@@ -304,7 +311,7 @@ public class SmsController implements IBaseController { ...@@ -304,7 +311,7 @@ public class SmsController implements IBaseController {
if (!StringUtils.isEmpty(deviceId)) { if (!StringUtils.isEmpty(deviceId)) {
String verificationDeviceCountKey = Constants.REDIS_VOICE_DEVICE_COUNT + deviceId; String verificationDeviceCountKey = Constants.REDIS_VOICE_DEVICE_COUNT + deviceId;
Long getDeviceVerificationCount = redisTemplate.opsForHash().increment(verificationDeviceCountKey, Constants.REDIS_VOICE_DEVICE_COUNT, 1); Long getDeviceVerificationCount = redisTemplate.opsForHash().increment(verificationDeviceCountKey, Constants.REDIS_VOICE_DEVICE_COUNT, 1);
redisTemplate.expire(verificationDeviceCountKey, Constants.ONE_DAY,TimeUnit.SECONDS); redisTemplate.expire(verificationDeviceCountKey, DateUtils.getSeconds(), TimeUnit.SECONDS);
if (getDeviceVerificationCount > DEVICE_MAX_PER_DAY) { if (getDeviceVerificationCount > DEVICE_MAX_PER_DAY) {
return JsonResult.buildErrorStateResult("您设备已经达到获取今天语音验证码上限", null); return JsonResult.buildErrorStateResult("您设备已经达到获取今天语音验证码上限", null);
} }
...@@ -317,7 +324,7 @@ public class SmsController implements IBaseController { ...@@ -317,7 +324,7 @@ public class SmsController implements IBaseController {
String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo; String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo;
long expire = redisTemplate.getExpire(key, TimeUnit.MINUTES); long expire = redisTemplate.getExpire(key, TimeUnit.MINUTES);
if (expire >= EXPIRE_MINUTES - 1) { if (expire >= EXPIRE_MINUTES - 1) {
return JsonResult.buildSuccessResult("发送成功", null); return JsonResult.buildErrorStateResult("1分钟内不能重复获取验证码", null);
} }
String randomCode = smsIsDebug ? "0000" : String.valueOf(random.nextInt(8999) + 1000); String randomCode = smsIsDebug ? "0000" : String.valueOf(random.nextInt(8999) + 1000);
String uniqueId = phoneNo + UUID.randomUUID().toString().replaceAll("-", ""); String uniqueId = phoneNo + UUID.randomUUID().toString().replaceAll("-", "");
...@@ -359,7 +366,7 @@ public class SmsController implements IBaseController { ...@@ -359,7 +366,7 @@ public class SmsController implements IBaseController {
} }
/** /**
* 删除用户重置密码短信验证错误 * 删除用户重置密码短信验证错误
* @param phoneNo * @param phoneNo
*/ */
private void deleteRetSendCode(String phoneNo){ private void deleteRetSendCode(String phoneNo){
......
package cn.quantgroup.xyqb.controller.internal.token;
import cn.quantgroup.xyqb.controller.IBaseController;
import cn.quantgroup.xyqb.model.JsonResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
/**
* 发放一次性令牌
*
* @author 任文超
* @version 1.0.0
* @since 2017-10-31
*/
@RestController
@RequestMapping("/token")
public class OneTimeTokenController implements IBaseController {
private static final Long SECONDS = 5 * 60L;
@Autowired
@Qualifier("stringRedisTemplate")
private RedisTemplate<String, String> redisTemplate;
/**
* 发放一枚一次性令牌
* One-Time Token用法:http请求首部行添加参数{One-Time-Token 6ac0665b-e19c-4392-a244-7b61690833f5}
*
* @return 一次性令牌
*/
@RequestMapping(value = "/oneTime")
public JsonResult oneTimeToken() {
String token = UUID.randomUUID().toString();
redisTemplate.opsForValue().set(token, Boolean.TRUE.toString(), SECONDS, TimeUnit.SECONDS);
return JsonResult.buildSuccessResult("", token);
}
}
package cn.quantgroup.xyqb.controller.internal.user; package cn.quantgroup.xyqb.controller.internal.user;
import cn.quantgroup.xyqb.Constants; import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.aspect.captcha.CaptchaFineteValidator;
import cn.quantgroup.xyqb.aspect.captcha.PasswordFineteValidator; import cn.quantgroup.xyqb.aspect.captcha.PasswordFineteValidator;
import cn.quantgroup.xyqb.aspect.logcaller.LogHttpCaller; import cn.quantgroup.xyqb.aspect.logcaller.LogHttpCaller;
import cn.quantgroup.xyqb.controller.IBaseController; import cn.quantgroup.xyqb.controller.IBaseController;
...@@ -8,7 +9,9 @@ import cn.quantgroup.xyqb.entity.Merchant; ...@@ -8,7 +9,9 @@ import cn.quantgroup.xyqb.entity.Merchant;
import cn.quantgroup.xyqb.entity.User; import cn.quantgroup.xyqb.entity.User;
import cn.quantgroup.xyqb.entity.UserDetail; import cn.quantgroup.xyqb.entity.UserDetail;
import cn.quantgroup.xyqb.entity.WechatUserInfo; import cn.quantgroup.xyqb.entity.WechatUserInfo;
import cn.quantgroup.xyqb.exception.PasswordErrorLimitException;
import cn.quantgroup.xyqb.exception.UserNotExistException; import cn.quantgroup.xyqb.exception.UserNotExistException;
import cn.quantgroup.xyqb.exception.VerificationCodeErrorException;
import cn.quantgroup.xyqb.model.JsonResult; import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.model.UserModel; import cn.quantgroup.xyqb.model.UserModel;
import cn.quantgroup.xyqb.model.UserRegisterMqMessage; import cn.quantgroup.xyqb.model.UserRegisterMqMessage;
...@@ -39,6 +42,7 @@ import java.util.*; ...@@ -39,6 +42,7 @@ import java.util.*;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* Http服务接口:用户注册、登录、重置密码
* Created by FrankChow on 15/7/5. * Created by FrankChow on 15/7/5.
*/ */
@RestController @RestController
...@@ -69,9 +73,11 @@ public class UserController implements IBaseController { ...@@ -69,9 +73,11 @@ public class UserController implements IBaseController {
@Autowired @Autowired
private IWechatService wechatService; private IWechatService wechatService;
private static final char[] PWD_BASE = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', private static final char[] PWD_BASE = {
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'}; '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") @RequestMapping("/test")
public JsonResult test() { public JsonResult test() {
...@@ -122,12 +128,70 @@ public class UserController implements IBaseController { ...@@ -122,12 +128,70 @@ public class UserController implements IBaseController {
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)",null); 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 @PasswordFineteValidator
@RequestMapping("/login") @RequestMapping("/login")
public JsonResult login( public JsonResult login(
@RequestParam(required = false, defaultValue = "1") Long channelId, String appChannel, @RequestParam(required = false, defaultValue = "1") Long channelId, String appChannel,
@RequestParam(required = false, defaultValue = "1") Long createdFrom, @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 = "") 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); LOGGER.info("user/login,请求参数channelId:{},appChannel:{},createdFrom:{},userId:{},key:{},openId:{},dimension:{},",channelId,appChannel,createdFrom,userId,key,openId,dimension);
Merchant merchant = merchantService.findMerchantByName(key); Merchant merchant = merchantService.findMerchantByName(key);
if (merchant == null) { if (merchant == null) {
...@@ -143,11 +207,13 @@ public class UserController implements IBaseController { ...@@ -143,11 +207,13 @@ public class UserController implements IBaseController {
@RequestMapping("/login/fast") @RequestMapping("/login/fast")
public JsonResult loginFast( public JsonResult loginFast(
@RequestParam(required = false, defaultValue = "1") Long channelId, String appChannel, @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) { @RequestParam(required = false, defaultValue = "1") Long createdFrom,
Map<String, JsonResult> validMap = getHeaderParam(request); @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); LOGGER.info("user/login/fast,请求参数channelId:{},appChannel:{},createdFrom:{},btRegisterChannelId:{},key:{},dimension:{},",channelId,appChannel,createdFrom,btRegisterChannelId,key,dimension);
if (null != validMap.get("fail")) { if (null != validMap.get("fail")) {
return validMap.get("fail"); return validMap.get("fail");
} }
...@@ -157,6 +223,9 @@ public class UserController implements IBaseController { ...@@ -157,6 +223,9 @@ public class UserController implements IBaseController {
} }
JsonResult successResult = validMap.get("success"); JsonResult successResult = validMap.get("success");
String phoneNo = successResult.getData().toString(); String phoneNo = successResult.getData().toString();
String verificationCode = successResult.getMsg();
// 执行短信验证码检查
smsValidForFastLogin(phoneNo, verificationCode);
User user = userService.findByPhoneWithCache(phoneNo); User user = userService.findByPhoneWithCache(phoneNo);
if (user != null && !user.getEnable()) { if (user != null && !user.getEnable()) {
LOGGER.error("用户不存在,或者已经注销,phoneNo:{}",phoneNo); LOGGER.error("用户不存在,或者已经注销,phoneNo:{}",phoneNo);
...@@ -177,7 +246,7 @@ public class UserController implements IBaseController { ...@@ -177,7 +246,7 @@ public class UserController implements IBaseController {
private User registerFastWhenLogin(String phoneNo, Long channelId, Long registerFrom, String appChannel, Long btRegisterChannelId,String dimension) { private User registerFastWhenLogin(String phoneNo, Long channelId, Long registerFrom, String appChannel, Long btRegisterChannelId,String dimension) {
String password = genRandomPwd(); 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)) { if (!ValidationUtil.validatePhoneNo(phoneNo)) {
LOGGER.info("用户快速注册失败,手机号错误, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo); LOGGER.info("用户快速注册失败,手机号错误, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
throw new UserNotExistException("手机号错误"); throw new UserNotExistException("手机号错误");
...@@ -201,14 +270,16 @@ public class UserController implements IBaseController { ...@@ -201,14 +270,16 @@ public class UserController implements IBaseController {
* @return * @return
*/ */
private Map<String, JsonResult> getHeaderParam(HttpServletRequest request) { 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 verificationHeader = "Verification ";
String credential = request.getHeader("authorization"); String credential = request.getHeader("authorization");
if (StringUtils.isBlank(credential)) { if (StringUtils.isBlank(credential)) {
result.put("fail", JsonResult.buildErrorStateResult("登录失败", null)); result.put("fail", JsonResult.buildErrorStateResult("登录失败", null));
return result;
} }
if (!credential.startsWith(verificationHeader)) { if (!credential.startsWith(verificationHeader)) {
result.put("fail", JsonResult.buildErrorStateResult("登录失败", null)); result.put("fail", JsonResult.buildErrorStateResult("登录失败", null));
return result;
} }
credential = credential.substring(verificationHeader.length(), credential.length()); credential = credential.substring(verificationHeader.length(), credential.length());
byte[] buf = Base64.decodeBase64(credential); byte[] buf = Base64.decodeBase64(credential);
...@@ -216,51 +287,19 @@ public class UserController implements IBaseController { ...@@ -216,51 +287,19 @@ public class UserController implements IBaseController {
String[] credentialArr = credential.split(":"); String[] credentialArr = credential.split(":");
if (credentialArr.length != 2) { if (credentialArr.length != 2) {
result.put("fail", JsonResult.buildErrorStateResult("登录失败", null)); result.put("fail", JsonResult.buildErrorStateResult("登录失败", null));
return result;
} }
String phoneNo = credentialArr[0]; String phoneNo = credentialArr[0];
String verificationCode = credentialArr[1]; String verificationCode = credentialArr[1];
LOGGER.info("用户快速登录,phoneNo:{} , verificationCode:{}", phoneNo, verificationCode); LOGGER.info("用户快速登录,phoneNo:{} , verificationCode:{}", phoneNo, verificationCode);
if (!ValidationUtil.validatePhoneNo(phoneNo)) { if (!ValidationUtil.validatePhoneNo(phoneNo) || StringUtils.isBlank(verificationCode)) {
result.put("fail", JsonResult.buildErrorStateResult("登录失败", null)); result.put("fail", JsonResult.buildErrorStateResult("登录失败", null));
return result;
} }
// 校验短信密码 result.put("success", JsonResult.buildSuccessResult(verificationCode, phoneNo));
validateFastLoginVerificationCode(result, phoneNo, verificationCode);
result.put("success", JsonResult.buildSuccessResult("", phoneNo));
return result; return result;
} }
/**
* 短信密码校验
* @param result - Map
* @param phoneNo - 登录手机号
* @param verificationCode - 短信密码
*/
private void validateFastLoginVerificationCode(Map<String, JsonResult> result, String phoneNo, String verificationCode) {
if (smsService.validateFastLoginVerificationCode(phoneNo, verificationCode)) {
return;
}
// 短信密码错误时,给该账号添加计数器
String passwordErrorCountKey = Constants.REDIS_PASSWORD_ERROR_COUNT + phoneNo;
if (!stringRedisTemplate.hasKey(passwordErrorCountKey)) {
stringRedisTemplate.opsForValue().set(passwordErrorCountKey, String.valueOf(0), Constants.ONE_DAY, TimeUnit.SECONDS);
}
LOGGER.info("用户快速登录,验证码校验失败,phoneNo:{} , verificationCode:{}", phoneNo, verificationCode);
// 密码错误计数
Long errorCount = stringRedisTemplate.opsForValue().increment(passwordErrorCountKey, 1L);
if(errorCount >= Constants.Image_Need_Count){
// 短信密码错误次数超过上限,执行销毁
String verificationCodeKey = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo;
stringRedisTemplate.delete(verificationCodeKey);
// 短信密码错误计数器归零
stringRedisTemplate.opsForValue().set(passwordErrorCountKey, String.valueOf(0));
stringRedisTemplate.expire(passwordErrorCountKey, Constants.ONE_DAY, TimeUnit.SECONDS);
result.put("fail", JsonResult.buildErrorStateResult("错误次数过多,请重新获取短信验证码", null));
}else{
result.put("fail", JsonResult.buildErrorStateResult("验证码不正确", null));
}
}
/** /**
* 用户快速注册 * 用户快速注册
* *
...@@ -269,6 +308,7 @@ public class UserController implements IBaseController { ...@@ -269,6 +308,7 @@ public class UserController implements IBaseController {
* @param channelId * @param channelId
* @return * @return
*/ */
@LogHttpCaller
@RequestMapping("/register/fast") @RequestMapping("/register/fast")
public JsonResult registerFast(@RequestParam String phoneNo, @RequestParam String verificationCode, @RequestParam(required = false) Long channelId, 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, @RequestParam(required = false) Long registerFrom, @RequestParam(required = false, defaultValue = "") String appChannel,
...@@ -290,27 +330,22 @@ public class UserController implements IBaseController { ...@@ -290,27 +330,22 @@ public class UserController implements IBaseController {
if (null == registerFrom) { if (null == registerFrom) {
registerFrom = 1L; registerFrom = 1L;
} }
smsValidForFastLogin(phoneNo, verificationCode);
if (userService.exist(phoneNo)) { if (userService.exist(phoneNo)) {
LOGGER.info("用户快速注册失败,该手机号已经被注册, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo); LOGGER.info("用户快速注册失败,该手机号已经被注册, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildErrorStateResult("该手机号已经被注册", null); 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)) { if (!userService.register(phoneNo, password, registerFrom, getIp(), channelId,btRegisterChannelId,dimension)) {
LOGGER.info("用户快速注册失败,请稍后重试, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo); LOGGER.info("用户快速注册失败,请稍后重试, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildErrorStateResult("注册失败,请稍后重试", null); return JsonResult.buildErrorStateResult("注册失败,请稍后重试", null);
} }
LOGGER.info("用户快速注册成功, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo); LOGGER.info("用户快速注册成功, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildSuccessResult(null, null); return JsonResult.buildSuccessResult(null, null);
} }
/** /**
* 用户注册 * 用户注册
* *
* @param phoneNo * @param phoneNo
* @param password * @param password
...@@ -339,34 +374,28 @@ public class UserController implements IBaseController { ...@@ -339,34 +374,28 @@ public class UserController implements IBaseController {
if (null == registerFrom) { if (null == registerFrom) {
registerFrom = 1L; registerFrom = 1L;
} }
smsValidForRegister(phoneNo, verificationCode);
if (userService.exist(phoneNo)) { if (userService.exist(phoneNo)) {
LOGGER.info("用户注册失败,该手机号已经被注册, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo); LOGGER.info("用户注册失败,该手机号已经被注册, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildErrorStateResult("该手机号已经被注册", null); 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)) { if (!userService.register(phoneNo, password, registerFrom, getIp(), channelId,btRegisterChannelId,dimension)) {
LOGGER.info("用户快速注册失败,请稍后重试, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo); LOGGER.info("用户快速注册失败,请稍后重试, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildErrorStateResult("注册失败,请稍后重试", null); return JsonResult.buildErrorStateResult("注册失败,请稍后重试", null);
} }
LOGGER.info("用户注册成功, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo); LOGGER.info("用户注册成功, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
return JsonResult.buildSuccessResult(null, null); return JsonResult.buildSuccessResult(null, null);
} }
/** /**
* 检查用户是否存在 * 检查用户是否存在
* *
* @param phoneNo * @param phoneNo 手机号
* @return * @return
*/ */
@RequestMapping("/exist") @RequestMapping("/exist")
public JsonResult exist(@RequestParam String phoneNo) { public JsonResult exist(@RequestParam String phoneNo) {
LOGGER.info("检查用户是否存在, phoneNo:{}", phoneNo); LOGGER.info("检查用户是否存在, phoneNo:{}", phoneNo);
if (userService.exist(phoneNo)) { if (userService.exist(phoneNo)) {
LOGGER.info("该手机号已经注册, phoneNo:{}", phoneNo); LOGGER.info("该手机号已经注册, phoneNo:{}", phoneNo);
return JsonResult.buildErrorStateResult("该手机号已经注册", null); return JsonResult.buildErrorStateResult("该手机号已经注册", null);
...@@ -374,11 +403,10 @@ public class UserController implements IBaseController { ...@@ -374,11 +403,10 @@ public class UserController implements IBaseController {
return JsonResult.buildSuccessResult(null, null); return JsonResult.buildSuccessResult(null, null);
} }
/** /**
* 检查用户是否存在 * 检查用户是否存在
* *
* @param phoneNo * @param phoneNo 手机号
* @return * @return
*/ */
@RequestMapping("/exist_check") @RequestMapping("/exist_check")
...@@ -395,6 +423,7 @@ public class UserController implements IBaseController { ...@@ -395,6 +423,7 @@ public class UserController implements IBaseController {
* @param verificationCode * @param verificationCode
* @return * @return
*/ */
@LogHttpCaller
@RequestMapping("/reset_password") @RequestMapping("/reset_password")
public JsonResult resetPassword(@RequestParam String phoneNo, public JsonResult resetPassword(@RequestParam String phoneNo,
@RequestParam String password, @RequestParam String password,
...@@ -409,13 +438,10 @@ public class UserController implements IBaseController { ...@@ -409,13 +438,10 @@ public class UserController implements IBaseController {
if (password.length() < 6 || password.length() > 12) { if (password.length() < 6 || password.length() > 12) {
return JsonResult.buildErrorStateResult("密码应为6-12位", null); return JsonResult.buildErrorStateResult("密码应为6-12位", null);
} }
if (!smsService.validRegisterOrResetPasswdVerificationCode(phoneNo, verificationCode)) { smsValidForRegister(phoneNo, verificationCode);
if(needRetSendCode(phoneNo)){ if (!userService.exist(phoneNo)) {
String key = Constants.REDIS_PREFIX_VERIFICATION_CODE + phoneNo; LOGGER.info("修改密码失败,该手机号尚未注册, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo);
stringRedisTemplate.delete(key); return JsonResult.buildErrorStateResult("该手机号尚未注册", null);
return JsonResult.buildErrorStateResult("错误次数过多,请重新获取短信验证码", null);
}
return JsonResult.buildErrorStateResult("短信验证码错误", null);
} }
if (!userService.resetPassword(phoneNo, password)) { if (!userService.resetPassword(phoneNo, password)) {
return JsonResult.buildErrorStateResult("修改密码失败", null); return JsonResult.buildErrorStateResult("修改密码失败", null);
...@@ -426,23 +452,6 @@ public class UserController implements IBaseController { ...@@ -426,23 +452,6 @@ public class UserController implements IBaseController {
return JsonResult.buildSuccessResult(null, null); 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是否已经过期不存在了 * 检查token是否已经过期不存在了
* *
...@@ -503,13 +512,13 @@ public class UserController implements IBaseController { ...@@ -503,13 +512,13 @@ public class UserController implements IBaseController {
if (null == registerFrom) { if (null == registerFrom) {
registerFrom = 1L; registerFrom = 1L;
} }
LOGGER.info("用户快速注册成功, registerFrom:{}, phoneNo:{}", registerFrom, phoneNo); User newUser = userService.registerAndReturn(phoneNo, password, registerFrom);
if(newUser != null && newUser.getId() != null && newUser.getId() > 0){
return userService.registerAndReturn(phoneNo, password, registerFrom); 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) { private JsonResult loginWithHttpBasic(Long channelId, String appChannel, Long createdFrom, Merchant merchant, HttpServletRequest request, String openId,String dimension) {
User user = verificateUserNameAndPassword(request, openId); User user = verificateUserNameAndPassword(request, openId);
if (user == null) { if (user == null) {
...@@ -537,20 +546,26 @@ public class UserController implements IBaseController { ...@@ -537,20 +546,26 @@ public class UserController implements IBaseController {
} }
String[] credentialArr = bufStr.split(":"); String[] credentialArr = bufStr.split(":");
if (credentialArr.length != 2) { if (credentialArr.length != 2) {
LOGGER.info("用户登录失败:{}", bufStr);
// 向该ipv4添加错误计数器 // 向该ipv4添加错误计数器
countErrorByIpv4(); countErrorByIpv4();
return null; return null;
} }
String userName = credentialArr[0]; LOGGER.info("用户正在登录... [{}]", credentialArr);
String phoneNo = credentialArr[0];
String pass = credentialArr[1]; String pass = credentialArr[1];
User user = userService.findByPhoneWithCache(userName); User user = userService.findByPhoneWithCache(phoneNo);
if (user == null || !user.getEnable()) { if (user == null || !user.getEnable()) {
// 向该phoneNo添加错误计数器
countErrorByPhoneNo(phoneNo);
// 向该ipv4添加错误计数器 // 向该ipv4添加错误计数器
countErrorByIpv4(); countErrorByIpv4();
return null; return null;
} }
//验证密码 //验证密码
if (!validatePassword(pass, user.getPassword())) { if (!validatePassword(pass, user.getPassword())) {
// 向该phoneNo添加错误计数器
countErrorByPhoneNo(phoneNo);
// 向该ipv4添加错误计数器 // 向该ipv4添加错误计数器
countErrorByIpv4(); countErrorByIpv4();
return null; return null;
...@@ -558,13 +573,34 @@ public class UserController implements IBaseController { ...@@ -558,13 +573,34 @@ public class UserController implements IBaseController {
return user; 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添加错误计数器 * 向该ipv4添加错误计数器
*/ */
private void countErrorByIpv4() { private void countErrorByIpv4() {
// if(!ValidationUtil.isAtDangerousTime()){ // Todo -- 全天候开放监控
// return; /*if(!ValidationUtil.isAtDangerousTime()){
// } return;
}*/
String ipv4 = getIp(); String ipv4 = getIp();
if (StringUtils.isNotBlank(ipv4) && !ValidationUtil.validateLocalIpv4(ipv4)) { if (StringUtils.isNotBlank(ipv4) && !ValidationUtil.validateLocalIpv4(ipv4)) {
String ipv4Key = getIpKey(getIp()); String ipv4Key = getIpKey(getIp());
...@@ -639,4 +675,55 @@ public class UserController implements IBaseController { ...@@ -639,4 +675,55 @@ public class UserController implements IBaseController {
return JsonResult.buildSuccessResult(null, null); 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);
String verificationCountKey = Constants.REDIS_VERIFICATION_COUNT + phoneNo;
stringRedisTemplate.opsForHash().delete(verificationCountKey, Constants.REDIS_VERIFICATION_COUNT);
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 >= Constants.VERIFICATION_CODE_FINITE_COUNT);
}
} }
package cn.quantgroup.xyqb.exception; package cn.quantgroup.xyqb.exception;
/** /**
* @author mengfan.feng * 密码错误次数达到上限异常
* @time 2015-09-08 17:49 * @author 任文超
* @time 2017-11-10
*/ */
public class PasswordErrorException extends RuntimeException { public class PasswordErrorLimitException extends RuntimeException {
private static final long serialVersionUID = -1L; private static final long serialVersionUID = -1L;
public PasswordErrorException(String msg, Throwable t) { public PasswordErrorLimitException(String msg, Throwable t) {
super(msg, t); super(msg, t);
} }
public PasswordErrorException(String msg) { public PasswordErrorLimitException(String msg) {
super(msg); super(msg);
} }
} }
...@@ -26,8 +26,9 @@ import java.io.PrintWriter; ...@@ -26,8 +26,9 @@ import java.io.PrintWriter;
public class RequestFilter implements Filter { public class RequestFilter implements Filter {
private static final String[] ALLOWED_PATTERNS = { private static final String[] ALLOWED_PATTERNS = {
"/user_detail/**","/hello/**","/innerapi/**", "/user/exist", "/motan/**", "/user/register", "/user/login", "/user/register/fast","/auth/info/login", "/user_detail/**","/hello/**","/innerapi/**", "/user/exist", "/motan/**", "/user/register", "/user/login", "/user/register/fast",
"/user/login/fast","/user/reset_password", "/user/exist_check","/user/center/**","/user/lock_ipv4", "/token/oneTime", "/user/loginV1", "/user/login/fastV1","/user/**","/api/sms/send_login_code_new_forH5","/user/lock_ipv4",
"/auth/info/login","/user/login/fast","/user/reset_password", "/user/exist_check","/user/center/**",
"/jr58/**", "/app/login", "/app/login_super","/app/login2","/user/login2", "/wechat/**", "/config/**", "/api/**", "/user/exists_token","/query/**", "/jr58/**", "/app/login", "/app/login_super","/app/login2","/user/login2", "/wechat/**", "/config/**", "/api/**", "/user/exists_token","/query/**",
"/platform/api/page/return_url", "/MP_" + "/platform/api/page/return_url", "/MP_" +
"verify_AWiagUn4kZiwmTt0.txt" "verify_AWiagUn4kZiwmTt0.txt"
......
...@@ -63,8 +63,8 @@ public class JsonResult implements Serializable { ...@@ -63,8 +63,8 @@ public class JsonResult implements Serializable {
return new JsonResult(msg, SUCCESS_CODE, data, SUCCESS_BUSSINESS_CODE); return new JsonResult(msg, SUCCESS_CODE, data, SUCCESS_BUSSINESS_CODE);
} }
public static JsonResult buildSuccessResult(String msg, Object data, Long bussinessId) { public static JsonResult buildSuccessResult(String msg, Object data, Long businessCode) {
return new JsonResult(msg, SUCCESS_CODE, data, bussinessId); return new JsonResult(msg, SUCCESS_CODE, data, businessCode);
} }
/** /**
...@@ -78,12 +78,12 @@ public class JsonResult implements Serializable { ...@@ -78,12 +78,12 @@ public class JsonResult implements Serializable {
return new JsonResult(msg, SUCCESS_CODE, data, ERROR_BUSSINESS_CODE); return new JsonResult(msg, SUCCESS_CODE, data, ERROR_BUSSINESS_CODE);
} }
public static JsonResult buildErrorStateResult(String msg, Object data, Long busniessId) { public static JsonResult buildErrorStateResult(String msg, Object data, Long businessCode) {
return new JsonResult(msg, SUCCESS_CODE, data, busniessId); return new JsonResult(msg, SUCCESS_CODE, data, businessCode);
} }
public static JsonResult buildFatalErrorStateResult(String msg, Object data, Long busniessId) { public static JsonResult buildFatalErrorStateResult(String msg, Object data, Long businessCode) {
return new JsonResult(msg, ERROR_STATE_CODE, data, busniessId); return new JsonResult(msg, ERROR_STATE_CODE, data, businessCode);
} }
public String getMsg() { public String getMsg() {
......
...@@ -118,7 +118,7 @@ public class SmsServiceImpl implements ISmsService { ...@@ -118,7 +118,7 @@ public class SmsServiceImpl implements ISmsService {
//smsSender.confirmSmsResult("1", unqiueId); //smsSender.confirmSmsResult("1", unqiueId);
LOGGER.info("confirmMsg send success, uniqueId={}", unqiueId); LOGGER.info("confirmMsg send success, uniqueId={}", unqiueId);
} catch (Exception e) { } catch (Exception e) {
LOGGER.info("短信验证短信中心确认失效"); LOGGER.info("短信验证短信中心确认失效");
} }
if (StringUtils.equals(code, smsVerificationCode)) { if (StringUtils.equals(code, smsVerificationCode)) {
return true; return true;
......
...@@ -27,7 +27,7 @@ public class XyqbSessionContextHolder { ...@@ -27,7 +27,7 @@ public class XyqbSessionContextHolder {
return threadSession.get(); return threadSession.get();
} }
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("x-auth-token"); String token = request.getHeader(Constants.X_AUTH_TOKEN);
if (token == null || token.length() != 36) { if (token == null || token.length() != 36) {
return null; return null;
} }
...@@ -54,7 +54,7 @@ public class XyqbSessionContextHolder { ...@@ -54,7 +54,7 @@ public class XyqbSessionContextHolder {
public static SessionStruct getXSessionFromRedis(){ public static SessionStruct getXSessionFromRedis(){
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("x-auth-token"); String token = request.getHeader(Constants.X_AUTH_TOKEN);
if (token == null || token.length() != 36) { if (token == null || token.length() != 36) {
return null; return null;
} }
......
...@@ -34,6 +34,9 @@ public class SimpleCaptcha extends ImageCaptcha { ...@@ -34,6 +34,9 @@ public class SimpleCaptcha extends ImageCaptcha {
} }
private Boolean validateResponse(String response) { private Boolean validateResponse(String response) {
if(StringUtils.isBlank(this.response) || StringUtils.isBlank(response)){
return false;
}
return StringUtils.equals(this.response, response); return StringUtils.equals(this.response, response);
} }
......
...@@ -7,7 +7,7 @@ import java.util.Calendar; ...@@ -7,7 +7,7 @@ import java.util.Calendar;
*/ */
public class DateUtils { public class DateUtils {
/** /**
* 计算当前时间到当天23:59:59时间差, * 计算当前时间到当天 23:59:59.999 时间差,
* 返回时间差(单位秒) * 返回时间差(单位秒)
* @return * @return
*/ */
...@@ -16,9 +16,10 @@ public class DateUtils { ...@@ -16,9 +16,10 @@ public class DateUtils {
endOfDay.set(Calendar.HOUR_OF_DAY, 23); endOfDay.set(Calendar.HOUR_OF_DAY, 23);
endOfDay.set(Calendar.MINUTE, 59); endOfDay.set(Calendar.MINUTE, 59);
endOfDay.set(Calendar.SECOND, 59); endOfDay.set(Calendar.SECOND, 59);
endOfDay.set(Calendar.MILLISECOND, 999);
long timeStamp = endOfDay.getTimeInMillis(); long timeStamp = endOfDay.getTimeInMillis();
Calendar current = Calendar.getInstance(); Calendar current = Calendar.getInstance();
long now = current.getTimeInMillis(); long now = System.currentTimeMillis();
long during = (timeStamp - now) / 1000; long during = (timeStamp - now) / 1000;
return during; return during;
} }
......
...@@ -26,7 +26,7 @@ public class ValidationUtil { ...@@ -26,7 +26,7 @@ public class ValidationUtil {
private static Pattern localIpv4Pattern = Pattern.compile(localIpv4RegExp); private static Pattern localIpv4Pattern = Pattern.compile(localIpv4RegExp);
public static boolean validatePhoneNo(String phoneNo) { public static boolean validatePhoneNo(String phoneNo) {
boolean lengthValid = StringUtils.isNotEmpty(phoneNo) && phoneNo.length() == 11 && StringUtils.isNumeric(phoneNo); boolean lengthValid = StringUtils.isNotBlank(phoneNo) && phoneNo.length() == 11 && StringUtils.isNumeric(phoneNo);
if (!lengthValid) { if (!lengthValid) {
return false; return false;
} }
......
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
public class CommonTests {
@Test
public void compileBooleanAndNull() {
Assert.assertFalse(null instanceof Boolean);
Assert.assertNotEquals(null, Boolean.TRUE);
Assert.assertNotEquals(null, Boolean.FALSE);
}
@Test
public void print() {
System.out.println(null instanceof Boolean);
System.out.println(Boolean.TRUE.equals(null));
System.out.println(Boolean.FALSE.equals(null));
}
}
package login;
import cn.quantgroup.xyqb.Bootstrap;
import cn.quantgroup.xyqb.Constants;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.octo.captcha.service.CaptchaServiceException;
import org.apache.commons.lang3.StringUtils;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import java.nio.charset.Charset;
import java.util.Base64;
import java.util.Optional;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Bootstrap.class)
@WebAppConfiguration
public class LoginForH5Tests {
final String phoneNo = "13461067662";
final String userName = "root";
final String password = "!QAZ2wsx";
private MockMvc mvc;
@Autowired
WebApplicationContext webApplicationConnect;
@Before
public void setUp() throws JsonProcessingException {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationConnect).build();
}
/**
* 测试Server是否可达
* @throws Exception
*/
@Test
public void testServer() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
mvc.perform(MockMvcRequestBuilders.get("/user/loginForH5").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
mvc.perform(MockMvcRequestBuilders.get("/user/login/fastForH5").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
mvc.perform(MockMvcRequestBuilders.get("/api/captcha").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
mvc.perform(MockMvcRequestBuilders.get("/api/sms/send_login_code").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
/**
* 测试图形验证码账密登录
* @throws Exception
*/
@Test
public void testLoginFoH5() throws Exception{
Assert.assertTrue(false);
}
/**
* 测试TokenOnce切面
* @throws Exception
*/
@Test
public void testLoginFastFoH5() throws Exception{
// 获取TokenOnce
String oneTimeTokenUri = "/token/oneTime";
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get(oneTimeTokenUri).accept(MediaType.APPLICATION_JSON)
.param("phoneNo", phoneNo))
.andExpect(status().isOk())
.andReturn();
String content = mvcResult.getResponse().getContentAsString();
JSONObject jsonResult = JSON.parseObject(new String(content));
Object code = jsonResult.get("code");
Assert.assertEquals("0000", code);
Object data = jsonResult.get("data");
Assert.assertNotNull(data);
String oneTimeToken = String.valueOf(data);
Assert.assertNotEquals("", oneTimeToken);
String smsUri = "/api/sms/send_login_code";
mvcResult = mvc.perform(MockMvcRequestBuilders.get(oneTimeTokenUri).accept(MediaType.APPLICATION_JSON)
.param("phoneNo", phoneNo))
.andExpect(status().isOk())
.andReturn();
content = mvcResult.getResponse().getContentAsString();
jsonResult = JSON.parseObject(new String(content));
code = jsonResult.get("code");
Assert.assertEquals("0000", code);
data = jsonResult.get("data");
Assert.assertNotNull(data);
String verificationCode = "1234";
StringBuilder verificationBuilder = new StringBuilder();
String authorization = "Verification " + new String(Base64.getEncoder().encodeToString(verificationBuilder.append(phoneNo).append(":").append(verificationCode).toString().getBytes(Charset.forName("UTF-8"))));
// 第一次使用TokenOnce
String aspectUri = "/user/login/fastForH5";
mvcResult = mvc.perform(MockMvcRequestBuilders.get(aspectUri).accept(MediaType.APPLICATION_JSON)
.header(Constants.ONE_TIME_TOKEN, oneTimeToken)
.header("authorization", authorization))
.andExpect(status().isOk())
.andReturn();
content = mvcResult.getResponse().getContentAsString();
jsonResult = JSON.parseObject(new String(content));
code = jsonResult.get("code");
Object businessCode = jsonResult.get("businessCode");
Assert.assertEquals("0000", code);
Assert.assertNotEquals("0002", businessCode);
// 使用过期的TokenOnce与verificationCode
mvcResult = mvc.perform(MockMvcRequestBuilders.get(aspectUri).accept(MediaType.APPLICATION_JSON)
.header(Constants.ONE_TIME_TOKEN, oneTimeToken)
.header("authorization", authorization))
.andExpect(status().isOk())
.andReturn();
content = mvcResult.getResponse().getContentAsString();
jsonResult = JSON.parseObject(new String(content));
code = jsonResult.get("code");
Assert.assertEquals("0000", code);
businessCode = jsonResult.get("businessCode");
Assert.assertEquals("0002", businessCode);
// 不使用TokenOnce和verificationCode
mvcResult = mvc.perform(MockMvcRequestBuilders.get(aspectUri).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn();
content = mvcResult.getResponse().getContentAsString();
jsonResult = JSON.parseObject(new String(content));
code = jsonResult.get("code");
Assert.assertEquals("0000", code);
businessCode = jsonResult.get("businessCode");
Assert.assertEquals("0002", businessCode);
}
}
package login;
import java.nio.charset.Charset;
import java.util.Base64;
public class TestStringCode {
public static void main(String[] args) {
System.out.println(base64("13511112222", "000000"));
System.out.println(base64("18022223333", "000000"));
}
final static String AUTHORIZATION = "authorization";
final static String PREFIX = "Basic ";
/*
* 4.153
* 13576450525 123456 318e235d3e52648b236faa3f748000d5
* 13724823305 123456 318e235d3e52648b236faa3f748000d5
*
* 4.155
* 13511112222 000000 c8937b92506c0e2918de053dea69edd3
* 18022223333 000000 c8937b92506c0e2918de053dea69edd3
*/
final static String base64(String account, String password) {
String authorization = PREFIX + new String(Base64.getEncoder().encodeToString((account+":"+password).getBytes(Charset.forName("UTF-8"))));
return authorization;
}
}
package token;
import cn.quantgroup.xyqb.Bootstrap;
import cn.quantgroup.xyqb.Constants;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import java.nio.charset.Charset;
import java.util.Base64;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Bootstrap.class)
@WebAppConfiguration
public class OneTimeTokenTests {
final String userName = "root";
final String password = "!QAZ2wsx";
final String phoneNo = "13461067662";
private MockMvc mvc;
@Autowired
WebApplicationContext webApplicationConnect;
@Before
public void setUp() throws JsonProcessingException {
mvc = MockMvcBuilders.webAppContextSetup(webApplicationConnect).build();
}
/**
* 测试Server是否可达
* @throws Exception
*/
@Test
public void testServer() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
mvc.perform(MockMvcRequestBuilders.get("/token/oneTime").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
/**
* 测试OneTime-Token发放服务
* @throws Exception
*/
@Test
public void testOneTimeToken() throws Exception{
String tokenOnceUri = "/token/oneTime";
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get(tokenOnceUri).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn();
String content = mvcResult.getResponse().getContentAsString();
JSONObject jsonResult = JSON.parseObject(new String(content));
Object code = jsonResult.get("code");
Assert.assertEquals("0000", code);
Object data = jsonResult.getString("data");
Assert.assertNotNull(data);
String oneTimeToken = String.valueOf(data);
Assert.assertNotEquals("", oneTimeToken);
}
/**
* 测试OneTime-Token切面
* @throws Exception
*/
// TODO 用户注册先不加OneTime-Token校验,进一步确认后再添加或删除本用例
//@Test
public void testAspect() throws Exception{
// 获取OneTime-Token
String oneTimeTokenUri = "/token/oneTime";
MvcResult mvcResult = mvc.perform(MockMvcRequestBuilders.get(oneTimeTokenUri).accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andReturn();
String content = mvcResult.getResponse().getContentAsString();
JSONObject jsonResult = JSON.parseObject(new String(content));
Object code = jsonResult.get("code");
Assert.assertEquals("0000", code);
Object data = jsonResult.getString("data");
Assert.assertNotNull(data);
String oneTimeToken = String.valueOf(data);
Assert.assertNotEquals("", oneTimeToken);
// 第一次使用OneTime-Token
String aspectUri = "/user/loginForH5";
mvcResult = mvc.perform(MockMvcRequestBuilders.get(aspectUri).accept(MediaType.APPLICATION_JSON)
.param(Constants.ONE_TIME_TOKEN, oneTimeToken)
.param("phoneNo", userName)
.param("password", password))
.andExpect(status().isOk())
.andReturn();
content = mvcResult.getResponse().getContentAsString();
jsonResult = JSON.parseObject(new String(content));
code = jsonResult.get("code");
Object businessCode = jsonResult.get("businessCode");
Assert.assertEquals("0000", code);
Assert.assertNotEquals("0002", businessCode);
// 使用过期的TokenOnce
mvcResult = mvc.perform(MockMvcRequestBuilders.get(aspectUri).accept(MediaType.APPLICATION_JSON)
.param(Constants.ONE_TIME_TOKEN, oneTimeToken)
.param("phoneNo", userName)
.param("password", password))
.andExpect(status().isOk())
.andReturn();
content = mvcResult.getResponse().getContentAsString();
jsonResult = JSON.parseObject(new String(content));
code = jsonResult.get("code");
Assert.assertEquals("0000", code);
businessCode = jsonResult.get("businessCode");
Assert.assertEquals("0002", businessCode);
// 不使用TokenOnce
mvcResult = mvc.perform(MockMvcRequestBuilders.get(aspectUri).accept(MediaType.APPLICATION_JSON)
.param("phoneNo", userName)
.param("password", password))
.andExpect(status().isOk())
.andReturn();
content = mvcResult.getResponse().getContentAsString();
jsonResult = JSON.parseObject(new String(content));
code = jsonResult.get("code");
Assert.assertEquals("0000", code);
businessCode = jsonResult.get("businessCode");
Assert.assertEquals("0002", businessCode);
}
}
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