Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
X
xyqb-user2
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
head_group
xyqb-user2
Commits
db628406
Commit
db628406
authored
Nov 23, 2017
by
技术部-任文超
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
/user/login接口添加针对ipv4的密码错误计数器
parent
2d785812
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
176 additions
and
9 deletions
+176
-9
Constants.java
src/main/java/cn/quantgroup/xyqb/Constants.java
+1
-0
PasswordErrorFiniteValidateAdvisor.java
...qb/aspect/captcha/PasswordErrorFiniteValidateAdvisor.java
+120
-0
PasswordFineteValidator.java
...antgroup/xyqb/aspect/captcha/PasswordFineteValidator.java
+15
-0
UserController.java
...ntgroup/xyqb/controller/internal/user/UserController.java
+15
-0
ValidationUtil.java
src/main/java/cn/quantgroup/xyqb/util/ValidationUtil.java
+25
-9
No files found.
src/main/java/cn/quantgroup/xyqb/Constants.java
View file @
db628406
...
@@ -37,6 +37,7 @@ public interface Constants {
...
@@ -37,6 +37,7 @@ public interface Constants {
String
REDIS_VERIFICATION_COUNT
=
"verification_code_count:"
;
String
REDIS_VERIFICATION_COUNT
=
"verification_code_count:"
;
final
Long
Image_Need_Count
=
3L
;
final
Long
Image_Need_Count
=
3L
;
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:"
;
/**
/**
* redis中token的key值前缀
* redis中token的key值前缀
*/
*/
...
...
src/main/java/cn/quantgroup/xyqb/aspect/captcha/PasswordErrorFiniteValidateAdvisor.java
0 → 100644
View file @
db628406
package
cn
.
quantgroup
.
xyqb
.
aspect
.
captcha
;
import
cn.quantgroup.xyqb.Constants
;
import
cn.quantgroup.xyqb.model.JsonResult
;
import
cn.quantgroup.xyqb.util.ValidationUtil
;
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.nio.charset.Charset
;
import
java.util.*
;
/**
* 密码错误限次的校验
* @author 任文超
* @version 1.0.0
* @since 2017-11-23
*/
@Aspect
@Component
public
class
PasswordErrorFiniteValidateAdvisor
{
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
PasswordErrorFiniteValidateAdvisor
.
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
;
/**
* 密码错误限次切面
*/
@Pointcut
(
"@annotation(cn.quantgroup.xyqb.aspect.captcha.PasswordErrorFiniteValidator)"
)
private
void
passwordErrorFiniteValidate
()
{
}
/**
* 在受保护的接口方法执行前, 执行密码错误限次校验
*
* @param pjp
* @return
* @throws Throwable
*/
@Around
(
"passwordErrorFiniteValidate()"
)
private
Object
doFiniteValidate
(
ProceedingJoinPoint
pjp
)
throws
Throwable
{
HttpServletRequest
request
=
((
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
()).
getRequest
();
// 客户端IP
String
clientIp
=
getIp
(
request
);
Long
countErrorByIp
=
getIpv4Count
(
clientIp
);
// 5分钟内不超过3次
if
(
countErrorByIp
>
Constants
.
Image_Need_Count
){
return
JsonResult
.
buildErrorStateResult
(
"登录失败"
,
null
);
}
return
pjp
.
proceed
();
}
// 获取该ipv4密码错误计数器
private
Long
getIpv4Count
(
String
ipv4
)
{
if
(
ValidationUtil
.
validateIpv4
(
ipv4
)
&&
ValidationUtil
.
validateLocalIpv4
(
ipv4
))
{
return
0L
;
}
String
key
=
getIpKey
(
ipv4
);
String
countString
=
redisTemplate
.
opsForValue
().
get
(
key
);
if
(
StringUtils
.
isBlank
(
countString
))
{
return
0L
;
}
return
Long
.
valueOf
(
countString
);
}
private
final
static
String
getIpKey
(
String
ipv4
){
return
Constants
.
REDIS_PASSWORD_ERROR_COUNT_FOR_IPV4
+
ipv4
;
}
/**
* 客户端IP解析
*
* @param request 当前请求,其首部行必须包含形如【SingleToken 13461067662:0123456789abcdef】的UTF-8编码的Base64加密参数
* @return 客户端IP 或 null
*/
private
String
getIp
(
HttpServletRequest
request
)
{
Objects
.
requireNonNull
(
request
,
"无效请求"
);
String
ip
=
request
.
getHeader
(
"x-real-ip"
);
if
(
StringUtils
.
isBlank
(
ip
))
{
ip
=
request
.
getRemoteAddr
();
}
//过滤反向代理的ip
String
[]
stemps
=
ip
.
split
(
","
);
if
(
stemps
.
length
>=
1
)
{
//得到第一个IP,即客户端真实IP
ip
=
stemps
[
0
];
}
ip
=
ip
.
trim
();
if
(
ip
.
length
()
>
23
)
{
ip
=
ip
.
substring
(
0
,
23
);
}
return
ip
;
}
}
src/main/java/cn/quantgroup/xyqb/aspect/captcha/PasswordFineteValidator.java
0 → 100644
View file @
db628406
package
cn
.
quantgroup
.
xyqb
.
aspect
.
captcha
;
import
java.lang.annotation.*
;
/**
* 密码错误限次的校验标记
* @author 任文超
* @version 1.0.0
* @since 2017-11-23
*/
@Documented
@Target
(
ElementType
.
METHOD
)
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
PasswordFineteValidator
{
}
src/main/java/cn/quantgroup/xyqb/controller/internal/user/UserController.java
View file @
db628406
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.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
;
import
cn.quantgroup.xyqb.entity.Merchant
;
import
cn.quantgroup.xyqb.entity.Merchant
;
...
@@ -76,6 +77,7 @@ public class UserController implements IBaseController {
...
@@ -76,6 +77,7 @@ public class UserController implements IBaseController {
'l'
,
'm'
,
'n'
,
'o'
,
'p'
,
'q'
,
'r'
,
's'
,
't'
,
'u'
,
'v'
,
'w'
,
'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'
};
'x'
,
'y'
,
'z'
,
'0'
,
'1'
,
'2'
,
'3'
,
'4'
,
'5'
,
'6'
,
'7'
,
'8'
,
'9'
};
@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
,
...
@@ -523,11 +525,24 @@ public class UserController implements IBaseController {
...
@@ -523,11 +525,24 @@ public class UserController implements IBaseController {
}
}
//验证密码
//验证密码
if
(!
validatePassword
(
pass
,
user
.
getPassword
()))
{
if
(!
validatePassword
(
pass
,
user
.
getPassword
()))
{
String
ipv4
=
getIp
();
if
(
StringUtils
.
isNotBlank
(
ipv4
)
&&
!
ValidationUtil
.
validateLocalIpv4
(
ipv4
))
{
String
ipv4Key
=
getIpKey
(
getIp
());
if
(!
stringRedisTemplate
.
hasKey
(
getIpKey
(
getIp
()))){
// 计数周期5分钟
stringRedisTemplate
.
opsForValue
().
set
(
ipv4Key
,
String
.
valueOf
(
0
),
5
,
TimeUnit
.
MINUTES
);
}
stringRedisTemplate
.
opsForValue
().
increment
(
ipv4Key
,
1L
);
}
return
null
;
return
null
;
}
}
return
user
;
return
user
;
}
}
private
final
static
String
getIpKey
(
String
ipv4
){
return
Constants
.
REDIS_PASSWORD_ERROR_COUNT_FOR_IPV4
+
ipv4
;
}
private
boolean
validatePassword
(
String
paramPass
,
String
targetPassword
)
{
private
boolean
validatePassword
(
String
paramPass
,
String
targetPassword
)
{
return
StringUtils
.
defaultString
(
targetPassword
,
""
).
equals
(
PasswordUtil
.
MD5
(
paramPass
.
toLowerCase
()
+
pwdSalt
));
return
StringUtils
.
defaultString
(
targetPassword
,
""
).
equals
(
PasswordUtil
.
MD5
(
paramPass
.
toLowerCase
()
+
pwdSalt
));
}
}
...
...
src/main/java/cn/quantgroup/xyqb/util/ValidationUtil.java
View file @
db628406
...
@@ -11,33 +11,49 @@ import java.util.regex.Pattern;
...
@@ -11,33 +11,49 @@ import java.util.regex.Pattern;
*/
*/
public
class
ValidationUtil
{
public
class
ValidationUtil
{
private
static
String
regExp
=
"^((13[0-9])|(14[0-9])|(15[0-9])|(17[0-9])|(18[0-9])|(19[0-9]))\\d{8}$"
;
private
static
String
phoneRegExp
=
"^((13[0-9])|(14[0-9])|(15[0-9])|(17[0-9])|(18[0-9])|(19[0-9]))\\d{8}$"
;
private
static
String
chineseExp
=
"^[\u4e00-\u9fa5]+(\\.|·)?[\u4e00-\u9fa5]+$"
;
private
static
String
chineseNameRegExp
=
"^[\u4e00-\u9fa5]+(\\.|·)?[\u4e00-\u9fa5]+$"
;
private
static
String
ipv4RegExp
=
"^((2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?)\\.){3}(2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?)$"
;
private
static
String
localIpv4RegExp
=
"^172(\\.2[0-4][0-9]|25[0-5]|[01]?[0-9][0-9]?){3}$"
;
private
static
Pattern
phonePattern
=
Pattern
.
compile
(
regExp
);
private
static
Pattern
phonePattern
=
Pattern
.
compile
(
phoneRegExp
);
private
static
Pattern
chinesePattern
=
Pattern
.
compile
(
chineseExp
);
private
static
Pattern
chinesePattern
=
Pattern
.
compile
(
chineseNameRegExp
);
private
static
Pattern
ipv4Pattern
=
Pattern
.
compile
(
ipv4RegExp
);
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
.
isNotEmpty
(
phoneNo
)
&&
phoneNo
.
length
()
==
11
&&
StringUtils
.
isNumeric
(
phoneNo
);
if
(!
lengthValid
)
{
if
(!
lengthValid
)
{
return
false
;
return
false
;
}
}
Matcher
matcher
=
phonePattern
.
matcher
(
phoneNo
);
Matcher
matcher
=
phonePattern
.
matcher
(
phoneNo
);
return
matcher
.
find
();
return
matcher
.
find
();
}
}
public
static
boolean
validateChinese
(
String
chinese
)
{
public
static
boolean
validateChinese
(
String
chinese
)
{
if
(
StringUtils
.
is
Empty
(
chinese
))
{
if
(
StringUtils
.
is
Blank
(
chinese
))
{
return
false
;
return
false
;
}
}
Matcher
matcher
=
chinesePattern
.
matcher
(
chinese
);
Matcher
matcher
=
chinesePattern
.
matcher
(
chinese
);
return
matcher
.
find
();
return
matcher
.
find
();
}
}
public
static
boolean
validateIpv4
(
String
ipv4
)
{
if
(
StringUtils
.
isBlank
(
ipv4
))
{
return
false
;
}
Matcher
matcher
=
ipv4Pattern
.
matcher
(
ipv4
);
return
matcher
.
find
();
}
public
static
boolean
validateLocalIpv4
(
String
localIpv4
)
{
if
(
StringUtils
.
isBlank
(
localIpv4
))
{
return
false
;
}
Matcher
matcher
=
localIpv4Pattern
.
matcher
(
localIpv4
);
return
matcher
.
find
();
}
public
static
boolean
validateChannelId
(
Long
channelId
)
{
public
static
boolean
validateChannelId
(
Long
channelId
)
{
return
channelId
==
0L
?
false
:
true
;
return
channelId
==
0L
?
false
:
true
;
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment