问题:一般情况下,我们需要先登录,然后进入到下一个页面,但如果有人知道文件名等方式,绕过登录,可直接去访问后续页面,针对这样的问题,可以使用过滤器Filter去操作,具体方案如下:
文章转载http://www.51testing.com/html/06/183306-124904.html
附Filter学习资料:http://www.cnblogs.com/xdp-gacl/p/3948353.html
(本文档内容为个人笔记作用,如有侵权之处,联系本人,我会删除!)
我们首先定义了一些可以通过URL直接访问的页面,如登陆页面,重登陆页面等。当用户没有登陆而尝试访问受保护的URL时,Filter将拦截该请求,并把访问的URL重定向到登陆页面。
在web.xml中的配置如下:
<
filter
>
<
filter
-
name
>
filterservlet
</
filter
-
name
>
<
filter
-
class
>
com
.
comtop
.
app
.
common
.
FilterServlet
</
filter
-
class
>
<
init
-
param
>
<
param
-
name
>
freePages
</
param
-
name
>
<
param
-
value
>
/
Login
.
jsp
;/
LoginAction
.
do
;/
index
.
jsp
;/
ReLogin
.
jsp
;/
SSOLoginAction
.
do
;
</
param
-
value
>
</
init
-
param
>
<
init
-
param
>
<
param
-
name
>
toPage
</
param
-
name
>
<
param
-
value
>/
ReLogin
.
jsp
</
param
-
value
>
</
init
-
param
>
</
filter
>
<
filter
-
mapping
>
<
filter
-
name
>
filterservlet
</
filter
-
name
>
<
url
-
pattern
>*.
do
</
url
-
pattern
>
</
filter
-
mapping
>
<
filter
-
mapping
>
<
filter
-
name
>
filterservlet
</
filter
-
name
>
<
url
-
pattern
>*.
jsp
</
url
-
pattern
>
</
filter
-
mapping
>
在<filter></filter>中定义一些基本信息,比如filter的名称,filter的类以及相关初始参数。这里我们把能直接访问的页面定义为freePages,并定义了它的值。还定义了默认的重定向页面,Relogin.jsp。
接着定义了filter-mapping,让后缀名为.do或.jsp的URL都被Filter所保护。
FilterServlet具体代码(import部分省略):
publicclass
FilterServlet
extends
HttpServlet
implements
Filter
{
private
FilterConfig filterConfig
;
private
String
[]
freePages
;
private
String
toPage
=
null
;
privatestatic
Loggerlogger
;
/**
*
初始化filter(这里重写父类的方法)
* @param filterConfig FilterConfig filter
配置对象
* @throws ServletException
*/
publicvoid
init
(
FilterConfigfilterConfig
)
throws
ServletException
{
logger
=
Toolkit
.
getInstance
().
getLogger
(
this
.
getClass
().
getName
());
int
i
=
0
;
String
pages
=
null
;
StringTokenizer
strTokenizer
=
null
;
if
(
logger
.
isDebugEnabled
()){
logger
.
debug
(
"initvalidate session filter "
);
}
this
.
filterConfig
=
filterConfig
;
//
以下从配置文件获取配置信息
this
.
toPage
=
filterConfig
.
getInitParameter
(
"toPage"
);
pages
=
filterConfig
.
getInitParameter
(
"freePages"
)
;
if
(
toPage
==
null
||
pages
==
null
||
toPage
.
trim
().
length
()==
0
||
pages
.
trim
().
length
()==
0
){
logger
.
error
(
"web.xml
中filterServlet没有配置初始化参数\"toPage\"或\"freePage\"."
);
thrownew
ServletException
(
"web.xml
中filterServlet没有配置初始化参数
\"toPage\"
或\"freePage\"."
);
}
if
(
logger
.
isDebugEnabled
()){
logger
.
debug
(
"toPage
:"
+
toPage
);
logger
.
debug
(
"freePages:"
+
pages
);
}
strTokenizer
=
new
StringTokenizer
(
pages
,
";"
);
this
.
freePages
=
new
String
[
strTokenizer
.
countTokens
()];
while
(
strTokenizer
.
hasMoreTokens
()){
freePages
[
i
++]=
strTokenizer
.
nextToken
();
}
if
(!
isFreePage
(
toPage
)){
logger
.
error
(
"web.xml
中filter初始化参数\"toPage\"的值必须是\"freePage\"中的某个页面."
);
thrownew
ServletException
(
"web.xml
中filter初始化参数\"toPage\"的值
必须是\"freePage\"中的某个页面."
);
}
}
/**
*
判断一个请求URI是否是不过滤的页面
* @param requestURI String
请求URI
* @return boolean
返回true为不过滤页面
*/
privateboolean
isFreePage
(
String
requestURI
){
boolean
isFree
=
false
;
for
(
int
i
=
0
;
i
<
freePages
.
length
;
i
++){
if
(
requestURI
.
endsWith
(
freePages
[
i
])){
return
true
;
}
}
return
isFree
;
}
/**
*
判断请求是否为有效Session
* @param request ServletRequest
请求对象
* @return boolean
返回true为有效Session
*/
privateboolean
isValidSession
(
ServletRequest
request
){
HttpServletRequest httpRequest
=(
HttpServletRequest
)
request
;
if
(
httpRequest
.
getSession
().
getAttribute
(
GlobalConstants
.
SECURITY_LOGIN_KEY
)
==
GlobalConstants
.
SECURITY_IS_LOGIN
){
return
true
;
}
if
(
logger
.
isDebugEnabled
()){
logger
.
debug
(
"Session
无效,请求:"
+
httpRequest
.
getRequestURI
());
}
return
false
;
}
/**
*
过滤动作
* @param request ServletRequest
请求对象
* @param response ServletResponse
响应对象
* @param filterChain FilterChain
过滤器链对象
*/
publicvoid
doFilter
(
ServletRequest
request
,
ServletResponseresponse
,
FilterChain
filterChain
){
String
requestURI
=
null
;
ActionErrors errors
=
new
ActionErrors
();
ActionError errorSession
=
null
;
HttpServletRequest httpRequest
=(
HttpServletRequest
)
request
;
HttpServletResponse httpResponse
=(
HttpServletResponse
)
response
;
requestURI
=
httpRequest
.
getRequestURI
();
if
(
logger
.
isDebugEnabled
()){
logger
.
debug
(
"Sessionfilter RequestURI:"
+
requestURI
);
}
if
(!
isFreePage
(
requestURI
)){
//
如果是保护页面
if
(!
isValidSession
(
request
)){
//
如果Session无效
String
toPageURL
=
null
;
try
{
toPageURL
=
httpRequest
.
getContextPath
()+
toPage
;
httpResponse
.
encodeRedirectURL
(
toPageURL
);
httpResponse
.
sendRedirect
(
toPageURL
);
//
转发响应
}
catch
(
IOException
ex
){
logger
.
error
(
"Sessionfilter
过滤时发生IO异常"
,
ex
);
}
}
}
if
(!
httpResponse
.
isCommitted
()){
//
如果响应未提交,交给过滤器链
try
{
filterChain
.
doFilter
(
request
,
response
);
}
catch
(
ServletExceptionsx
){
filterConfig
.
getServletContext
().
log
(
sx
.
getMessage
());
}
catch
(
IOException
iox
){
filterConfig
.
getServletContext
().
log
(
iox
.
getMessage
());
}
}
}
//
父类的方法
publicvoid
destroy
(){
}
public
FilterConfiggetFilterConfig
(){
returnthis
.
filterConfig
;
}
publicvoid
setFilterConfig
(
FilterConfigfilterConfig
){
this
.
filterConfig
=
filterConfig
;
}
}
这里isFreePage方法判断用户访问的URL是否是受保护的,从配置文件中将freePages的值得到后,以分号为隔离符将它们取出放到一个数组中,这个数组存放的每个String都是一个freePage。另外,isValidSession方法判断在session中是否存在用户的登陆信息,如果用户未登陆,则返回false。每一个filter从doFilter()方法
中得到当前的request及response,在doFilter()方法中,以下代码完成核心判断:
if
(!
isFreePage
(
requestURI
)){
//
如果是保护页面
if
(!
isValidSession
(
request
)){
//
如果Session无效
String
toPageURL
=
null
;
try
{
toPageURL
=
httpRequest
.
getContextPath
()+
toPage
;
httpResponse
.
encodeRedirectURL
(
toPageURL
);
httpResponse
.
sendRedirect
(
toPageURL
);
//
转发响应
}
catch
(
IOException
ex
){
logger
.
error
(
"Sessionfilter
过滤时发生IO异常"
,
ex
);
}
}
}
只有是通过isFreePage(requestURI)和isValidSession(request)两层验证的页面才能被访问到,基本实现了防止用户非法访问页面的情况。