Commit 2d1a4134 authored by 技术部-任文超's avatar 技术部-任文超

Merge branch 'master' into feature/20171121

parents 24342a64 0656edcf
......@@ -41,16 +41,22 @@ public interface Constants {
String X_AUTH_TOKEN = "x-auth-token";
String ONE_TIME_TOKEN = "oneTimeToken";
// -- Start -- IPV4安全策略常量组
String REDIS_PASSWORD_ERROR_COUNT = "password_error_count:";
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:";
Long IPV4_LOCK_MINUTES = 6 * 60L;
Long IPV4_LOCK_MINUTES = 3 * 60L;
Long IPV4_COUNT_MINUTES = 1L;
Long IPV4_LOCK_ON_COUNTS = 200L;
Long IPV4_LOCK_ON_COUNTS = 60L;
int DANGEROUS_TIME_START = 22;
int DANGEROUS_TIME_END = 6;
String CLEAR_LOCK_FOR_IPV4 = "x-clear-lock-11241842-y";
String CLEAR_LOCK_FOR_IPV4_KEY = "lhp.family.dwy.sjs.yym.cxy.cpg";
// -- End -- IPV4安全策略常量组
/**
* redis中token的key值前缀
*/
......
package cn.quantgroup.xyqb.aspect.captcha;
package cn.quantgroup.xyqb.aspect.lock;
import cn.quantgroup.xyqb.Constants;
......@@ -39,7 +39,7 @@ public class PasswordErrorFiniteValidateAdvisor {
/**
* 密码错误限次切面
*/
@Pointcut("@annotation(cn.quantgroup.xyqb.aspect.captcha.PasswordFineteValidator)")
@Pointcut("@annotation(cn.quantgroup.xyqb.aspect.lock.PasswordFineteValidator)")
private void passwordErrorFiniteValidate() {
}
......@@ -59,9 +59,19 @@ public class PasswordErrorFiniteValidateAdvisor {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
// 客户端IP
String clientIp = getIp(request);
if (StringUtils.startsWith(clientIp, "139.198.")){
// 入口服务器IP
if(StringUtils.startsWith(clientIp, "139.198.")){
return pjp.proceed();
}
// 白名单
if(redisTemplate.opsForSet().isMember(Constants.IPV4_LOCK_WHITE, clientIp)){
return pjp.proceed();
}
// 黑名单
if(redisTemplate.opsForSet().isMember(Constants.IPV4_LOCK_BLACK, clientIp)){
LOGGER.info("Locked ip access:{}", clientIp);
return JsonResult.buildErrorStateResult("登录失败", null);
}
String lockIpv4Key = getLockIpv4Key(clientIp);
String lock = redisTemplate.opsForValue().get(lockIpv4Key);
if (Objects.equals(Boolean.TRUE.toString(), lock)){
......
package cn.quantgroup.xyqb.aspect.captcha;
package cn.quantgroup.xyqb.aspect.lock;
import java.lang.annotation.*;
......
package cn.quantgroup.xyqb.config.web;
import cn.quantgroup.xyqb.interceptors.ChannelIdInterceptor;
import cn.quantgroup.xyqb.interceptors.IPWhiteListInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
......@@ -13,12 +12,11 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
@Value("${configserver.disable}")
private Integer isDebug;
@Value("${configserver.disable}")
private Integer isDebug;
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new IPWhiteListInterceptor(isDebug)).addPathPatterns("/innerapi/**");
registry.addInterceptor(new ChannelIdInterceptor()).addPathPatterns("/**");
}
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new IPWhiteListInterceptor(isDebug)).addPathPatterns("/innerapi/**");
}
}
package cn.quantgroup.xyqb.controller.external.lock;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.controller.IBaseController;
import cn.quantgroup.xyqb.model.JsonResult;
import cn.quantgroup.xyqb.util.ValidationUtil;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
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.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* 锁控制器
*
* @author renwc
* @version 1.0.0
* @since 2017-11-25
*/
@RestController
@RequestMapping("/lock")
public class LockIpv4Controller implements IBaseController {
private static final Logger LOGGER = LoggerFactory.getLogger(LockIpv4Controller.class);
@Autowired
@Qualifier("stringRedisTemplate")
private RedisTemplate<String, String> redisTemplate;
/**
* 获取操作密令
* @header lock_ipv4 - 获取密令
* @param act - 操作标记,true-lock,false-unlock
* @param request
* @return
*/
@RequestMapping("/key")
public JsonResult key(@RequestParam(required = false)String act, HttpServletRequest request) {
if(Objects.equals(Boolean.TRUE.toString(), act) || Objects.equals(Boolean.FALSE.toString(), act)){
// 操作标记
boolean lock = Objects.equals(Boolean.TRUE.toString(), act);
String header_key = request.getHeader(Constants.IPV4_LOCK.replace(":", ""));
if(Objects.equals(Constants.CLEAR_LOCK_FOR_IPV4, header_key)){
String md5Key = ValidationUtil.getMd5Key(lock);
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)", md5Key);
}
}
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)",null);
}
/**
* 锁定/解锁特定IP
* @param ip - 目标IP
* @param key - 密令
* @param act - 操作标记,true-锁定,false-解锁
* @param request
* @return
*/
@RequestMapping("/lock_ipv4")
public JsonResult lockIpv4(@RequestParam(required = true)String ip,
@RequestParam(required = true)String key,
@RequestParam(required = false)String act,
HttpServletRequest request) {
if(!ValidationUtil.validateIpv4(ip) || StringUtils.isBlank(act) || StringUtils.isBlank(key)){
LOGGER.info("Lock_ipv4: fail to clear_or_lock ip:{}", ip);
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)",null);
}
if(Objects.equals(Boolean.TRUE.toString(), act) || Objects.equals(Boolean.FALSE.toString(), act)){
// 操作标记
boolean lock = Objects.equals(Boolean.TRUE.toString(), act);
boolean valid = ValidationUtil.isValid(key, lock);
// Todo - 兼容简单验证规则,暂时保留
if(!valid){
Calendar now = Calendar.getInstance();
int hour = now.get(Calendar.HOUR_OF_DAY);
valid = Objects.equals(Constants.CLEAR_LOCK_FOR_IPV4_KEY+hour, key);
}
if(valid){
lockIpv4(ip, lock);
return JsonResult.buildSuccessResult("Success",null);
}
}
LOGGER.info("Lock_ipv4: fail to clear_or_lock ip:{}", ip);
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)",null);
}
/**
* 锁定/解锁特定IP
* @header lock_ipv4 - 获取密令
* @param ip - 目标IP
* @param lock - 操作标记,true-锁定,false-解锁
*/
private void lockIpv4(String ip, boolean lock){
String lockIpv4Key = getLockIpv4Key(ip);
if(lock){
// 每分钟计数阈值
long counts = Constants.IPV4_LOCK_ON_COUNTS;
String redisCounts = redisTemplate.opsForValue().get(Constants.IPV4_LOCK_ON_COUNTS_REDIS);
if(StringUtils.isNumeric(redisCounts) && Integer.valueOf(redisCounts) > 0){
counts = Integer.valueOf(redisCounts);
}
// 锁定时长
long minutes = Constants.IPV4_LOCK_MINUTES;
String redisMinutes = redisTemplate.opsForValue().get(Constants.IPV4_LOCK_ON_COUNTS_REDIS);
if(StringUtils.isNumeric(redisMinutes) && Integer.valueOf(redisMinutes) > 0){
minutes = Integer.valueOf(redisMinutes);
}
redisTemplate.opsForValue().set(lockIpv4Key, Boolean.TRUE.toString(), minutes, TimeUnit.MINUTES);
LOGGER.info("Lock_ipv4: locked ip access:{}, error overstep {} times in {} minutes, do lock {} minutes", ip, counts, Constants.IPV4_COUNT_MINUTES, minutes);
}else{
redisTemplate.delete(lockIpv4Key);
LOGGER.info("Lock_ipv4: unlocked ip Success. ip:{}", ip);
}
}
/**
* 配置特定IP到黑/白名单 - Redis
* @param ip - 目标IP
* @param key - 密令
* @param act - 操作:true-添加,false-删除
* @param type - 名单类型:true-黑名单,false-白名单
* @param request
* @return
*/
@RequestMapping("/configHitList")
public JsonResult configHitList(@RequestParam(required = true)String ip,
@RequestParam(required = true)String key,
@RequestParam(required = false)String act,
@RequestParam(required = false)String type,
HttpServletRequest request) {
if(!ValidationUtil.validateIpv4(ip) || StringUtils.isBlank(key) || StringUtils.isBlank(act) || StringUtils.isBlank(type)){
LOGGER.info("Lock_ipv4: fail to config hit list for ip:{}", ip);
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)",null);
}
boolean actOk = Objects.equals(Boolean.TRUE.toString(), act) || Objects.equals(Boolean.FALSE.toString(), act);
boolean typeOk = Objects.equals(Boolean.TRUE.toString(), type) || Objects.equals(Boolean.FALSE.toString(), type);
// 操作标记
boolean valid = (actOk && typeOk) && ValidationUtil.isValid(key, Objects.equals(Boolean.TRUE.toString(), act));
if(valid){
boolean operate = Objects.equals(Boolean.TRUE.toString(), act);
boolean lock = Objects.equals(Boolean.TRUE.toString(), type);
configHitList(ip, operate, lock);
return JsonResult.buildSuccessResult("Success",null);
}
LOGGER.info("Lock_ipv4: fail to config hit list for ip:{}", ip);
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)",null);
}
/**
* 配置特定IP到黑/白名单 - Redis
* @param ip - 目标IP
* @param operate - 操作:true-添加,false-删除
* @param lock - 名单类型:true-黑名单,false-白名单
*/
private void configHitList(String ip, boolean operate, boolean lock) {
if(!ValidationUtil.validateIpv4(ip)){
return;
}
if(operate){
if(lock){
redisTemplate.opsForSet().add(Constants.IPV4_LOCK_BLACK, ip);
LOGGER.info("Lock_ipv4: add black-list item Success, ip:{}", ip);
}else{
redisTemplate.opsForSet().add(Constants.IPV4_LOCK_WHITE, ip);
LOGGER.info("Lock_ipv4: add white-list item Success, ip:{}", ip);
}
}else{
if(lock){
redisTemplate.opsForSet().remove(Constants.IPV4_LOCK_BLACK, ip);
LOGGER.info("Lock_ipv4: remove black-list item Success, ip:{}", ip);
}else{
redisTemplate.opsForSet().remove(Constants.IPV4_LOCK_WHITE, ip);
LOGGER.info("Lock_ipv4: remove white-list item Success, ip:{}", ip);
}
LOGGER.info("Lock_ipv4: white-list:{},black-list:{}", JSONObject.toJSON(redisTemplate.opsForSet().members(Constants.IPV4_LOCK_WHITE)), JSONObject.toJSON(redisTemplate.opsForSet().members(Constants.IPV4_LOCK_BLACK)));
}
}
/**
* 设定可选阈值 - Redis
* @param key - 密令
* @param act - 操作:true-添加,false-删除
* @param counts - 每分钟计数阈值
* @param minutes - 锁定时长
* @param request
* @return
*/
@RequestMapping("/configNoun")
public JsonResult configNoun(@RequestParam(required = true)String key,
@RequestParam(required = false)String act,
@RequestParam(required = false)String counts,
@RequestParam(required = false)String minutes,
HttpServletRequest request) {
if(StringUtils.isBlank(key) || StringUtils.isBlank(act) || !StringUtils.isNumeric(counts) || !StringUtils.isNumeric(minutes)){
LOGGER.info("Lock_ipv4: fail to config noun");
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)",null);
}
boolean actOk = Objects.equals(Boolean.TRUE.toString(), act) || Objects.equals(Boolean.FALSE.toString(), act);
boolean valid = actOk && ValidationUtil.isValid(key, Objects.equals(Boolean.TRUE.toString(), act));
if(valid){
// 操作标记
boolean operate = Objects.equals(Boolean.TRUE.toString(), act);
// 每分钟计数阈值
int redisCounts = Integer.valueOf(counts);
// 锁定时长
int redisMinutes = Integer.valueOf(minutes);
if(redisCounts > 0 && redisMinutes > 0){
configNoun(redisCounts, redisMinutes, operate);
return JsonResult.buildSuccessResult("Success",null);
}
}
LOGGER.info("Lock_ipv4: fail to config noun");
return JsonResult.buildErrorStateResult("Are you a robot monkey?(^_^)",null);
}
/**
* 设定可选阈值 - Redis
* @param counts - 每分钟计数阈值(? > 0)
* @param minutes - 锁定时长(? > 0)
* @param operate - 操作:true-添加,false-删除
*/
private final void configNoun(int counts, int minutes, boolean operate){
if(operate) {
if(counts > 0){
redisTemplate.opsForValue().set(Constants.IPV4_LOCK_ON_COUNTS_REDIS, String.valueOf(counts));
LOGGER.info("Lock_ipv4: config redis-param counts Success, counts:{}", counts);
}
if(minutes > 0){
redisTemplate.opsForValue().set(Constants.IPV4_LOCK_MINUTES_REDIS, String.valueOf(minutes));
LOGGER.info("Lock_ipv4: config redis-param minutes Success, minutes:{}", minutes);
}
}else{
redisTemplate.delete(Constants.IPV4_LOCK_ON_COUNTS_REDIS);
redisTemplate.delete(Constants.IPV4_LOCK_MINUTES_REDIS);
LOGGER.info("Lock_ipv4: remove redis-param counts、minutes Success, counts:{},minutes:{}, current default:[counts:{},minutes:{}]", Constants.IPV4_LOCK_ON_COUNTS, Constants.IPV4_LOCK_MINUTES);
}
}
/**
* 获取Redis-key
* @param ipv4
* @return Redis-key
*/
private final static String getLockIpv4Key(String ipv4){
return Constants.IPV4_LOCK + ipv4;
}
}
......@@ -2,7 +2,7 @@ package cn.quantgroup.xyqb.controller.internal.user;
import cn.quantgroup.xyqb.Constants;
import cn.quantgroup.xyqb.aspect.captcha.CaptchaFineteValidator;
import cn.quantgroup.xyqb.aspect.captcha.PasswordFineteValidator;
import cn.quantgroup.xyqb.aspect.lock.PasswordFineteValidator;
import cn.quantgroup.xyqb.aspect.logcaller.LogHttpCaller;
import cn.quantgroup.xyqb.controller.IBaseController;
import cn.quantgroup.xyqb.entity.Merchant;
......
......@@ -26,12 +26,8 @@ import java.io.PrintWriter;
public class RequestFilter implements Filter {
private static final String[] ALLOWED_PATTERNS = {
"/user_detail/**","/hello/**","/innerapi/**", "/user/exist", "/motan/**", "/user/register", "/user/login", "/user/register/fast",
"/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/**",
"/platform/api/page/return_url", "/MP_" +
"verify_AWiagUn4kZiwmTt0.txt"
"/wechat/**", "/config/**", "/api/**", "/query/**", "/user_detail/**", "/hello/**", "/innerapi/**", "/motan/**", "/user/**", "/lock/**",
"/auth/info/login", "/app/login", "/app/login_super", "/app/login2", "/platform/api/page/return_url", "/MP_verify_AWiagUn4kZiwmTt0.txt"
};
private static final String UNAUTH_RESULT = JSONObject.toJSONString(JsonResult.buildErrorStateResult("登录失败", null));
@Autowired
......
package cn.quantgroup.xyqb.interceptors;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created by Miraculous on 15/7/10.
*/
public class ChannelIdInterceptor implements HandlerInterceptor {
private static final String CHANNEL_ID = "channelId";
private static final String CREATED_FROM = "createdFrom";
private static final String APP_CHANNEL = "appChannel";
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object o) throws Exception {
String channelId = request.getParameter(CHANNEL_ID);
if (channelId == null) {
channelId = (String) request.getAttribute(CHANNEL_ID);
}
if (channelId != null) {
request.getSession().setAttribute(CHANNEL_ID, channelId);
}
String createdFrom = request.getParameter(CREATED_FROM);
if (createdFrom == null) {
createdFrom = (String) request.getAttribute(CREATED_FROM);
}
if (createdFrom != null) {
request.getSession().setAttribute(CREATED_FROM, createdFrom);
}
String appChannel = request.getParameter(APP_CHANNEL);
if (appChannel == null) {
appChannel = (String) request.getAttribute(APP_CHANNEL);
}
if (appChannel != null) {
request.getSession().setAttribute(APP_CHANNEL, appChannel);
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) throws Exception {
}
}
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