# 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]