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);
......
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.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