# learn-web-shiro **Repository Path**: gapper/learn-web-shiro ## Basic Information - **Project Name**: learn-web-shiro - **Description**: 演示servlet环境如何集成shiro - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-12-24 - **Last Updated**: 2021-12-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 1. 在servlet容器(比如tomcat、jetty、weblogic)启动时,监听器、过滤器的执行顺序 ServletContextListener监听器会先被实例化,在执行初始化方法先执行,然后过滤器在实例化, 再执行过滤器的init方法。 2. shiro通过ShiroFilter与Web集成,这个ShiroFilter具备以下功能 a. 拦截需要认证或授权才能进行访问的URL b. 拦截到URL后,进行认证和授权。 c. 读取配置文件(如ini配置文件) 思考:SpringMVC如何接管web应用的? 靠DispatcherServlet。 struts2如何接管web应用的? 靠Struts2Filter 其他各种框架,如何要与web环境集成,则要么是通过Servlet、要么是通过Filter为切入点来集成的 这是规律! shiro框架要集成到web环境中,就是通过一个过滤器! 就是:ShiroFilter 3. 准备环境 a. 需要创建一个web应用 b. 依赖: servlet-api shiro-all commons-logging 4. shiro与web集成 a. 配置EnvironmentLoaderListener监听器,该监听器会创建WebEnvironment的实现类的对象, 并存放到ServletContext范围中(application范围) 通过查看WebEnvironment接口的源码,不难发现,WebEnvironment接口对外暴露的功能有: 1)提供WebSecurityManager(说明WebEnvironment的实现类,必须创建WebSecurityManager并将其封装起来) 2)提供FilterChainResolver(说明WebEnvironment的实现类,必须创建FilterChainResolver并将其封装起来) org.apache.shiro.web.env.EnvironmentLoaderListener b. 告诉EnvironmentLoaderListener监听器shiro.ini配置文件的位置(默认值是"/WEB-INF/shiro.ini") shiroConfigLocations classpath:shiro.ini c. 配置ShiroFilter, ShiroFilter会从ServletContext中取出WebEnvironment的实现类,并从WebEnvironment的实现类中取出SecurityManager 再将SecurityManager设置到SecurityUtils中。(通过查看ShiroFilter源码中的init方法,可以很容易地确定这一点) shiroFilter org.apache.shiro.web.servlet.ShiroFilter shiroFilter /* d. web ini配置 [main] authc.loginUrl=/login.do roles.unauthorizedUrl=/unauthorized.do perms.unauthorizedUrl=/unauthorized.do [users] gao=123,admin zhang=123 [roles] admin=user:*,menu:* [urls] /login.do=anon /unauthorized.do=anon /static/**=anon /authenticated.do=authc /role.do=authc,roles[admin] /permission.do=authc,perms["user:create"] 其中最重要的就是[urls]部分的配置,其格式是"url=拦截器[参数], 拦截器[参数]" 拦截器说明: anon表示可匿名访问,即无需通过认证就能访问 authc表示需要身份认证通过后才能访问 roles[admin]表示需要有admin角色才能访问 perms["user:create"]表示需要有"user:create"权限才能访问 url模式使用Ant风格,Ant路径通配符支持?、*、** ? 匹配一个任意字符 比如:/admin?匹配/admin1, 但不匹配/admin或/admin12 * 匹配0到多个任意字符 比如:/admin*匹配/admin12,但不匹配/admin/1 **匹配路径中的零个或多个路径 比如:/admin/**匹配/admin/a或/admin/a/b url模式匹配顺序:使用第一个匹配的url模式对应的拦截器链 /bb/**=filter1 /bb/aa=filter2 /**=filter3 如果请求的url是"/bb/aa", 最终匹配到的拦截器是filter1 e. 注意,如果url没有与某个权限或者角色绑定,那就是公共资源,谁都可以访问 5. Shiro通过ProxiedFilterChain对Servlet容器的FilterChain进行了代理 1) 即先走Shiro自己的Filter体系,然后才会委托给Servlet容器的FilterChain进行Servlet容器级别的Filter链执行 a. 先执行Shiro自己的Filter链 b. 再执行Servlet容器的Filter链 2) Shiro自己的ProxiedFilterChain是同通过FilterChainResolver生成的,下面是FilterChainResolver的源码, 不难看出originalChain就是Servlet原始的过滤器链 public interface FilterChainResolver { FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain); } FilterChainResolver有一个默认实现: PathMatchingFilterChainResolver 该实现恰恰就是根据[urls]中配置的url模式是否与请求的url匹配来生成shiro自己的过滤器链的 比如:/abc.do=authc,roles["admin"], 如果客户端浏览器请求的URL恰是/abc.do,则ProxiedFilterChain中就会有2个过滤器,分别是: authc、roles 3) 自定义shiro过滤器 a. 创建一个类,继承AccessControlFilter(抽象类) b. 实现isAccessAllowed方法和onAccessDenied方法。 isAccessAllowed用于控制是否允许用户访问,返回true表示允许且放行到过滤器链上的下一个过滤器,返回false表示不允许用户访问 onAccessDenied表示当用户的访问被拒绝时,是否自己处理,如果返回true表示自己不处理且放行到过滤器链上的下一个过滤器,返回false表示自己已经处理了(比如重定向到另一个页面) // 自定义一个shiro过滤器,如果用户拥有指定的任何一个角色就放行,否则跳转到登录界面 public class HasAnyRoleFilter extends AccessControlFilter { @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { HttpServletRequest req = WebUtils.toHttp(request); String[] roles = (String[]) mappedValue; // 获取当前登录用户 Subject subject = getSubject(request, response); for (String role : roles) { if(subject.hasRole(role)) { return true; } } return false; } @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { System.out.println("BBBB"); setLoginUrl("/login.do"); redirectToLogin(request, response); return false; } } 自定义shiro过滤器完成以后,还需要在shiro.ini中配置一下: [filters] any=xian.woniuxy.filter.HasAnyRoleFilter [urls] /users.jsp=authc,any[admin,guest]