原文參照: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<Object,
AuthorizationInfo>
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
[七]、驗證測試
啓動項目後會看到如下頁面: