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
679117d5
Commit
679117d5
authored
Dec 27, 2020
by
linlinjava
Browse files
feat: 支持验证码
parent
519d7b15
Changes
13
Hide whitespace changes
Inline
Side-by-side
litemall-admin-api/pom.xml
View file @
679117d5
...
...
@@ -40,6 +40,10 @@
<groupId>
org.apache.shiro
</groupId>
<artifactId>
shiro-spring-boot-web-starter
</artifactId>
</dependency>
<dependency>
<groupId>
com.github.penggle
</groupId>
<artifactId>
kaptcha
</artifactId>
</dependency>
<dependency>
<groupId>
com.github.xiaoymin
</groupId>
<artifactId>
swagger-bootstrap-ui
</artifactId>
...
...
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/config/KaptchaConfig.java
0 → 100644
View file @
679117d5
package
org.linlinjava.litemall.admin.config
;
import
com.google.code.kaptcha.Producer
;
import
com.google.code.kaptcha.impl.DefaultKaptcha
;
import
com.google.code.kaptcha.util.Config
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
java.util.Properties
;
@Configuration
public
class
KaptchaConfig
{
@Bean
public
Producer
kaptchaProducer
()
{
Properties
properties
=
new
Properties
();
properties
.
setProperty
(
"kaptcha.image.width"
,
"100"
);
properties
.
setProperty
(
"kaptcha.image.height"
,
"40"
);
properties
.
setProperty
(
"kaptcha.textproducer.font.size"
,
"32"
);
properties
.
setProperty
(
"kaptcha.textproducer.font.color"
,
"0,0,0"
);
properties
.
setProperty
(
"kaptcha.textproducer.char.string"
,
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYAZ"
);
properties
.
setProperty
(
"kaptcha.textproducer.char.length"
,
"4"
);
properties
.
setProperty
(
"kaptcha.noise.impl"
,
"com.google.code.kaptcha.impl.NoNoise"
);
DefaultKaptcha
kaptcha
=
new
DefaultKaptcha
();
Config
config
=
new
Config
(
properties
);
kaptcha
.
setConfig
(
config
);
return
kaptcha
;
}
}
\ No newline at end of file
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/config/ShiroConfig.java
View file @
679117d5
...
...
@@ -29,6 +29,7 @@ public class ShiroConfig {
ShiroFilterFactoryBean
shiroFilterFactoryBean
=
new
ShiroFilterFactoryBean
();
shiroFilterFactoryBean
.
setSecurityManager
(
securityManager
);
Map
<
String
,
String
>
filterChainDefinitionMap
=
new
LinkedHashMap
<
String
,
String
>();
filterChainDefinitionMap
.
put
(
"/admin/auth/kaptcha"
,
"anon"
);
filterChainDefinitionMap
.
put
(
"/admin/auth/login"
,
"anon"
);
filterChainDefinitionMap
.
put
(
"/admin/auth/401"
,
"anon"
);
filterChainDefinitionMap
.
put
(
"/admin/auth/index"
,
"anon"
);
...
...
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/shiro/AdminWebSessionManager.java
View file @
679117d5
...
...
@@ -18,7 +18,7 @@ public class AdminWebSessionManager extends DefaultWebSessionManager {
public
AdminWebSessionManager
()
{
super
();
setGlobalSessionTimeout
(
MILLIS_PER_HOUR
*
6
);
setSessionIdCookieEnabled
(
false
);
//
setSessionIdCookieEnabled(false);
setSessionIdUrlRewritingEnabled
(
false
);
}
...
...
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/util/AdminResponseCode.java
View file @
679117d5
...
...
@@ -7,6 +7,8 @@ public class AdminResponseCode {
public
static
final
Integer
ADMIN_ALTER_NOT_ALLOWED
=
603
;
public
static
final
Integer
ADMIN_DELETE_NOT_ALLOWED
=
604
;
public
static
final
Integer
ADMIN_INVALID_ACCOUNT
=
605
;
public
static
final
Integer
ADMIN_INVALID_KAPTCHA
=
606
;
public
static
final
Integer
ADMIN_INVALID_KAPTCHA_REQUIRED
=
607
;
public
static
final
Integer
GOODS_UPDATE_NOT_ALLOWED
=
610
;
public
static
final
Integer
GOODS_NAME_EXIST
=
611
;
public
static
final
Integer
ORDER_CONFIRM_NOT_ALLOWED
=
620
;
...
...
litemall-admin-api/src/main/java/org/linlinjava/litemall/admin/web/AdminAuthController.java
View file @
679117d5
package
org.linlinjava.litemall.admin.web
;
import
com.google.code.kaptcha.Producer
;
import
org.apache.commons.logging.Log
;
import
org.apache.commons.logging.LogFactory
;
import
org.apache.shiro.SecurityUtils
;
...
...
@@ -24,12 +25,18 @@ import org.springframework.context.ApplicationContext;
import
org.springframework.util.StringUtils
;
import
org.springframework.validation.annotation.Validated
;
import
org.springframework.web.bind.annotation.*
;
import
sun.misc.BASE64Encoder
;
import
javax.imageio.ImageIO
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpSession
;
import
java.awt.image.BufferedImage
;
import
java.io.ByteArrayOutputStream
;
import
java.io.IOException
;
import
java.time.LocalDateTime
;
import
java.util.*
;
import
static
org
.
linlinjava
.
litemall
.
admin
.
util
.
AdminResponseCode
.
ADMIN_INVALID_ACCOUNT
;
import
static
org
.
linlinjava
.
litemall
.
admin
.
util
.
AdminResponseCode
.
*
;
@RestController
@RequestMapping
(
"/admin/auth"
)
...
...
@@ -46,6 +53,37 @@ public class AdminAuthController {
@Autowired
private
LogHelper
logHelper
;
@Autowired
private
Producer
kaptchaProducer
;
@GetMapping
(
"/kaptcha"
)
public
Object
kaptcha
(
HttpServletRequest
request
)
{
String
kaptcha
=
doKaptcha
(
request
);
if
(
kaptcha
!=
null
)
{
return
ResponseUtil
.
ok
(
kaptcha
);
}
return
ResponseUtil
.
fail
();
}
private
String
doKaptcha
(
HttpServletRequest
request
)
{
// 生成验证码
String
text
=
kaptchaProducer
.
createText
();
BufferedImage
image
=
kaptchaProducer
.
createImage
(
text
);
HttpSession
session
=
request
.
getSession
();
session
.
setAttribute
(
"kaptcha"
,
text
);
try
{
ByteArrayOutputStream
outputStream
=
new
ByteArrayOutputStream
();
ImageIO
.
write
(
image
,
"jpeg"
,
outputStream
);
BASE64Encoder
encoder
=
new
BASE64Encoder
();
String
base64
=
encoder
.
encode
(
outputStream
.
toByteArray
());
String
captchaBase64
=
"data:image/jpeg;base64,"
+
base64
.
replaceAll
(
"\r\n"
,
""
);
return
captchaBase64
;
}
catch
(
IOException
e
)
{
return
null
;
}
}
/*
* { username : value, password : value }
*/
...
...
@@ -53,10 +91,20 @@ public class AdminAuthController {
public
Object
login
(
@RequestBody
String
body
,
HttpServletRequest
request
)
{
String
username
=
JacksonUtil
.
parseString
(
body
,
"username"
);
String
password
=
JacksonUtil
.
parseString
(
body
,
"password"
);
String
code
=
JacksonUtil
.
parseString
(
body
,
"code"
);
if
(
StringUtils
.
isEmpty
(
username
)
||
StringUtils
.
isEmpty
(
password
))
{
return
ResponseUtil
.
badArgument
();
}
if
(
StringUtils
.
isEmpty
(
code
))
{
return
ResponseUtil
.
fail
(
ADMIN_INVALID_KAPTCHA_REQUIRED
,
"验证码不能空"
);
}
HttpSession
session
=
request
.
getSession
();
String
kaptcha
=
(
String
)
session
.
getAttribute
(
"kaptcha"
);
if
(
Objects
.
requireNonNull
(
code
).
compareToIgnoreCase
(
kaptcha
)
!=
0
)
{
return
ResponseUtil
.
fail
(
ADMIN_INVALID_KAPTCHA
,
"验证码不正确"
,
doKaptcha
(
request
));
}
Subject
currentUser
=
SecurityUtils
.
getSubject
();
try
{
...
...
litemall-admin/src/api/login.js
View file @
679117d5
import
request
from
'
@/utils/request
'
export
function
loginByUsername
(
username
,
password
)
{
export
function
loginByUsername
(
username
,
password
,
code
)
{
const
data
=
{
username
,
password
password
,
code
}
return
request
({
url
:
'
/auth/login
'
,
...
...
@@ -27,3 +28,9 @@ export function getUserInfo(token) {
})
}
export
function
getKaptcha
()
{
return
request
({
url
:
'
/auth/kaptcha
'
,
method
:
'
get
'
})
}
litemall-admin/src/store/modules/user.js
View file @
679117d5
...
...
@@ -35,7 +35,7 @@ const user = {
LoginByUsername
({
commit
},
userInfo
)
{
const
username
=
userInfo
.
username
.
trim
()
return
new
Promise
((
resolve
,
reject
)
=>
{
loginByUsername
(
username
,
userInfo
.
password
).
then
(
response
=>
{
loginByUsername
(
username
,
userInfo
.
password
,
userInfo
.
code
).
then
(
response
=>
{
const
token
=
response
.
data
.
data
.
token
commit
(
'
SET_TOKEN
'
,
token
)
setToken
(
token
)
...
...
litemall-admin/src/utils/request.js
View file @
679117d5
...
...
@@ -3,6 +3,8 @@ import { Message, MessageBox } from 'element-ui'
import
store
from
'
@/store
'
import
{
getToken
}
from
'
@/utils/auth
'
axios
.
defaults
.
withCredentials
=
true
// create an axios instance
const
service
=
axios
.
create
({
baseURL
:
process
.
env
.
VUE_APP_BASE_API
,
// api 的 base_url
...
...
litemall-admin/src/views/login/index.vue
View file @
679117d5
...
...
@@ -18,6 +18,16 @@
<el-input
v-model=
"loginForm.password"
:type=
"passwordType"
name=
"password"
auto-complete=
"on"
tabindex=
"2"
show-password
placeholder=
"管理员密码"
@
keyup.enter.native=
"handleLogin"
/>
</el-form-item>
<el-form-item
prop=
"code"
>
<span
class=
"svg-container"
>
<svg-icon
icon-class=
"lock"
/>
</span>
<el-input
v-model=
"loginForm.code"
auto-complete=
"off"
name=
"code"
tabindex=
"2"
placeholder=
"验证码"
style=
"width: 60%"
@
keyup.enter.native=
"handleLogin"
/>
<div
class=
"login-code"
>
<img
:src=
"codeImg"
@
click=
"getCode"
>
</div>
</el-form-item>
<el-button
:loading=
"loading"
type=
"primary"
style=
"width:100%;margin-bottom:30px;"
@
click.native.prevent=
"handleLogin"
>
登录
</el-button>
<div
style=
"position:relative"
>
...
...
@@ -43,6 +53,8 @@
</
template
>
<
script
>
import
{
getKaptcha
}
from
'
@/api/login
'
export
default
{
name
:
'
Login
'
,
data
()
{
...
...
@@ -56,8 +68,10 @@ export default {
return
{
loginForm
:
{
username
:
'
admin123
'
,
password
:
'
admin123
'
password
:
'
admin123
'
,
code
:
''
},
codeImg
:
''
,
loginRules
:
{
username
:
[{
required
:
true
,
message
:
'
管理员账户不允许为空
'
,
trigger
:
'
blur
'
}],
password
:
[
...
...
@@ -79,12 +93,18 @@ export default {
},
created
()
{
this
.
getCode
()
// window.addEventListener('hashchange', this.afterQRScan)
},
destroyed
()
{
// window.removeEventListener('hashchange', this.afterQRScan)
},
methods
:
{
getCode
()
{
getKaptcha
().
then
(
response
=>
{
this
.
codeImg
=
response
.
data
.
data
})
},
handleLogin
()
{
this
.
$refs
.
loginForm
.
validate
(
valid
=>
{
if
(
valid
&&
!
this
.
loading
)
{
...
...
@@ -93,6 +113,9 @@ export default {
this
.
loading
=
false
this
.
$router
.
push
({
path
:
this
.
redirect
||
'
/
'
})
}).
catch
(
response
=>
{
if
(
response
.
data
.
errno
===
606
||
response
.
data
.
errno
===
605
)
{
this
.
codeImg
=
response
.
data
.
data
}
this
.
$notify
.
error
({
title
:
'
失败
'
,
message
:
response
.
data
.
errmsg
...
...
@@ -174,7 +197,14 @@ $light_gray:#eee;
margin
:
0
auto
;
overflow
:
hidden
;
}
.login-code
{
padding-top
:
5px
;
float
:
right
;
img
{
cursor
:
pointer
;
vertical-align
:middle
}
}
.tips
{
font-size
:
14px
;
color
:
#fff
;
...
...
litemall-core/src/main/java/org/linlinjava/litemall/core/config/CorsConfig.java
View file @
679117d5
...
...
@@ -17,6 +17,7 @@ public class CorsConfig {
corsConfiguration
.
addAllowedHeader
(
"*"
);
// 2 设置访问源请求头
corsConfiguration
.
addAllowedMethod
(
"*"
);
// 3 设置访问源请求方法
corsConfiguration
.
setMaxAge
(
maxAge
);
corsConfiguration
.
setAllowCredentials
(
true
);
return
corsConfiguration
;
}
...
...
litemall-core/src/main/java/org/linlinjava/litemall/core/util/ResponseUtil.java
View file @
679117d5
...
...
@@ -109,6 +109,14 @@ public class ResponseUtil {
return
obj
;
}
public
static
Object
fail
(
int
errno
,
String
errmsg
,
String
data
)
{
Map
<
String
,
Object
>
obj
=
new
HashMap
<
String
,
Object
>(
3
);
obj
.
put
(
"errno"
,
errno
);
obj
.
put
(
"errmsg"
,
errmsg
);
obj
.
put
(
"data"
,
data
);
return
obj
;
}
public
static
Object
badArgument
()
{
return
fail
(
401
,
"参数不对"
);
}
...
...
pom.xml
View file @
679117d5
...
...
@@ -154,7 +154,13 @@
<artifactId>
springfox-swagger-ui
</artifactId>
<version>
2.9.2
</version>
</dependency>
<dependency>
<groupId>
com.github.penggle
</groupId>
<artifactId>
kaptcha
</artifactId>
<version>
2.3.2
</version>
</dependency>
<!--引入ui包-->
<dependency>
<groupId>
com.github.xiaoymin
</groupId>
...
...
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