Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
jinli gu
Litemall
Commits
bd22847a
Commit
bd22847a
authored
Jul 21, 2018
by
Menethil
Browse files
添加注册短信验证和重置密码短信验证
parent
129cd27f
Changes
9
Hide whitespace changes
Inline
Side-by-side
litemall-core/src/main/java/org/linlinjava/litemall/core/notify/NotifyService.java
View file @
bd22847a
package
org.linlinjava.litemall.core.notify
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.mail.MailSender
;
import
org.springframework.mail.SimpleMailMessage
;
import
org.springframework.scheduling.annotation.Async
;
...
...
@@ -54,6 +53,23 @@ public class NotifyService {
smsSender
.
sendWithTemplate
(
phoneNumber
,
templateId
,
params
);
}
/**
* 以同步的方式发送短信模版消息通知
*
* @param phoneNumber 接收通知的电话号码
* @param notifyType 通知类别,通过该枚举值在配置文件中获取相应的模版ID
* @param params 通知模版内容里的参数,类似"您的验证码为{1}"中{1}的值
* @return
*/
public
SmsResult
notifySmsTemplateSync
(
String
phoneNumber
,
NotifyType
notifyType
,
String
[]
params
)
{
if
(
smsSender
==
null
)
return
null
;
int
templateId
=
Integer
.
parseInt
(
getTemplateId
(
notifyType
,
smsTemplate
));
return
smsSender
.
sendWithTemplate
(
phoneNumber
,
templateId
,
params
);
}
/**
* 微信模版消息通知
*
...
...
litemall-core/src/main/java/org/linlinjava/litemall/core/notify/SmsResult.java
0 → 100644
View file @
bd22847a
package
org.linlinjava.litemall.core.notify
;
/**
* 发送短信的返回结果
*/
public
class
SmsResult
{
private
boolean
successful
;
private
Object
result
;
/**
* 短信是否发送成功
*
* @return
*/
public
boolean
isSuccessful
()
{
return
successful
;
}
public
void
setSuccessful
(
boolean
successful
)
{
this
.
successful
=
successful
;
}
public
Object
getResult
()
{
return
result
;
}
public
void
setResult
(
Object
result
)
{
this
.
result
=
result
;
}
}
litemall-core/src/main/java/org/linlinjava/litemall/core/notify/SmsSender.java
View file @
bd22847a
...
...
@@ -8,7 +8,7 @@ public interface SmsSender {
* @param phone 接收通知的电话号码
* @param content 短消息内容
*/
void
send
(
String
phone
,
String
content
);
SmsResult
send
(
String
phone
,
String
content
);
/**
...
...
@@ -18,5 +18,5 @@ public interface SmsSender {
* @param templateId 通知模板ID
* @param params 通知模版内容里的参数,类似"您的验证码为{1}"中{1}的值
*/
void
sendWithTemplate
(
String
phone
,
int
templateId
,
String
[]
params
);
SmsResult
sendWithTemplate
(
String
phone
,
int
templateId
,
String
[]
params
);
}
\ No newline at end of file
litemall-core/src/main/java/org/linlinjava/litemall/core/notify/TencentSmsSender.java
View file @
bd22847a
...
...
@@ -5,11 +5,14 @@ import com.github.qcloudsms.SmsSingleSenderResult;
import
com.github.qcloudsms.httpclient.HTTPException
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.springframework.stereotype.Service
;
import
java.io.IOException
;
/*
* 腾讯云短信服务
*/
@Service
public
class
TencentSmsSender
implements
SmsSender
{
private
final
Log
logger
=
LogFactory
.
getLog
(
TencentSmsSender
.
class
);
...
...
@@ -24,22 +27,36 @@ public class TencentSmsSender implements SmsSender {
}
@Override
public
void
send
(
String
phone
,
String
content
)
{
public
SmsResult
send
(
String
phone
,
String
content
)
{
try
{
SmsSingleSenderResult
result
=
sender
.
send
(
0
,
"86"
,
phone
,
content
,
""
,
""
);
logger
.
debug
(
result
);
SmsResult
smsResult
=
new
SmsResult
();
smsResult
.
setSuccessful
(
true
);
smsResult
.
setResult
(
result
);
return
smsResult
;
}
catch
(
HTTPException
|
IOException
e
)
{
e
.
printStackTrace
();
}
return
null
;
}
@Override
public
void
sendWithTemplate
(
String
phone
,
int
templateId
,
String
[]
params
)
{
public
SmsResult
sendWithTemplate
(
String
phone
,
int
templateId
,
String
[]
params
)
{
try
{
SmsSingleSenderResult
result
=
sender
.
sendWithParam
(
"86"
,
phone
,
templateId
,
params
,
""
,
""
,
""
);
logger
.
debug
(
result
);
SmsResult
smsResult
=
new
SmsResult
();
smsResult
.
setSuccessful
(
true
);
smsResult
.
setResult
(
result
);
return
smsResult
;
}
catch
(
HTTPException
|
IOException
e
)
{
e
.
printStackTrace
();
}
return
null
;
}
}
litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/dao/CaptchaItem.java
0 → 100644
View file @
bd22847a
package
org.linlinjava.litemall.wx.dao
;
import
java.time.LocalDateTime
;
public
class
CaptchaItem
{
private
String
phoneNumber
;
private
String
code
;
private
LocalDateTime
expireTime
;
public
String
getPhoneNumber
()
{
return
phoneNumber
;
}
public
void
setPhoneNumber
(
String
phoneNumber
)
{
this
.
phoneNumber
=
phoneNumber
;
}
public
String
getCode
()
{
return
code
;
}
public
void
setCode
(
String
code
)
{
this
.
code
=
code
;
}
public
LocalDateTime
getExpireTime
()
{
return
expireTime
;
}
public
void
setExpireTime
(
LocalDateTime
expireTime
)
{
this
.
expireTime
=
expireTime
;
}
}
\ No newline at end of file
litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/service/CaptchaCodeManager.java
0 → 100644
View file @
bd22847a
package
org.linlinjava.litemall.wx.service
;
import
org.linlinjava.litemall.wx.dao.CaptchaItem
;
import
java.time.LocalDateTime
;
import
java.util.HashMap
;
import
java.util.Map
;
/**
* 缓存系统中的验证码
*/
public
class
CaptchaCodeManager
{
private
static
Map
<
String
,
CaptchaItem
>
captchaCodeCache
=
new
HashMap
<>();
/**
* 添加到缓存
*
* @param phoneNumber 电话号码
* @param code 验证码
*/
public
static
boolean
addToCache
(
String
phoneNumber
,
String
code
)
{
//已经发过验证码且验证码还未过期
if
(
captchaCodeCache
.
get
(
phoneNumber
)
!=
null
)
{
if
(
captchaCodeCache
.
get
(
phoneNumber
).
getExpireTime
().
isAfter
(
LocalDateTime
.
now
()))
{
return
false
;
}
else
{
//存在但是已过期,删掉
captchaCodeCache
.
remove
(
phoneNumber
);
}
}
CaptchaItem
captchaItem
=
new
CaptchaItem
();
captchaItem
.
setPhoneNumber
(
phoneNumber
);
captchaItem
.
setCode
(
code
);
// 有效期为1分钟
captchaItem
.
setExpireTime
(
LocalDateTime
.
now
().
plusMinutes
(
1
));
captchaCodeCache
.
put
(
phoneNumber
,
captchaItem
);
return
true
;
}
/**
* 获取缓存的验证码
*
* @param phoneNumber 关联的电话号码
* @return 验证码
*/
public
static
String
getCachedCaptcha
(
String
phoneNumber
)
{
//没有这个电话记录
if
(
captchaCodeCache
.
get
(
phoneNumber
)
==
null
)
return
null
;
//有电话记录但是已经过期
if
(
captchaCodeCache
.
get
(
phoneNumber
).
getExpireTime
().
isBefore
(
LocalDateTime
.
now
()))
{
return
null
;
}
return
captchaCodeCache
.
get
(
phoneNumber
).
getCode
();
}
}
litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxAuthController.java
View file @
bd22847a
...
...
@@ -5,17 +5,22 @@ import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import
me.chanjar.weixin.common.exception.WxErrorException
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.linlinjava.litemall.core.notify.NotifyService
;
import
org.linlinjava.litemall.core.notify.NotifyType
;
import
org.linlinjava.litemall.core.notify.SmsResult
;
import
org.linlinjava.litemall.core.util.CharUtil
;
import
org.linlinjava.litemall.core.util.JacksonUtil
;
import
org.linlinjava.litemall.core.util.RegexUtil
;
import
org.linlinjava.litemall.core.util.ResponseUtil
;
import
org.linlinjava.litemall.core.util.bcrypt.BCryptPasswordEncoder
;
import
org.linlinjava.litemall.db.domain.LitemallUser
;
import
org.linlinjava.litemall.db.service.LitemallUserService
;
import
org.linlinjava.litemall.core.util.JacksonUtil
;
import
org.linlinjava.litemall.core.util.ResponseUtil
;
import
org.linlinjava.litemall.wx.dao.WxLoginInfo
;
import
org.linlinjava.litemall.wx.dao.UserInfo
;
import
org.linlinjava.litemall.wx.dao.UserToken
;
import
org.linlinjava.litemall.wx.dao.WxLoginInfo
;
import
org.linlinjava.litemall.wx.service.CaptchaCodeManager
;
import
org.linlinjava.litemall.wx.service.UserTokenManager
;
import
org.linlinjava.litemall.wx.util.IpUtil
;
import
org.linlinjava.litemall.core.util.bcrypt.BCryptPasswordEncoder
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.web.bind.annotation.PostMapping
;
import
org.springframework.web.bind.annotation.RequestBody
;
...
...
@@ -39,47 +44,48 @@ public class WxAuthController {
@Autowired
private
WxMaService
wxService
;
@Autowired
private
NotifyService
notifyService
;
/**
* 账号登录
*
* @param body 请求内容,{ username: xxx, password: xxx }
* @param body
请求内容,{ username: xxx, password: xxx }
* @param request 请求对象
* @return 登录结果
*
成功则
*
{
*
errno: 0,
*
errmsg: '成功',
*
data:
*
{
*
token: xxx,
*
tokenExpire: xxx,
*
userInfo: xxx
*
}
*
}
*
失败则 { errno: XXX, errmsg: XXX }
* 成功则
* {
* errno: 0,
* errmsg: '成功',
* data:
* {
* token: xxx,
* tokenExpire: xxx,
* userInfo: xxx
* }
* }
* 失败则 { errno: XXX, errmsg: XXX }
*/
@RequestMapping
(
"login"
)
public
Object
login
(
@RequestBody
String
body
,
HttpServletRequest
request
)
{
String
username
=
JacksonUtil
.
parseString
(
body
,
"username"
);
String
password
=
JacksonUtil
.
parseString
(
body
,
"password"
);
if
(
username
==
null
||
password
==
null
){
if
(
username
==
null
||
password
==
null
)
{
return
ResponseUtil
.
badArgument
();
}
List
<
LitemallUser
>
userList
=
userService
.
queryByUsername
(
username
);
List
<
LitemallUser
>
userList
=
userService
.
queryByUsername
(
username
);
LitemallUser
user
=
null
;
if
(
userList
.
size
()
>
1
){
if
(
userList
.
size
()
>
1
)
{
return
ResponseUtil
.
serious
();
}
else
if
(
userList
.
size
()
==
0
){
}
else
if
(
userList
.
size
()
==
0
)
{
return
ResponseUtil
.
badArgumentValue
();
}
else
{
}
else
{
user
=
userList
.
get
(
0
);
}
BCryptPasswordEncoder
encoder
=
new
BCryptPasswordEncoder
();
if
(!
encoder
.
matches
(
password
,
user
.
getPassword
())){
if
(!
encoder
.
matches
(
password
,
user
.
getPassword
()))
{
return
ResponseUtil
.
fail
(
403
,
"账号密码不对"
);
}
...
...
@@ -102,26 +108,26 @@ public class WxAuthController {
* 微信登录
*
* @param wxLoginInfo 请求内容,{ code: xxx, userInfo: xxx }
* @param request 请求对象
* @param request
请求对象
* @return 登录结果
*
成功则
*
{
*
errno: 0,
*
errmsg: '成功',
*
data:
*
{
*
token: xxx,
*
tokenExpire: xxx,
*
userInfo: xxx
*
}
*
}
*
失败则 { errno: XXX, errmsg: XXX }
* 成功则
* {
* errno: 0,
* errmsg: '成功',
* data:
* {
* token: xxx,
* tokenExpire: xxx,
* userInfo: xxx
* }
* }
* 失败则 { errno: XXX, errmsg: XXX }
*/
@RequestMapping
(
"login_by_weixin"
)
public
Object
loginByWeixin
(
@RequestBody
WxLoginInfo
wxLoginInfo
,
HttpServletRequest
request
)
{
String
code
=
wxLoginInfo
.
getCode
();
UserInfo
userInfo
=
wxLoginInfo
.
getUserInfo
();
if
(
code
==
null
||
userInfo
==
null
){
if
(
code
==
null
||
userInfo
==
null
)
{
return
ResponseUtil
.
badArgument
();
}
...
...
@@ -135,12 +141,12 @@ public class WxAuthController {
e
.
printStackTrace
();
}
if
(
sessionKey
==
null
||
openId
==
null
){
if
(
sessionKey
==
null
||
openId
==
null
)
{
return
ResponseUtil
.
fail
();
}
LitemallUser
user
=
userService
.
queryByOid
(
openId
);
if
(
user
==
null
){
if
(
user
==
null
)
{
user
=
new
LitemallUser
();
user
.
setUsername
(
userInfo
.
getNickName
());
// 其实没有用,因为用户没有真正注册
user
.
setPassword
(
openId
);
// 其实没有用,因为用户没有真正注册
...
...
@@ -148,15 +154,14 @@ public class WxAuthController {
user
.
setAvatar
(
userInfo
.
getAvatarUrl
());
user
.
setNickname
(
userInfo
.
getNickName
());
user
.
setGender
(
userInfo
.
getGender
());
user
.
setUserLevel
((
byte
)
0
);
user
.
setStatus
((
byte
)
0
);
user
.
setUserLevel
((
byte
)
0
);
user
.
setStatus
((
byte
)
0
);
user
.
setLastLoginTime
(
LocalDateTime
.
now
());
user
.
setLastLoginIp
(
IpUtil
.
client
(
request
));
user
.
setAddTime
(
LocalDateTime
.
now
());
userService
.
add
(
user
);
}
else
{
}
else
{
user
.
setLastLoginTime
(
LocalDateTime
.
now
());
user
.
setLastLoginIp
(
IpUtil
.
client
(
request
));
userService
.
update
(
user
);
...
...
@@ -172,31 +177,49 @@ public class WxAuthController {
return
ResponseUtil
.
ok
(
result
);
}
/**
* 请求验证码
*
* @param body 手机号码{mobile}
* @return
*/
@PostMapping
(
"regCaptcha"
)
public
Object
registerCaptcha
(
@RequestBody
String
body
)
{
String
phoneNumber
=
JacksonUtil
.
parseString
(
body
,
"mobile"
);
String
code
=
CharUtil
.
getRandomNum
(
6
);
notifyService
.
notifySmsTemplateSync
(
phoneNumber
,
NotifyType
.
CAPTCHA
,
new
String
[]{
code
});
boolean
successful
=
CaptchaCodeManager
.
addToCache
(
phoneNumber
,
code
);
return
successful
?
ResponseUtil
.
ok
()
:
ResponseUtil
.
badArgument
();
}
/**
* 账号注册
*
* @param body 请求内容
* {
* username: xxx,
* password: xxx,
* mobile: xxx
* code: xxx
* }
* 其中code是手机验证码,目前还不支持手机短信验证码
* @param body
请求内容
*
{
*
username: xxx,
*
password: xxx,
*
mobile: xxx
*
code: xxx
*
}
*
其中code是手机验证码,目前还不支持手机短信验证码
* @param request 请求对象
* @return 登录结果
*
成功则
*
{
*
errno: 0,
*
errmsg: '成功',
*
data:
*
{
*
token: xxx,
*
tokenExpire: xxx,
*
userInfo: xxx
*
}
*
}
*
失败则 { errno: XXX, errmsg: XXX }
* 成功则
* {
* errno: 0,
* errmsg: '成功',
* data:
* {
* token: xxx,
* tokenExpire: xxx,
* userInfo: xxx
* }
* }
* 失败则 { errno: XXX, errmsg: XXX }
*/
@PostMapping
(
"register"
)
public
Object
register
(
@RequestBody
String
body
,
HttpServletRequest
request
)
{
...
...
@@ -205,22 +228,27 @@ public class WxAuthController {
String
mobile
=
JacksonUtil
.
parseString
(
body
,
"mobile"
);
String
code
=
JacksonUtil
.
parseString
(
body
,
"code"
);
if
(
username
==
null
||
password
==
null
||
mobile
==
null
||
code
==
null
){
if
(
username
==
null
||
password
==
null
||
mobile
==
null
||
code
==
null
)
{
return
ResponseUtil
.
badArgument
();
}
List
<
LitemallUser
>
userList
=
userService
.
queryByUsername
(
username
);
if
(
userList
.
size
()
>
0
){
if
(
userList
.
size
()
>
0
)
{
return
ResponseUtil
.
fail
(
403
,
"用户名已注册"
);
}
userList
=
userService
.
queryByMobile
(
mobile
);
if
(
userList
.
size
()
>
0
){
if
(
userList
.
size
()
>
0
)
{
return
ResponseUtil
.
fail
(
403
,
"手机号已注册"
);
}
if
(!
RegexUtil
.
isMobileExact
(
mobile
)){
if
(!
RegexUtil
.
isMobileExact
(
mobile
))
{
return
ResponseUtil
.
fail
(
403
,
"手机号格式不正确"
);
}
//判断验证码是否正确
String
cacheCode
=
CaptchaCodeManager
.
getCachedCaptcha
(
mobile
);
if
(
cacheCode
==
null
||
cacheCode
.
isEmpty
()
||
!
cacheCode
.
equals
(
code
))
return
ResponseUtil
.
fail
(
403
,
"验证码错误"
);
LitemallUser
user
=
new
LitemallUser
();
BCryptPasswordEncoder
encoder
=
new
BCryptPasswordEncoder
();
...
...
@@ -234,9 +262,9 @@ public class WxAuthController {
user
.
setWeixinOpenid
(
""
);
user
.
setAvatar
(
"https://yanxuan.nosdn.127.net/80841d741d7fa3073e0ae27bf487339f.jpg?imageView&quality=90&thumbnail=64x64"
);
user
.
setNickname
(
username
);
user
.
setGender
((
byte
)
0
);
user
.
setUserLevel
((
byte
)
0
);
user
.
setStatus
((
byte
)
0
);
user
.
setGender
((
byte
)
0
);
user
.
setUserLevel
((
byte
)
0
);
user
.
setStatus
((
byte
)
0
);
user
.
setLastLoginTime
(
LocalDateTime
.
now
());
user
.
setLastLoginIp
(
IpUtil
.
client
(
request
));
user
.
setAddTime
(
LocalDateTime
.
now
());
...
...
@@ -261,17 +289,17 @@ public class WxAuthController {
/**
* 账号密码重置
*
* @param body 请求内容
* {
* password: xxx,
* mobile: xxx
* code: xxx
* }
* 其中code是手机验证码,目前还不支持手机短信验证码
* @param body
请求内容
*
{
*
password: xxx,
*
mobile: xxx
*
code: xxx
*
}
*
其中code是手机验证码,目前还不支持手机短信验证码
* @param request 请求对象
* @return 登录结果
*
成功则 { errno: 0, errmsg: '成功' }
*
失败则 { errno: XXX, errmsg: XXX }
* 成功则 { errno: 0, errmsg: '成功' }
* 失败则 { errno: XXX, errmsg: XXX }
*/
@PostMapping
(
"reset"
)
public
Object
reset
(
@RequestBody
String
body
,
HttpServletRequest
request
)
{
...
...
@@ -279,22 +307,26 @@ public class WxAuthController {
String
mobile
=
JacksonUtil
.
parseString
(
body
,
"mobile"
);
String
code
=
JacksonUtil
.
parseString
(
body
,
"code"
);
if
(
mobile
==
null
||
code
==
null
||
password
==
null
){
if
(
mobile
==
null
||
code
==
null
||
password
==
null
)
{
return
ResponseUtil
.
badArgument
();
}
//判断验证码是否正确
String
cacheCode
=
CaptchaCodeManager
.
getCachedCaptcha
(
mobile
);
if
(
cacheCode
==
null
||
cacheCode
.
isEmpty
()
||
!
cacheCode
.
equals
(
code
))
return
ResponseUtil
.
fail
(
403
,
"验证码错误"
);
List
<
LitemallUser
>
userList
=
userService
.
queryByMobile
(
mobile
);
LitemallUser
user
=
null
;
if
(
userList
.
size
()
>
1
){
if
(
userList
.
size
()
>
1
)
{
return
ResponseUtil
.
serious
();
}
else
if
(
userList
.
size
()
==
0
){
}
else
if
(
userList
.
size
()
==
0
)
{
return
ResponseUtil
.
fail
(
403
,
"手机号未注册"
);
}
else
{
}
else
{
user
=
userList
.
get
(
0
);
}
// TODO 重新生成的密码无法登陆
BCryptPasswordEncoder
encoder
=
new
BCryptPasswordEncoder
();
String
encodedPassword
=
encoder
.
encode
(
password
);
user
.
setPassword
(
encodedPassword
);
...
...
litemall-wx/pages/auth/register/register.js
View file @
bd22847a
...
...
@@ -31,10 +31,32 @@ Page({
},
sendCode
:
function
()
{
wx
.
showModal
({
title
:
'
注意
'
,
content
:
'
由于目前不支持手机短信发送,因此验证码任意值都可以
'
,
showCancel
:
false
let
that
=
this
;
wx
.
request
({
url
:
api
.
AuthRegisterCaptcha
,
data
:
{
mobile
:
that
.
data
.
mobile
},
method
:
'
POST
'
,
header
:
{
'
content-type
'
:
'
application/json
'
},
success
:
function
(
res
)
{
if
(
res
.
data
.
errno
==
0
)
{
wx
.
showModal
({
title
:
'
发送成功
'
,
content
:
'
验证码已发送
'
,
showCancel
:
false
});
}
else
{
wx
.
showModal
({
title
:
'
错误信息
'
,
content
:
res
.
data
.
errmsg
,
showCancel
:
false
});
}
}
});
},
startRegister
:
function
()
{
...
...
litemall-wx/pages/auth/reset/reset.js
View file @
bd22847a
...
...
@@ -29,11 +29,34 @@ Page({
// 页面关闭
},
sendCode
:
function
()
{
wx
.
showModal
({
title
:
'
注意
'
,
content
:
'
由于目前不支持手机短信发送,因此验证码任意值都可以
'
,
showCancel
:
false
let
that
=
this
;
wx
.
request
({
url
:
api
.
AuthRegisterCaptcha
,
data
:
{
mobile
:
that
.
data
.
mobile
},
method
:
'
POST
'
,
header
:
{
'
content-type
'
:
'
application/json
'
},
success
:
function
(
res
)
{
if
(
res
.
data
.
errno
==
0
)
{
wx
.
showModal
({
title
:
'
发送成功
'
,
content
:
'
验证码已发送
'
,
showCancel
:
false
});
}
else
{
wx
.
showModal
({
title
:
'
错误信息
'
,
content
:
res
.
data
.
errmsg
,
showCancel
:
false
});
}
}
});
},
startReset
:
function
(){
...
...
Write
Preview
Supports
Markdown
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