Shiro源码——shiro提供默认过滤器详解
Posted 敲代码的小小酥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Shiro源码——shiro提供默认过滤器详解相关的知识,希望对你有一定的参考价值。
shiro为了实现权限、认证功能,定义了多个过滤器,下面对每个过滤器的作用进行了解。
一、AnonymousFilter过滤器
允许在不执行任何类型的安全检查的情况下立即访问路径的筛选器。
也就是我们配置的类似:/user/signup/** = anon 的权限,会走这个过滤器。该过滤器只定义了一个方法,直接返回true,进行放行。
@Override
protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue)
// Always return true since we allow access to anyone
return true;
二、FormAuthenticationFilter过滤器
要求请求用户通过身份验证才能继续请求,如果未通过身份验证,则通过将用户重定向到您配置的loginUrl,强制用户通过登录。
这个过滤器用username,password和remeberme构造出一个Token对象,然后自动调用subject的login(token)方法尝试登陆。需要注意的是尝试登陆操作只有在isLoginSubmission(request,response)方法返回true,且request是post时发生。
可见,shiro为我们提供好了登陆过滤器,没有登陆而访问资源,会自动跳转到登陆页面。这就是使用框架的好处,自动有了跳转登录的功能,如果不用权限管理框架,那么这个过滤器就需要我们自己写。
下面分析一下这个过滤器的重点方法:
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception
if (isLoginRequest(request, response)) //请求路径是登陆路径
if (isLoginSubmission(request, response)) //请求方式是否满足要求,默认是post请求
if (log.isTraceEnabled())
log.trace("Login submission detected. Attempting to execute login.");
return executeLogin(request, response);//执行登陆操作,登陆成功,返回true
else
if (log.isTraceEnabled())
log.trace("Login page view.");
//allow them to see the login page ;)
return true;//否则直接返回true
else //如果请求不是登陆请求
if (log.isTraceEnabled())
log.trace("Attempting to access a path which requires authentication. Forwarding to the " +
"Authentication url [" + getLoginUrl() + "]");
saveRequestAndRedirectToLogin(request, response);//跳转到登陆页面
return false;
可以看到,这个方法就是如果是登陆请求,则放行,如果不是登陆请求,则跳转到登陆页面。说明,这个方法,一定是在已经判断出用户还没有登陆时,才会调用的,因为如果不是登陆请求,它会直接跳转到登陆页面,所以说,这个方法肯定是在其他方法判断出没有登陆后,才走的,至于在哪调用的,我们后面分析。
三、LogoutFilter过滤器
拦截退出请求,并重定向到退出后的路径。核心方法如下:
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception
Subject subject = getSubject(request, response);
// Check if POST only logout is enabled
if (isPostOnlyLogout())
// check if the current request's method is a POST, if not redirect
if (!WebUtils.toHttp(request).getMethod().toUpperCase(Locale.ENGLISH).equals("POST"))
return onLogoutRequestNotAPost(request, response);
String redirectUrl = getRedirectUrl(request, response, subject);
//try/catch added for SHIRO-298:
try
subject.logout();//先执行退出方法
catch (SessionException ise)
log.debug("Encountered session exception during logout. This can generally safely be ignored.", ise);
issueRedirect(request, response, redirectUrl);//设置重定向路径
return false;//返回flase,不放行
可见,该过滤器就是执行退出操作,然后重定向的。这也省去了我们自己定义方法的操作。这个过滤器在哪里配置使用,我们后面讲。
四、PermissionsAuthorizationFilter过滤器
该过滤器是判断用户是否有权限访问资源,核心代码如下:
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException
Subject subject = getSubject(request, response);
String[] perms = (String[]) mappedValue;
boolean isPermitted = true;
if (perms != null && perms.length > 0)
if (perms.length == 1)
if (!subject.isPermitted(perms[0]))
isPermitted = false;
else
if (!subject.isPermittedAll(perms))
isPermitted = false;
return isPermitted;
五、PortFilter过滤器
要求请求位于特定端口上的筛选器,如果不是,则重定向到该端口上的同一URL。这个过滤器在一定场景下还是很有用的。
六、RolesAuthorizationFilter过滤器
和PermissionsAuthorizationFilter过滤器类似,这个是过滤请求的用户有没有某个角色。
七、UserFilter过滤器
如果访问者是已知用户(定义为具有已知主体),则允许访问资源的筛选器。这意味着通过“记住我”功能进行身份验证或记住的任何用户都将被允许从此筛选器访问。
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
if (isLoginRequest(request, response))
return true;
else
Subject subject = getSubject(request, response);
// If principal is not null, then the user is known and should be allowed access.
return subject.getPrincipal() != null;
/**
* This default implementation simply calls
* @link #saveRequestAndRedirectToLogin(javax.servlet.ServletRequest, javax.servlet.ServletResponse) saveRequestAndRedirectToLogin
* and then immediately returns <code>false</code>, thereby preventing the chain from continuing so the redirect may
* execute.
*/
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception
saveRequestAndRedirectToLogin(request, response);
return false;
这个我们在研究记住我功能时再说。
总结
上面分析了这么多过滤器,那到底啥时候用呢,我们在shiro的配置文件中,定义哪些路径,被哪些过滤器过滤,如下:
filterChainDefinitionMap.put("/favicon.ico**", "anon");
filterChainDefinitionMap.put("/css/**", "anon");
filterChainDefinitionMap.put("/docs/**", "anon");
filterChainDefinitionMap.put("/fonts/**", "anon");
filterChainDefinitionMap.put("/img/**", "anon");
filterChainDefinitionMap.put("/ajax/**", "anon");
filterChainDefinitionMap.put("/js/**", "anon");
filterChainDefinitionMap.put("/druid/**", "anon");
//filterChainDefinitionMap.put("/score/**", "anon");
filterChainDefinitionMap.put("/base/**", "anon");
filterChainDefinitionMap.put("/captcha/captchaImage**", "anon");
filterChainDefinitionMap.put("/app/api/**", "anon");
// 退出 logout地址,shiro去清除session
filterChainDefinitionMap.put("/logout", "logout");
// 不需要拦截的访问
filterChainDefinitionMap.put("/login", "anon,captchaValidate");
这样,就将请求和过滤器绑定了起来。
以上是关于Shiro源码——shiro提供默认过滤器详解的主要内容,如果未能解决你的问题,请参考以下文章