设为首页 收藏本站
查看: 1170|回复: 0

[经验分享] Apache Shiro学习笔记(六)FilterChain

[复制链接]

尚未签到

发表于 2018-11-19 12:23:23 | 显示全部楼层 |阅读模式
鲁春利的工作笔记,好记性不如烂笔头
  

  Apache Shiro学习笔记(七)IniWebEnvironment
  

  Shiro FilterChain

  Shiro 对Servlet 容器的FilterChain 进行了代理,即ShiroFilter 在继续Servlet 容器的Filter链的执行之前,通过ProxiedFilterChain 对Servlet 容器的FilterChain 进行了代理;即先走Shiro 自己的Filter 体系,然后才会委托给Servlet 容器的FilterChain 进行Servlet 容器级别的Filter链执行;Shiro的ProxiedFilterChain执行流程:
  1、先执行Shiro自己的Filter链;
  2、再执行Servlet容器的Filter链(即原始的Filter)。
  

  ProxiedFilterChain 是通过FilterChainResolver 根据配置文件中[urls]部分是否与请求的URL是否匹配解析得到的。

  •   FilterChainResolver
package org.apache.shiro.web.filter.mgt;
public interface FilterChainResolver {
    FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain);
}  Shiro 内部提供了一个路径匹配的FilterChainResolver 实现:PathMatchingFilterChainResolver:
  其根据[urls]中配置的url 模式(默认Ant 风格)= 拦截器链和请求的url是否匹配来解析得到配置的拦截器链的;而PathMatchingFilterChainResolver内部通过FilterChainManager维护着拦截器链,比如DefaultFilterChainManager实现维护着url 模式与拦截器链的关系。因此我们可以通过FilterChainManager 进行动态动态增加url模式与拦截器链的关系。

  •   PathMatchingFilterChainResolver
package org.apache.shiro.web.filter.mgt;
public class PathMatchingFilterChainResolver implements FilterChainResolver {
    private FilterChainManager filterChainManager;
    private PatternMatcher pathMatcher;
    public PathMatchingFilterChainResolver() {
        this.pathMatcher = new AntPathMatcher();
        this.filterChainManager = new DefaultFilterChainManager();
    }
    public PathMatchingFilterChainResolver(FilterConfig filterConfig) {
        this.pathMatcher = new AntPathMatcher();
        this.filterChainManager = new DefaultFilterChainManager(filterConfig);
    }
    public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
        FilterChainManager filterChainManager = getFilterChainManager();
        if (!filterChainManager.hasChains()) {
            return null;
        }
        String requestURI = getPathWithinApplication(request);
        //the 'chain names' in this implementation are actually path patterns defined by the user.  We just use them
        //as the chain name for the FilterChainManager's requirements
        for (String pathPattern : filterChainManager.getChainNames()) {
            // If the path does match, then pass on to the subclass implementation for specific checks:
            if (pathMatches(pathPattern, requestURI)) {
                if (log.isTraceEnabled()) {
                    log.trace("Matched path pattern [" + pathPattern + "] for requestURI [" + requestURI + "].  " +
                            "Utilizing corresponding filter chain...");
                }
                return filterChainManager.proxy(originalChain, pathPattern);
            }
        }
        return null;
    }
}

  •   DefaultFilterChainManager

package org.apache.shiro.web.filter.mgt;
public class DefaultFilterChainManager implements FilterChainManager {
    private FilterConfig filterConfig;
    private Map filters; //pool of filters available for creating chains
    private Map filterChains; //key: chain name, value: chain
    public DefaultFilterChainManager() {
        this.filters = new LinkedHashMap();
        this.filterChains = new LinkedHashMap();
        addDefaultFilters(false);
    }
    public DefaultFilterChainManager(FilterConfig filterConfig) {
        this.filters = new LinkedHashMap();
        this.filterChains = new LinkedHashMap();
        setFilterConfig(filterConfig);
        addDefaultFilters(true);
    }
    protected void addDefaultFilters(boolean init) {
        for (DefaultFilter defaultFilter : DefaultFilter.values()) {
            addFilter(defaultFilter.name(), defaultFilter.newInstance(), init, false);
        }
    }
}  DefaultFilterChainManager 会默认添加org.apache.shiro.web.filter.mgt.DefaultFilter 中声明的
拦截器。

  •   DefaultFilter
public enum DefaultFilter {
    anon(AnonymousFilter.class),
    authc(FormAuthenticationFilter.class),
    authcBasic(BasicHttpAuthenticationFilter.class),
    logout(LogoutFilter.class),
    noSessionCreation(NoSessionCreationFilter.class),
    perms(PermissionsAuthorizationFilter.class),
    port(PortFilter.class),
    rest(HttpMethodPermissionFilter.class),
    roles(RolesAuthorizationFilter.class),
    ssl(SslFilter.class),
    user(UserFilter.class);
    // 代码略
}  

  如果要注册自定义拦截器,IniSecurityManagerFactory/WebIniSecurityManagerFactory在启动时会自动扫描ini 配置文件中的[filters]/[main]部分并注册这些拦截器到DefaultFilterChainManager;且创建相应的url 模式与其拦截器关系链。
  

  如果想自定义FilterChainResolver,可以通过实现WebEnvironment接口完成:
package org.apache.shiro.web.env;
public class IniWebEnvironment extends ResourceBasedWebEnvironment implements Initializable, Destroyable {
    protected FilterChainResolver createFilterChainResolver() {
        FilterChainResolver resolver = null;
        Ini ini = getIni();
        if (!CollectionUtils.isEmpty(ini)) {
            //only create a resolver if the 'filters' or 'urls' sections are defined:
            Ini.Section urls = ini.getSection(IniFilterChainResolverFactory.URLS);
            Ini.Section filters = ini.getSection(IniFilterChainResolverFactory.FILTERS);
            if (!CollectionUtils.isEmpty(urls) || !CollectionUtils.isEmpty(filters)) {
                //either the urls section or the filters section was defined.  Go ahead and create the resolver:
                IniFilterChainResolverFactory factory = new IniFilterChainResolverFactory(ini, this.objects);
                resolver = factory.getInstance();
            }
        }
        return resolver;
    }
}  


  •   MyIniWebEnvironment

public class MyIniWebEnvironment extends IniWebEnvironment {
    @Override
    protected FilterChainResolver createFilterChainResolver() {
        //在此处扩展自己的FilterChainResolver
        return super.createFilterChainResolver();
    }
}  如果覆盖了IniWebEnvironment 默认的FilterChainResolver,需要自己来解析请求与FilterChain 之间的关系。如果想动态实现url-拦截器的注册,就可以通过实现此处的FilterChainResolver来完成,比如:
//1、创建FilterChainResolver
    PathMatchingFilterChainResolver filterChainResolver = new PathMatchingFilterChainResolver();
//2、创建FilterChainManager
    DefaultFilterChainManager filterChainManager = new DefaultFilterChainManager();
//3、注册Filter
    for(DefaultFilter filter : DefaultFilter.values()) {
        filterChainManager.addFilter(filter.name(), (Filter) ClassUtils.newInstance(filter.getFilterClass()));
    }
//4、注册URL-Filter的映射关系
    filterChainManager.addToChain("/login.jsp", "authc");
    filterChainManager.addToChain("/unauthorized.jsp", "anon");
    filterChainManager.addToChain("/**", "authc");
    filterChainManager.addToChain("/**", "roles", "admin");
//5、设置Filter的属性
    FormAuthenticationFilter authcFilter = (FormAuthenticationFilter)filterChainManager.getFilter("authc");
    authcFilter.setLoginUrl("/login.jsp");
    RolesAuthorizationFilter rolesFilter = (RolesAuthorizationFilter)filterChainManager.getFilter("roles");
    rolesFilter.setUnauthorizedUrl("/unauthorized.jsp");
    filterChainResolver.setFilterChainManager(filterChainManager);
    return filterChainResolver;  此处自己去实现注册filter,及url 模式与filter 之间的映射关系。可以通过定制FilterChainResolver或FilterChainManager来完成诸如动态URL匹配的实现。
  

  

  然后再web.xml中进行如下配置Environment:

    shiroEnvironmentClass
    com.github.zhangkaitao.shiro.chapter8.web.env.MyIniWebEnvironment
  

  自定义拦截器
package com.invicme.apps.shiro.filter;
import java.io.IOException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.web.filter.PathMatchingFilter;
import org.apache.shiro.web.util.WebUtils;
/**
*
* @author lucl
* 自定义表单拦截器
*
*/
public class FormLoginFilter extends PathMatchingFilter {
    private String loginUrl = "/login.jsp";
    private String successUrl = "/";
    @Override
    protected boolean onPreHandle(ServletRequest request,
            ServletResponse response, Object mappedValue) throws Exception {
        if (SecurityUtils.getSubject().isAuthenticated()) {
            return true;// 已经登录过
        }
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse resp = (HttpServletResponse) response;
        if (isLoginRequest(req)) {
            if ("post".equalsIgnoreCase(req.getMethod())) {// form表单提交
                boolean loginSuccess = login(req); // 登录
                if (loginSuccess) {
                    return redirectToSuccessUrl(req, resp);
                }
            }
            return true;// 继续过滤器链
        } else {// 保存当前地址并重定向到登录界面
            saveRequestAndRedirectToLogin(req, resp);
            return false;
        }
    }
    private boolean redirectToSuccessUrl(HttpServletRequest req,
            HttpServletResponse resp) throws IOException {
        WebUtils.redirectToSavedRequest(req, resp, successUrl);
        return false;
    }
    private void saveRequestAndRedirectToLogin(HttpServletRequest req,
            HttpServletResponse resp) throws IOException {
        WebUtils.saveRequest(req);
        WebUtils.issueRedirect(req, resp, loginUrl);
    }
    private boolean login(HttpServletRequest req) {
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        try {
            SecurityUtils.getSubject().login(
                    new UsernamePasswordToken(username, password));
        } catch (Exception e) {
            req.setAttribute("shiroLoginFailure", e.getClass());
            return false;
        }
        return true;
    }
    private boolean isLoginRequest(HttpServletRequest req) {
        return pathsMatch(loginUrl, WebUtils.getPathWithinApplication(req));
    }
}  onPreHandle主要流程:
DSC0000.jpg

  shiro.ini配置

[filters]
formLogin=com.invicme.apps.shiro.filter.FormLoginFilter
[urls]
/test.jsp=formLogin
/login.jsp=formLogin  

  默认拦截器
  Shiro 内置了很多默认的拦截器,比如身份验证、授权等相关的。默认拦截器可以参考org.apache.shiro.web.filter.mgt.DefaultFilter中的枚举拦截器:
DSC0001.jpg

DSC0002.jpg

DSC0003.jpg

  





运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-637002-1-1.html 上篇帖子: 在Redhat安装部署Apache+MySQL+PHP(LAMP) 下篇帖子: (二)apache之httpd
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表