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提供默认过滤器详解的主要内容,如果未能解决你的问题,请参考以下文章

Shiro 登录认证源码详解

(转) shiro权限框架详解06-shiro与web项目整合(上)

shiro异步请求返回JSON响应

Web项目Shiro总结及源码(十六)

Shiro安全框架入门篇(登录验证实例详解与源码)

Shiro的Filter机制详解---源码分析