原文参照:http://www.micmiu.com/opensource/security/shiro-web-captcha/
目录结构:
- 概述
- 扩展shiro认证
- 验证码工具
- 验证码servlet
- 配置文件修改
- 修改登录页面
- 测试验证
[一]、概述
本文简单讲述在web应用整合shiro后,如何实现登录验证码认证的功能。
[二]、扩展shiro的认证
创建验证码异常类:CaptchaException.java
扩展默认的用户认证的bean为:UsernamePasswordCaptchaToken.java
扩展原始默认的过滤为:FormAuthenticationCaptchaFilter.java
修改shiro认证逻辑:ShiroDbRealm.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
package
com
.
micmiu
.
framework
.
web
.
v1
.
system
.
service
;
import
java
.
io
.
Serializable
;
import
org
.
apache
.
shiro
.
SecurityUtils
;
import
org
.
apache
.
shiro
.
authc
.
AccountException
;
import
org
.
apache
.
shiro
.
authc
.
AuthenticationException
;
import
org
.
apache
.
shiro
.
authc
.
AuthenticationInfo
;
import
org
.
apache
.
shiro
.
authc
.
AuthenticationToken
;
import
org
.
apache
.
shiro
.
authc
.
SimpleAuthenticationInfo
;
import
org
.
apache
.
shiro
.
authc
.
UnknownAccountException
;
import
org
.
apache
.
shiro
.
authz
.
AuthorizationInfo
;
import
org
.
apache
.
shiro
.
authz
.
SimpleAuthorizationInfo
;
import
org
.
apache
.
shiro
.
cache
.
Cache
;
import
org
.
apache
.
shiro
.
realm
.
AuthorizingRealm
;
import
org
.
apache
.
shiro
.
subject
.
PrincipalCollection
;
import
org
.
apache
.
shiro
.
subject
.
SimplePrincipalCollection
;
import
org
.
springframework
.
beans
.
factory
.
annotation
.
Autowired
;
import
com
.
micmiu
.
framework
.
web
.
v1
.
system
.
entity
.
Role
;
import
com
.
micmiu
.
framework
.
web
.
v1
.
system
.
entity
.
User
;
import
com
.
micmiu
.
modules
.
captcha
.
CaptchaServlet
;
import
com
.
micmiu
.
modules
.
support
.
shiro
.
CaptchaException
;
import
com
.
micmiu
.
modules
.
support
.
shiro
.
UsernamePasswordCaptchaToken
;
/**
* 演示用户和权限的认证,使用默认 的SimpleCredentialsMatcher
*
* @author <a href="http://www.micmiu.com">Michael Sun</a>
*/
public
class
ShiroDbRealm
extends
AuthorizingRealm
{
private
UserService
userService
;
/**
* 认证回调函数, 登录时调用.
*/
@
Override
protected
AuthenticationInfo
doGetAuthenticationInfo
(
AuthenticationToken
authcToken
)
throws
AuthenticationException
{
UsernamePasswordCaptchaToken
token
=
(
UsernamePasswordCaptchaToken
)
authcToken
;
String
username
=
token
.
getUsername
(
)
;
if
(
username
==
null
)
{
throw
new
AccountException
(
"Null usernames are not allowed by this realm."
)
;
}
// 增加判断验证码逻辑
String
captcha
=
token
.
getCaptcha
(
)
;
String
exitCode
=
(
String
)
SecurityUtils
.
getSubject
(
)
.
getSession
(
)
.
getAttribute
(
CaptchaServlet
.
KEY_CAPTCHA
)
;
if
(
null
==
captcha
||
!
captcha
.
equalsIgnoreCase
(
exitCode
)
)
{
throw
new
CaptchaException
(
"验证码错误"
)
;
}
User
user
=
userService
.
getUserByLoginName
(
username
)
;
if
(
null
==
user
)
{
throw
new
UnknownAccountException
(
"No account found for user ["
+
username
+
"]"
)
;
}
return
new
SimpleAuthenticationInfo
(
new
ShiroUser
(
user
.
getLoginName
(
)
,
user
.
getName
(
)
)
,
user
.
getPassword
(
)
,
getName
(
)
)
;
}
/**
* 授权查询回调函数, 进行鉴权但缓存中无用户的授权信息时调用.
*/
@
Override
protected
AuthorizationInfo
doGetAuthorizationInfo
(
PrincipalCollection
principals
)
{
ShiroUser
shiroUser
=
(
ShiroUser
)
principals
.
fromRealm
(
getName
(
)
)
.
iterator
(
)
.
next
(
)
;
User
user
=
userService
.
getUserByLoginName
(
shiroUser
.
getLoginName
(
)
)
;
if
(
user
!=
null
)
{
SimpleAuthorizationInfo
info
=
new
SimpleAuthorizationInfo
(
)
;
for
(
Role
role
:
user
.
getRoleList
(
)
)
{
// 基于Permission的权限信息
info
.
addStringPermissions
(
role
.
getAuthList
(
)
)
;
}
return
info
;
}
else
{
return
null
;
}
}
/**
* 更新用户授权信息缓存.
*/
public
void
clearCachedAuthorizationInfo
(
String
principal
)
{
SimplePrincipalCollection
principals
=
new
SimplePrincipalCollection
(
principal
,
getName
(
)
)
;
clearCachedAuthorizationInfo
(
principals
)
;
}
/**
* 清除所有用户授权信息缓存.
*/
public
void
clearAllCachedAuthorizationInfo
(
)
{
Cache
&
lt
;
Object
,
AuthorizationInfo
&
gt
;
cache
=
getAuthorizationCache
(
)
;
if
(
cache
!=
null
)
{
for
(
Object
key
:
cache
.
keys
(
)
)
{
cache
.
remove
(
key
)
;
}
}
}
@
Autowired
public
void
setUserService
(
UserService
userService
)
{
this
.
userService
=
userService
;
}
/**
* 自定义Authentication对象,使得Subject除了携带用户的登录名外还可以携带更多信息.
*/
public
static
class
ShiroUser
implements
Serializable
{
private
static
final
long
serialVersionUID
=
-
1748602382963711884L
;
private
String
loginName
;
private
String
name
;
public
ShiroUser
(
String
loginName
,
String
name
)
{
this
.
loginName
=
loginName
;
this
.
name
=
name
;
}
public
String
getLoginName
(
)
{
return
loginName
;
}
/**
* 本函数输出将作为默认的<shiro:principal/>输出.
*/
@
Override
public
String
toString
(
)
{
return
loginName
;
}
public
String
getName
(
)
{
return
name
;
}
}
}
|
[三]、验证码工具类
CaptchaUtil.java
[四]、创建验证码的servlet
CaptchaServlet.java
[五]、修改配置文件
在 web.xml 中增加配置:
修改 applicationContext-shiro.xml 中的配置如下:
[六]、修改登录页面
login.jsp
[七]、验证测试
启动项目后会看到如下页面: