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
8a797d43
Commit
8a797d43
authored
Sep 22, 2017
by
Java—红包—徐 然
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' into feature/hongbao
parents
d65b6eed
7bcedcf8
Changes
8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
465 additions
and
17 deletions
+465
-17
Constants.java
src/main/java/cn/quantgroup/xyqb/Constants.java
+11
-1
CaptchaNewValidateAdvisor.java
...tgroup/xyqb/aspect/captcha/CaptchaNewValidateAdvisor.java
+212
-0
CaptchaNewValidator.java
...n/quantgroup/xyqb/aspect/captcha/CaptchaNewValidator.java
+13
-0
CaptchaValidateAdvisor.java
...uantgroup/xyqb/aspect/captcha/CaptchaValidateAdvisor.java
+1
-1
ImageCaptchaController.java
...b/controller/external/captcha/ImageCaptchaController.java
+24
-11
SmsController.java
...uantgroup/xyqb/controller/internal/sms/SmsController.java
+181
-1
UserController.java
...ntgroup/xyqb/controller/internal/user/UserController.java
+21
-1
User.java
src/main/java/cn/quantgroup/xyqb/entity/User.java
+2
-2
No files found.
src/main/java/cn/quantgroup/xyqb/Constants.java
View file @
8a797d43
...
@@ -25,8 +25,18 @@ public interface Constants {
...
@@ -25,8 +25,18 @@ public interface Constants {
String
REDIS_PREFIX_VERIFICATION_CODE
=
"verificationCode_"
;
String
REDIS_PREFIX_VERIFICATION_CODE
=
"verificationCode_"
;
String
REDIS_VOICE_CODE_COUNT
=
"voice_verification_code_count:"
;
String
REDIS_PREFIX_VERIFICATION_VOICE_CODE
=
"verificationCode_voice_"
;
//新版短信验证码计数
String
REDIS_SMS_CODE_COUNT
=
"SMS_Phone_verification_code_count:"
;
String
REDIS_SMS_IP_COUNT
=
"SMS_Ip_verification_code_count:"
;
String
REDIS_SMS_DEVICE_COUNT
=
"SMS_Device_verification_code_count:"
;
//新版语音验证码计数
String
REDIS_VOICE_CODE_COUNT
=
"Voice_Phone_verification_code_count:"
;
String
REDIS_VOICE_IP_COUNT
=
"Voice_Ip_verification_code_count:"
;
String
REDIS_VOICE_DEVICE_COUNT
=
"Voice_Device_verification_code_count:"
;
String
REDIS_VERIFICATION_COUNT
=
"verification_code_count:"
;
final
Long
Image_Need_Count
=
3L
;
/**
/**
* redis中token的key值前缀
* redis中token的key值前缀
*/
*/
...
...
src/main/java/cn/quantgroup/xyqb/aspect/captcha/CaptchaNewValidateAdvisor.java
0 → 100644
View file @
8a797d43
package
cn
.
quantgroup
.
xyqb
.
aspect
.
captcha
;
import
cn.quantgroup.xyqb.Constants
;
import
cn.quantgroup.xyqb.controller.IBaseController
;
import
cn.quantgroup.xyqb.model.JsonResult
;
import
cn.quantgroup.xyqb.thirdparty.jcaptcha.AbstractManageableImageCaptchaService
;
import
com.octo.captcha.service.CaptchaServiceException
;
import
java.io.PipedReader
;
import
java.nio.charset.Charset
;
import
java.security.PrivateKey
;
import
java.util.Optional
;
import
java.util.UUID
;
import
java.util.concurrent.TimeUnit
;
import
javax.servlet.http.HttpServletRequest
;
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
;
/**
* 类名称:CaptchaValidateAdvisor
* 类描述:
*
* @author 李宁
* @version 1.0.0 创建时间:15/11/17 14:49 修改人: 修改时间:15/11/17 14:49 修改备注:
*/
@Aspect
@Component
public
class
CaptchaNewValidateAdvisor
{
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
CaptchaNewValidateAdvisor
.
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__"
;
@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.CaptchaNewValidator)"
)
private
void
needNewCaptchaValidate
()
{
}
private
static
final
String
IMAGE_IP_COUNT
=
"image:ip"
;
private
static
final
String
IMAGE_PHONE_COUNT
=
"image:phone"
;
private
static
final
String
IMAGE_DEVICEID_COUNT
=
"image:deviceId:"
;
private
static
final
Long
FIVE_MIN
=
24
*
5L
;
/**
* 在受图形验证码保护的接口方法执行前, 执行图形验证码校验
*
* @throws Throwable
*/
@Around
(
"needNewCaptchaValidate()"
)
private
Object
doCapchaValidate
(
ProceedingJoinPoint
pjp
)
throws
Throwable
{
HttpServletRequest
request
=
((
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
()).
getRequest
();
String
registerFrom
=
Optional
.
ofNullable
(
request
.
getParameter
(
"registerFrom"
)).
orElse
(
""
);
String
captchaId
=
Optional
.
ofNullable
(
request
.
getParameter
(
"captchaId"
)).
orElse
(
""
);
Object
captchaValue
=
request
.
getParameter
(
"captchaValue"
);
String
phoneNo
=
request
.
getParameter
(
"phoneNo"
);
String
deviceId
=
Optional
.
ofNullable
(
request
.
getParameter
(
"deviceId"
)).
orElse
(
""
);
String
clientIp
=
getIp
();
Long
countIP
=
countIP
(
clientIp
);
Long
countPhone
=
countPhone
(
phoneNo
);
Long
countDeviceId
=
countDeviceId
(
deviceId
);
if
(
countIP
>
Constants
.
Image_Need_Count
||
countPhone
>
Constants
.
Image_Need_Count
||
countDeviceId
>
Constants
.
Image_Need_Count
)
{
if
(
shouldSkipCaptchaValidate
(
registerFrom
,
captchaId
,
captchaValue
))
{
LOGGER
.
info
(
"使用超级图形验证码校验, registerFrom={}, clientIp={}"
,
registerFrom
,
request
.
getRemoteAddr
());
return
pjp
.
proceed
();
}
JsonResult
result
=
JsonResult
.
buildSuccessResult
(
"图形验证码不正确"
,
""
);
result
.
setBusinessCode
(
"0002"
);
if
(
captchaValue
!=
null
)
{
String
captcha
=
String
.
valueOf
(
captchaValue
);
// 忽略用户输入的大小写
captcha
=
StringUtils
.
lowerCase
(
captcha
);
// 验证码校验
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
result
;
}
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
countIP
(
String
clientIp
)
{
Long
count
=
1L
;
if
(
StringUtils
.
isBlank
(
clientIp
))
{
return
count
;
}
else
{
String
countString
=
redisTemplate
.
opsForValue
().
get
(
IMAGE_IP_COUNT
+
clientIp
);
if
(
StringUtils
.
isBlank
(
countString
))
{
redisTemplate
.
opsForValue
().
set
(
IMAGE_IP_COUNT
+
clientIp
,
String
.
valueOf
(
count
),
FIVE_MIN
,
TimeUnit
.
SECONDS
);
}
else
{
count
=
Long
.
valueOf
(
countString
)
+
1L
;
redisTemplate
.
opsForValue
().
set
(
IMAGE_IP_COUNT
+
clientIp
,
String
.
valueOf
(
count
),
FIVE_MIN
,
TimeUnit
.
SECONDS
);
}
return
count
;
}
}
private
Long
countPhone
(
String
phoneNo
)
{
Long
count
=
1L
;
String
countString
=
redisTemplate
.
opsForValue
().
get
(
IMAGE_PHONE_COUNT
+
phoneNo
);
if
(
StringUtils
.
isBlank
(
countString
))
{
redisTemplate
.
opsForValue
().
set
(
IMAGE_PHONE_COUNT
+
phoneNo
,
String
.
valueOf
(
count
),
FIVE_MIN
,
TimeUnit
.
SECONDS
);
}
else
{
count
=
Long
.
valueOf
(
countString
)
+
1L
;
redisTemplate
.
opsForValue
().
set
(
IMAGE_PHONE_COUNT
+
phoneNo
,
String
.
valueOf
(
count
),
FIVE_MIN
,
TimeUnit
.
SECONDS
);
}
return
count
;
}
/**
* 短信发送设备限制
*/
private
Long
countDeviceId
(
String
deviceId
)
{
Long
count
=
1L
;
if
(
StringUtils
.
isBlank
(
deviceId
))
{
return
count
;
}
else
{
String
countString
=
redisTemplate
.
opsForValue
().
get
(
IMAGE_DEVICEID_COUNT
+
deviceId
);
if
(
StringUtils
.
isBlank
(
countString
))
{
redisTemplate
.
opsForValue
().
set
(
IMAGE_DEVICEID_COUNT
+
deviceId
,
String
.
valueOf
(
count
),
FIVE_MIN
,
TimeUnit
.
SECONDS
);
}
else
{
count
=
Long
.
valueOf
(
countString
)
+
1L
;
redisTemplate
.
opsForValue
().
set
(
IMAGE_DEVICEID_COUNT
+
deviceId
,
String
.
valueOf
(
count
),
FIVE_MIN
,
TimeUnit
.
SECONDS
);
}
return
count
;
}
}
private
String
getIp
()
{
HttpServletRequest
request
=
getRequest
();
String
ip
=
request
.
getHeader
(
"x-real-ip"
);
if
(
StringUtils
.
isEmpty
(
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
;
}
private
HttpServletRequest
getRequest
()
{
ServletRequestAttributes
attrs
=
(
ServletRequestAttributes
)
RequestContextHolder
.
getRequestAttributes
();
return
attrs
.
getRequest
();
}
}
src/main/java/cn/quantgroup/xyqb/aspect/captcha/CaptchaNewValidator.java
0 → 100644
View file @
8a797d43
package
cn
.
quantgroup
.
xyqb
.
aspect
.
captcha
;
import
java.lang.annotation.*
;
/**
* Created by xuran on 2017/8/28.
*/
@Documented
@Target
(
ElementType
.
METHOD
)
@Retention
(
RetentionPolicy
.
RUNTIME
)
public
@interface
CaptchaNewValidator
{
}
src/main/java/cn/quantgroup/xyqb/aspect/captcha/CaptchaValidateAdvisor.java
View file @
8a797d43
...
@@ -85,7 +85,7 @@ public class CaptchaValidateAdvisor {
...
@@ -85,7 +85,7 @@ public class CaptchaValidateAdvisor {
return
pjp
.
proceed
();
return
pjp
.
proceed
();
}
}
JsonResult
result
=
JsonResult
.
buildSuccessResult
(
"图形验证码
错误, 请重新输入
"
,
""
);
JsonResult
result
=
JsonResult
.
buildSuccessResult
(
"图形验证码
不正确
"
,
""
);
result
.
setBusinessCode
(
"0002"
);
result
.
setBusinessCode
(
"0002"
);
if
(
captchaValue
!=
null
)
{
if
(
captchaValue
!=
null
)
{
String
captcha
=
String
.
valueOf
(
captchaValue
);
String
captcha
=
String
.
valueOf
(
captchaValue
);
...
...
src/main/java/cn/quantgroup/xyqb/controller/external/captcha/ImageCaptchaController.java
View file @
8a797d43
...
@@ -5,13 +5,21 @@ import cn.quantgroup.xyqb.aspect.captcha.CaptchaValidator;
...
@@ -5,13 +5,21 @@ import cn.quantgroup.xyqb.aspect.captcha.CaptchaValidator;
import
cn.quantgroup.xyqb.controller.IBaseController
;
import
cn.quantgroup.xyqb.controller.IBaseController
;
import
cn.quantgroup.xyqb.model.JsonResult
;
import
cn.quantgroup.xyqb.model.JsonResult
;
import
cn.quantgroup.xyqb.thirdparty.jcaptcha.AbstractManageableImageCaptchaService
;
import
cn.quantgroup.xyqb.thirdparty.jcaptcha.AbstractManageableImageCaptchaService
;
import
com.octo.captcha.service.CaptchaServiceException
;
import
java.nio.charset.Charset
;
import
java.util.Optional
;
import
java.util.concurrent.TimeUnit
;
import
org.apache.commons.codec.binary.Base64
;
import
org.apache.commons.codec.binary.Base64
;
import
org.apache.commons.lang3.StringUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
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.Qualifier
;
import
org.springframework.beans.factory.annotation.Value
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.web.bind.annotation.ModelAttribute
;
import
org.springframework.web.bind.annotation.ModelAttribute
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
import
javax.imageio.ImageIO
;
import
javax.imageio.ImageIO
;
...
@@ -22,41 +30,49 @@ import java.io.IOException;
...
@@ -22,41 +30,49 @@ import java.io.IOException;
import
java.util.HashMap
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Map
;
import
java.util.UUID
;
import
java.util.UUID
;
import
sun.management.counter.LongCounter
;
/**
/**
* 类名称:ImgCaptchaController
* 类名称:ImgCaptchaController
* 类描述:图形验证码控制器
* 类描述:图形验证码控制器
*
*
* @author 李宁
* @author 李宁
* @version 1.0.0
* @version 1.0.0 创建时间:15/11/17 11:49 修改人: 修改时间:15/11/17 11:49 修改备注:
* 创建时间:15/11/17 11:49
* 修改人:
* 修改时间:15/11/17 11:49
* 修改备注:
*/
*/
@RestController
@RestController
@RequestMapping
(
"/api"
)
@RequestMapping
(
"/api"
)
public
class
ImageCaptchaController
implements
IBaseController
{
public
class
ImageCaptchaController
implements
IBaseController
{
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
ImageCaptchaController
.
class
);
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
ImageCaptchaController
.
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__"
;
private
static
final
String
IMAGE_FORMAT_PNG
=
"png"
;
private
static
final
String
IMAGE_FORMAT_PNG
=
"png"
;
private
static
final
String
IMG_BASE64_PATTREN
=
"data:image/"
+
IMAGE_FORMAT_PNG
+
";base64,%s"
;
private
static
final
String
IMG_BASE64_PATTREN
=
"data:image/"
+
IMAGE_FORMAT_PNG
+
";base64,%s"
;
private
static
final
String
IMAGE_IP_COUNT
=
"image:ip"
;
private
static
final
String
IMAGE_PHONE_COUNT
=
"image:phone"
;
private
static
final
Long
FIVE_MIN
=
24
*
5L
;
@Autowired
@Autowired
@Qualifier
(
"customCaptchaService"
)
@Qualifier
(
"customCaptchaService"
)
private
AbstractManageableImageCaptchaService
imageCaptchaService
;
private
AbstractManageableImageCaptchaService
imageCaptchaService
;
@Autowired
@Qualifier
(
"stringRedisTemplate"
)
private
RedisTemplate
<
String
,
String
>
redisTemplate
;
@ModelAttribute
(
"clientIp"
)
@ModelAttribute
(
"clientIp"
)
public
String
initClientIp
()
{
public
String
initClientIp
()
{
return
getIp
();
return
getIp
();
}
}
/**
* 自动化测试忽略验证码
*/
@Value
(
"${xyqb.auth.captcha.autotest.enable:false}"
)
private
boolean
autoTestCaptchaEnabled
;
/**
/**
* 获取验证码
* 获取验证码
* 默认匹配 GET /captcha, 提供4位数字和字母混合图片验证码
* 默认匹配 GET /captcha, 提供4位数字和字母混合图片验证码
*
* @return
*/
*/
@RequestMapping
(
value
=
"/captcha"
)
@RequestMapping
(
value
=
"/captcha"
)
public
JsonResult
fetchCaptcha
(
HttpServletRequest
request
,
@ModelAttribute
(
"clientIp"
)
String
clientIp
)
{
public
JsonResult
fetchCaptcha
(
HttpServletRequest
request
,
@ModelAttribute
(
"clientIp"
)
String
clientIp
)
{
...
@@ -76,9 +92,7 @@ public class ImageCaptchaController implements IBaseController {
...
@@ -76,9 +92,7 @@ public class ImageCaptchaController implements IBaseController {
data
.
put
(
"imageId"
,
imageId
);
data
.
put
(
"imageId"
,
imageId
);
data
.
put
(
"image"
,
String
.
format
(
IMG_BASE64_PATTREN
,
imageBase64
));
data
.
put
(
"image"
,
String
.
format
(
IMG_BASE64_PATTREN
,
imageBase64
));
return
JsonResult
.
buildSuccessResult
(
""
,
data
);
return
JsonResult
.
buildSuccessResult
(
""
,
data
);
}
}
/**
/**
* 图片验证码验证
* 图片验证码验证
*/
*/
...
@@ -87,5 +101,4 @@ public class ImageCaptchaController implements IBaseController {
...
@@ -87,5 +101,4 @@ public class ImageCaptchaController implements IBaseController {
public
JsonResult
verificationImageCode
()
{
public
JsonResult
verificationImageCode
()
{
return
JsonResult
.
buildSuccessResult
(
""
,
null
);
return
JsonResult
.
buildSuccessResult
(
""
,
null
);
}
}
}
}
src/main/java/cn/quantgroup/xyqb/controller/internal/sms/SmsController.java
View file @
8a797d43
...
@@ -2,7 +2,9 @@ package cn.quantgroup.xyqb.controller.internal.sms;
...
@@ -2,7 +2,9 @@ package cn.quantgroup.xyqb.controller.internal.sms;
import
cn.quantgroup.sms.MsgParams
;
import
cn.quantgroup.sms.MsgParams
;
import
cn.quantgroup.xyqb.Constants
;
import
cn.quantgroup.xyqb.Constants
;
import
cn.quantgroup.xyqb.aspect.captcha.CaptchaNewValidator
;
import
cn.quantgroup.xyqb.aspect.captcha.CaptchaValidator
;
import
cn.quantgroup.xyqb.aspect.captcha.CaptchaValidator
;
import
cn.quantgroup.xyqb.controller.IBaseController
;
import
cn.quantgroup.xyqb.model.JsonResult
;
import
cn.quantgroup.xyqb.model.JsonResult
;
import
cn.quantgroup.xyqb.service.sms.ISmsService
;
import
cn.quantgroup.xyqb.service.sms.ISmsService
;
import
cn.quantgroup.xyqb.util.DateUtils
;
import
cn.quantgroup.xyqb.util.DateUtils
;
...
@@ -14,6 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired;
...
@@ -14,6 +16,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import
org.springframework.beans.factory.annotation.Qualifier
;
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.data.redis.core.RedisTemplate
;
import
org.springframework.web.bind.annotation.ModelAttribute
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.RequestParam
;
import
org.springframework.web.bind.annotation.RestController
;
import
org.springframework.web.bind.annotation.RestController
;
...
@@ -26,7 +29,7 @@ import java.util.concurrent.TimeUnit;
...
@@ -26,7 +29,7 @@ import java.util.concurrent.TimeUnit;
*/
*/
@RestController
@RestController
@RequestMapping
(
"/api/sms"
)
@RequestMapping
(
"/api/sms"
)
public
class
SmsController
{
public
class
SmsController
implements
IBaseController
{
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
SmsController
.
class
);
private
static
final
Logger
LOGGER
=
LoggerFactory
.
getLogger
(
SmsController
.
class
);
private
static
final
Random
random
=
new
Random
();
private
static
final
Random
random
=
new
Random
();
...
@@ -38,7 +41,14 @@ public class SmsController {
...
@@ -38,7 +41,14 @@ public class SmsController {
private
RedisTemplate
<
String
,
String
>
redisTemplate
;
private
RedisTemplate
<
String
,
String
>
redisTemplate
;
@Value
(
"${sms.is.debug}"
)
@Value
(
"${sms.is.debug}"
)
private
boolean
smsIsDebug
;
private
boolean
smsIsDebug
;
private
static
final
String
IMAGE_IP_COUNT
=
"image:ip"
;
private
static
final
String
IMAGE_PHONE_COUNT
=
"image:phone"
;
private
static
final
String
IMAGE_DEVICEID_COUNT
=
"image:deviceId:"
;
private
static
final
Long
IP_MAX_PER_DAY
=
5000L
;
//ip上限
private
static
final
Long
PHONE_MAX_PER_DAY
=
20L
;
//手机号短信上限
private
static
final
Long
PHONE_VOICE_MAX_PER_DAY
=
5L
;
//手机号语音上限
private
static
final
Long
DEVICE_MAX_PER_DAY
=
20L
;
//设备每天上限
/**
/**
* 短信验证码: for H5
* 短信验证码: for H5
* 使用 @FPLock 注解并加入自定义限制参数, 做针对手机号的发送次数限制
* 使用 @FPLock 注解并加入自定义限制参数, 做针对手机号的发送次数限制
...
@@ -142,6 +152,7 @@ public class SmsController {
...
@@ -142,6 +152,7 @@ public class SmsController {
//smsService.getSmsSender().sendConfirmableMessage(confirmableMsg);
//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
);
//删除用户重置密码,多次错误逻辑
return
JsonResult
.
buildSuccessResult
(
"发送成功"
,
uniqueId
);
return
JsonResult
.
buildSuccessResult
(
"发送成功"
,
uniqueId
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
LOGGER
.
error
(
"发送短信验证码失败"
);
LOGGER
.
error
(
"发送短信验证码失败"
);
...
@@ -170,10 +181,179 @@ public class SmsController {
...
@@ -170,10 +181,179 @@ public class SmsController {
try
{
try
{
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
);
//删除用户重置密码,多次错误逻辑
return
JsonResult
.
buildSuccessResult
(
"发送成功"
,
uniqueId
);
return
JsonResult
.
buildSuccessResult
(
"发送成功"
,
uniqueId
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
LOGGER
.
error
(
"发送语音短信验证码失败"
);
LOGGER
.
error
(
"发送语音短信验证码失败"
);
return
JsonResult
.
buildErrorStateResult
(
"发送失败"
,
null
);
return
JsonResult
.
buildErrorStateResult
(
"发送失败"
,
null
);
}
}
}
}
/**
* 快速登陆发送验证码新版
*/
@CaptchaNewValidator
@RequestMapping
(
"/send_login_code_voice_new"
)
public
JsonResult
sendLoginSmsCodeNew
(
@RequestParam
String
phoneNo
,
@RequestParam
(
required
=
false
)
String
registerFrom
,
String
usage
,
@RequestParam
(
required
=
false
)
String
deviceId
)
{
if
(
StringUtils
.
isEmpty
(
usage
)
||
!
"6"
.
equals
(
usage
))
{
LOGGER
.
error
(
"参数校验失败,用户登录语音验证码usage参数为{}"
,
usage
);
return
JsonResult
.
buildErrorStateResult
(
"参数校验失败."
,
null
);
}
LOGGER
.
info
(
"快速登陆-发送验证码, phoneNo:{}, registerFrom:{}"
,
phoneNo
,
registerFrom
);
return
sendVerificationCode2VoiceNew
(
phoneNo
,
usage
,
deviceId
);
}
/**
* 快速登陆发送短信验证码
*/
@CaptchaNewValidator
@RequestMapping
(
"/send_login_code_new"
)
public
JsonResult
sendLoginCodeVoiceNew
(
@RequestParam
String
phoneNo
,
@RequestParam
(
required
=
false
)
String
registerFrom
,
@RequestParam
(
required
=
false
)
String
deviceId
)
{
LOGGER
.
info
(
"快速登陆-发送验证码, phoneNo:{}, registerFrom:{}"
,
phoneNo
,
registerFrom
);
return
sendVerificationCode2New
(
phoneNo
,
deviceId
);
}
/**
* 新版本验证码
*/
private
JsonResult
sendVerificationCode2New
(
String
phoneNo
,
String
deviceId
)
{
if
(!
ValidationUtil
.
validatePhoneNo
(
phoneNo
))
{
return
JsonResult
.
buildErrorStateResult
(
"手机号格式有误"
,
null
);
}
String
verificationPhoneCountKey
=
Constants
.
REDIS_SMS_CODE_COUNT
+
phoneNo
;
Long
getPhoneVerificationCount
=
redisTemplate
.
opsForHash
().
increment
(
verificationPhoneCountKey
,
Constants
.
REDIS_SMS_CODE_COUNT
,
1
);
if
(
getPhoneVerificationCount
>
PHONE_MAX_PER_DAY
)
{
return
JsonResult
.
buildErrorStateResult
(
"今天已获取20次短信验证码,请使用语音验证码或明天再试"
,
null
);
}
String
verificationIPCountKey
=
getIp
();
if
(!
StringUtils
.
isEmpty
(
verificationIPCountKey
))
{
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
);
}
}
if
(!
StringUtils
.
isEmpty
(
deviceId
))
{
String
verificationDeviceCountKey
=
Constants
.
REDIS_SMS_DEVICE_COUNT
+
deviceId
;
Long
getDeviceVerificationCount
=
redisTemplate
.
opsForHash
().
increment
(
verificationDeviceCountKey
,
Constants
.
REDIS_SMS_DEVICE_COUNT
,
1
);
if
(
getDeviceVerificationCount
>
DEVICE_MAX_PER_DAY
)
{
return
JsonResult
.
buildErrorStateResult
(
"您设备已经达到获取今天短信验证码上限"
,
null
);
}
}
String
key
=
Constants
.
REDIS_PREFIX_VERIFICATION_CODE
+
phoneNo
;
long
expire
=
redisTemplate
.
getExpire
(
key
,
TimeUnit
.
MINUTES
);
if
(
expire
>=
EXPIRE_MINUTES
-
1
)
{
return
JsonResult
.
buildSuccessResult
(
"发送成功"
,
null
);
}
String
randomCode
=
smsIsDebug
?
"0000"
:
String
.
valueOf
(
random
.
nextInt
(
8999
)
+
1000
);
String
uniqueId
=
phoneNo
+
UUID
.
randomUUID
().
toString
().
replaceAll
(
"-"
,
""
);
List
<
String
>
newList
=
new
ArrayList
<>();
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
);
try
{
//smsService.getSmsSender().sendConfirmableMessage(confirmableMsg);
smsService
.
getSmsSender
().
sendMsg
(
message
);
redisTemplate
.
opsForValue
().
set
(
key
,
uniqueId
+
":"
+
randomCode
,
EXPIRE_MINUTES
,
TimeUnit
.
MINUTES
);
deleteRetSendCode
(
phoneNo
);
//删除用户重置密码,多次错误逻辑
if
(
needImageVlidate
(
verificationIPCountKey
,
deviceId
,
phoneNo
)){
return
JsonResult
.
buildSuccessResult
(
"发送成功"
,
uniqueId
,
0003
L
);
}
return
JsonResult
.
buildSuccessResult
(
"发送成功"
,
uniqueId
);
}
catch
(
Exception
e
)
{
LOGGER
.
error
(
"发送短信验证码失败"
);
return
JsonResult
.
buildErrorStateResult
(
"发送失败"
,
null
);
}
}
/**
* 新版本语音验证码
*/
private
JsonResult
sendVerificationCode2VoiceNew
(
String
phoneNo
,
String
usage
,
String
deviceId
)
{
String
verificationCountKey
=
Constants
.
REDIS_VOICE_CODE_COUNT
+
phoneNo
;
Long
getVerificationCount
=
redisTemplate
.
opsForHash
().
increment
(
verificationCountKey
,
usage
.
toString
(),
1
);
if
(
getVerificationCount
>
PHONE_VOICE_MAX_PER_DAY
)
{
return
JsonResult
.
buildErrorStateResult
(
"今天已获取5次语音验证码,请使用短信验证码或明天再试"
,
null
);
}
String
verificationIPCountKey
=
getIp
();
if
(!
StringUtils
.
isEmpty
(
verificationIPCountKey
))
{
verificationIPCountKey
=
Constants
.
REDIS_VOICE_IP_COUNT
+
verificationIPCountKey
;
Long
getIPVerificationCount
=
redisTemplate
.
opsForHash
().
increment
(
verificationIPCountKey
,
Constants
.
REDIS_VOICE_IP_COUNT
,
1
);
if
(
getIPVerificationCount
>
IP_MAX_PER_DAY
)
{
return
JsonResult
.
buildErrorStateResult
(
"您当前ip已经达到获取今天语音验证码上限"
,
null
);
}
}
if
(!
StringUtils
.
isEmpty
(
deviceId
))
{
String
verificationDeviceCountKey
=
Constants
.
REDIS_VOICE_DEVICE_COUNT
+
deviceId
;
Long
getDeviceVerificationCount
=
redisTemplate
.
opsForHash
().
increment
(
verificationDeviceCountKey
,
Constants
.
REDIS_VOICE_DEVICE_COUNT
,
1
);
if
(
getDeviceVerificationCount
>
DEVICE_MAX_PER_DAY
)
{
return
JsonResult
.
buildErrorStateResult
(
"您设备已经达到获取今天语音验证码上限"
,
null
);
}
}
redisTemplate
.
expire
(
verificationCountKey
,
DateUtils
.
getSeconds
(),
TimeUnit
.
SECONDS
);
if
(!
ValidationUtil
.
validatePhoneNo
(
phoneNo
))
{
return
JsonResult
.
buildErrorStateResult
(
"手机号格式有误"
,
null
);
}
String
key
=
Constants
.
REDIS_PREFIX_VERIFICATION_CODE
+
phoneNo
;
long
expire
=
redisTemplate
.
getExpire
(
key
,
TimeUnit
.
MINUTES
);
if
(
expire
>=
EXPIRE_MINUTES
-
1
)
{
return
JsonResult
.
buildSuccessResult
(
"发送成功"
,
null
);
}
String
randomCode
=
smsIsDebug
?
"0000"
:
String
.
valueOf
(
random
.
nextInt
(
8999
)
+
1000
);
String
uniqueId
=
phoneNo
+
UUID
.
randomUUID
().
toString
().
replaceAll
(
"-"
,
""
);
MsgParams
message
=
new
MsgParams
(
Collections
.
singletonList
(
4
),
phoneNo
,
"1"
,
"4"
,
Collections
.
singletonList
(
randomCode
),
uniqueId
);
try
{
smsService
.
getSmsSender
().
sendMsg
(
message
);
redisTemplate
.
opsForValue
().
set
(
key
,
uniqueId
+
":"
+
randomCode
,
EXPIRE_MINUTES
,
TimeUnit
.
MINUTES
);
deleteRetSendCode
(
phoneNo
);
//删除用户重置密码,多次错误逻辑
if
(
needImageVlidate
(
verificationIPCountKey
,
deviceId
,
phoneNo
)){
return
JsonResult
.
buildSuccessResult
(
"发送成功"
,
uniqueId
,
0003
L
);
}
return
JsonResult
.
buildSuccessResult
(
"发送成功"
,
uniqueId
);
}
catch
(
Exception
e
)
{
LOGGER
.
error
(
"发送语音短信验证码失败"
);
return
JsonResult
.
buildErrorStateResult
(
"发送失败"
,
null
);
}
}
/**
* 判断下次是否提示图形验证码
* @param clientIp
* @param deviceId
* @param phoneNo
* @return
*/
private
boolean
needImageVlidate
(
String
clientIp
,
String
deviceId
,
String
phoneNo
)
{
boolean
need
=
false
;
String
countIP
=
redisTemplate
.
opsForValue
().
get
(
IMAGE_IP_COUNT
+
clientIp
);
String
countDeviceId
=
redisTemplate
.
opsForValue
().
get
(
IMAGE_DEVICEID_COUNT
+
deviceId
);
String
countPhoneNo
=
redisTemplate
.
opsForValue
().
get
(
IMAGE_PHONE_COUNT
+
phoneNo
);
Long
ip
=
StringUtils
.
isBlank
(
countIP
)
?
1L
:
Long
.
valueOf
(
countIP
);
Long
devId
=
StringUtils
.
isBlank
(
countDeviceId
)
?
1L
:
Long
.
valueOf
(
countDeviceId
);
Long
phNo
=
StringUtils
.
isBlank
(
countPhoneNo
)
?
1L
:
Long
.
valueOf
(
countPhoneNo
);
if
(
ip
>=
Constants
.
Image_Need_Count
||
devId
>=
Constants
.
Image_Need_Count
||
phNo
>=
Constants
.
Image_Need_Count
)
{
need
=
true
;
}
return
need
;
}
/**
* 删除用户重置密码是短信验证错误
* @param phoneNo
*/
private
void
deleteRetSendCode
(
String
phoneNo
){
String
verificationCountKey
=
Constants
.
REDIS_VERIFICATION_COUNT
+
phoneNo
;
redisTemplate
.
opsForHash
().
delete
(
verificationCountKey
,
Constants
.
REDIS_VERIFICATION_COUNT
);
}
}
}
src/main/java/cn/quantgroup/xyqb/controller/internal/user/UserController.java
View file @
8a797d43
...
@@ -201,7 +201,7 @@ public class UserController implements IBaseController {
...
@@ -201,7 +201,7 @@ public class UserController implements IBaseController {
}
}
if
(!
smsService
.
validateFastLoginVerificationCode
(
phoneNo
,
verificationCode
))
{
if
(!
smsService
.
validateFastLoginVerificationCode
(
phoneNo
,
verificationCode
))
{
LOGGER
.
info
(
"用户快速登录,验证码校验失败,phoneNo:{} , verificationCode:{}"
,
phoneNo
,
verificationCode
);
LOGGER
.
info
(
"用户快速登录,验证码校验失败,phoneNo:{} , verificationCode:{}"
,
phoneNo
,
verificationCode
);
result
.
put
(
"fail"
,
JsonResult
.
buildErrorStateResult
(
"验证码
错误
"
,
null
));
result
.
put
(
"fail"
,
JsonResult
.
buildErrorStateResult
(
"验证码
不正确
"
,
null
));
}
}
result
.
put
(
"success"
,
JsonResult
.
buildSuccessResult
(
""
,
phoneNo
));
result
.
put
(
"success"
,
JsonResult
.
buildSuccessResult
(
""
,
phoneNo
));
return
result
;
return
result
;
...
@@ -356,6 +356,11 @@ public class UserController implements IBaseController {
...
@@ -356,6 +356,11 @@ public class UserController implements IBaseController {
return
JsonResult
.
buildErrorStateResult
(
"密码应为6-12位"
,
null
);
return
JsonResult
.
buildErrorStateResult
(
"密码应为6-12位"
,
null
);
}
}
if
(!
smsService
.
validRegisterOrResetPasswdVerificationCode
(
phoneNo
,
verificationCode
))
{
if
(!
smsService
.
validRegisterOrResetPasswdVerificationCode
(
phoneNo
,
verificationCode
))
{
if
(
needRetSendCode
(
phoneNo
)){
String
key
=
Constants
.
REDIS_PREFIX_VERIFICATION_CODE
+
phoneNo
;
stringRedisTemplate
.
delete
(
key
);
return
JsonResult
.
buildErrorStateResult
(
"错误次数过多,请重新获取短信验证码"
,
null
);
}
return
JsonResult
.
buildErrorStateResult
(
"短信验证码错误"
,
null
);
return
JsonResult
.
buildErrorStateResult
(
"短信验证码错误"
,
null
);
}
}
if
(!
userService
.
resetPassword
(
phoneNo
,
password
))
{
if
(!
userService
.
resetPassword
(
phoneNo
,
password
))
{
...
@@ -367,6 +372,21 @@ public class UserController implements IBaseController {
...
@@ -367,6 +372,21 @@ 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
);
if
(
getVerificationCount
>
5
){
return
needRetSend
=
true
;
}
return
needRetSend
;
}
/**
/**
* 检查token是否已经过期不存在了
* 检查token是否已经过期不存在了
*
*
...
...
src/main/java/cn/quantgroup/xyqb/entity/User.java
View file @
8a797d43
...
@@ -21,8 +21,6 @@ import java.sql.Timestamp;
...
@@ -21,8 +21,6 @@ import java.sql.Timestamp;
@Table
(
name
=
"user"
,
uniqueConstraints
=
@UniqueConstraint
(
columnNames
=
"phone_no"
))
@Table
(
name
=
"user"
,
uniqueConstraints
=
@UniqueConstraint
(
columnNames
=
"phone_no"
))
public
class
User
implements
Serializable
{
public
class
User
implements
Serializable
{
private
static
final
long
serialVersionUID
=
-
1L
;
@Id
@Id
@Column
(
name
=
"id"
)
@Column
(
name
=
"id"
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
@GeneratedValue
(
strategy
=
GenerationType
.
IDENTITY
)
...
@@ -56,6 +54,8 @@ public class User implements Serializable {
...
@@ -56,6 +54,8 @@ public class User implements Serializable {
@Column
(
name
=
"updated_at"
)
@Column
(
name
=
"updated_at"
)
@JSONField
(
serializeUsing
=
Timestamp2LongConverter
.
class
)
@JSONField
(
serializeUsing
=
Timestamp2LongConverter
.
class
)
private
Timestamp
updatedAt
;
private
Timestamp
updatedAt
;
private
static
final
long
serialVersionUID
=
-
1L
;
public
XUser
toXUser
()
{
public
XUser
toXUser
()
{
...
...
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