【Shiro】Apache Shiro架构之集成web
Shiro系列文章:
【Shiro】Apache Shiro架构之身份认证(Authentication)
【Shiro】Apache Shiro架构之权限认证(Authorization)
【Shiro】Apache Shiro架构之自定义realm
【Shiro】Apache Shiro架构之实际运用(整合到Spring中)
前面两节内容介绍了Shiro中是如何进行身份和权限的认证,但是只是单纯的进行Shiro的验证,简单一点的话,用的是.ini配置文件,也举了个使用jdbc realm的例子,这篇博文主要来总结一下Shiro是如何集成web的,即如何用在web工程中。
写在前面:本文没有使用web框架,比如springmvc或者struts2,用的是原始的servlet,使用的是.ini配置文件,旨在简单粗暴,说明问题。后面会写一些和框架整合的博文。
本文部分参考Apache Shiro的官方文档,文档地址:http://shiro.apache.org/web.html
新建一个基于maven的web工程,整个工程结构目录如下:
下面来总结一下Shiro集成web的步骤。
1. 配置
1.1 web.xml配置
Shiro如果想要集成到web中,首先需要在web.xml中配置Shiro的监听器和过滤器,如下:
<!-- 添加shiro支持 -->
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener> <filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
<init-param>
<param-name>configPath</param-name>
<param-value>/WEB-INF/shiro.ini</param-value>
</init-param>
</filter> <filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
由上面的配置可以看出,定义Shiro配置文件的路径在/WEB-INF/shiro.ini文件,Shiro的过滤器将会拦截所有的请求。web.xml中其他配置就是servlet的映射配置了,不同的servlet对应不同的请求url,如下:
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>demo.shiro.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping> <servlet>
<servlet-name>AdminServlet</servlet-name>
<servlet-class>demo.shiro.servlet.AdminServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AdminServlet</servlet-name>
<url-pattern>/admin</url-pattern>
</servlet-mapping> <servlet>
<servlet-name>TeacherRoleServlet</servlet-name>
<servlet-class>demo.shiro.servlet.TeacherRoleServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TeacherRoleServlet</servlet-name>
<url-pattern>/student</url-pattern>
</servlet-mapping>
<servlet-mapping> <servlet>
<servlet-name>LogoutServlet</servlet-name>
<servlet-class>demo.shiro.servlet.LogoutServlet</servlet-class>
</servlet>
<servlet-name>LogoutServlet</servlet-name>
<url-pattern>/logout</url-pattern>
</servlet-mapping> <servlet>
<servlet-name>TeacherPermsServlet</servlet-name>
<servlet-class>demo.shiro.servlet.TeacherPermsServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TeacherPermsServlet</servlet-name>
<url-pattern>/teacher</url-pattern>
</servlet-mapping>
1.2 pom.xml配置
pom文件中需要引入相关的jar
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>demo.shiro</groupId>
<artifactId>ShiroWeb</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version> <dependencies> <!-- shiro核心包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.5</version>
</dependency>
<!-- 添加shiro web支持 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.5</version>
</dependency> <!-- 添加sevlet支持 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<!-- 添加jsp支持 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- 添加jstl支持 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 添加log4j日志 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>ShiroWeb</finalName>
</build>
</project>
2. Shiro的内置过滤器(Default Filters)
当运行Web应用程序时,Shiro将创建一些有用的内置过滤器实例,并且自动的在[main]部分使用。我们可以人为配置它们,就好比spring中的bean一样,并且在自己定义的url中引用它们。Shiro中内置的过滤器有以下几个:
过滤器名 | 对应的类 |
---|---|
anon(匿名) | org.apache.shiro.web.filter.authc.AnonymousFilter |
authc(身份验证) | org.apache.shiro.web.filter.authc.FormAuthenticationFilter |
authcBasic(http基本验证) | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter |
logout(退出) | org.apache.shiro.web.filter.authc.LogoutFilter |
noSessionCreation(不创建session) | org.apache.shiro.web.filter.session.NoSessionCreationFilter |
perms(许可验证) | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter |
port(端口验证) | org.apache.shiro.web.filter.authz.PortFilter |
rest(rest方面) | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter |
roles(权限验证) | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter |
ssl(ssl方面) | org.apache.shiro.web.filter.authz.SslFilter |
user(用户方面) | org.apache.shiro.web.filter.authc.UserFilter |
这些内置的过滤器使用方法是这样的,一般先指定一个请求url对应一个过滤器名,由于该过滤器对应一个类,而这个类中会有一个属性,这个属性是当验证失败的时候指定要跳转到那个url的,所以将这个属性配置成验证失败后你要请求的url即可。这里我举其中几个(匿名,身份验证,许可验证,权限验证)来说明如何使用,其他的类似。
3. Shiro的配置文件
针对上面我提到的几个验证,先把shiro.ini文件写好:
[main]
#定义身份认证失败后的请求url映射,loginUrl是身份认证过滤器中的一个属性
authc.loginUrl=/login
#定义角色认证失败后的请求url映射,unauthorizedUrl是角色认证过滤器中的一个属性
roles.unauthorizedUrl=/unauthorized.jsp
#定义角色认证失败后请求url映射,unauthorizedUrl是角色认证过滤器中的一个属性
perms.unauthorizedUrl=/unauthorized.jsp #定义几个用户和角色
[users]
csdn1=123,admin,teacher
csdn2=123,teacher
csdn3=123,student
csdn4=123 #定义不同角色的权限
[roles]
admin=user:*,student:*
teacher=student:* #定义请求的地址需要做什么验证
[urls]
#请求login的时候不需要权限,游客身份即可(anon)
/login=anon
#请求/admin的时候,需要身份认证(authc)
/admin=authc
#请求/student的时候,需要角色认证,必须是拥有teacher角色的用户才行
/student=roles[teacher]
#请求/teacher的时候,需要权限认证,必须是拥有user:create权限的角色的用户才行
/teacher=perms["user:create"]
我简单说明一下这个配置,比如[main]中定义的authc.loginUrl=/login,authc是一个内置过滤器,它对应org.apache.shiro.web.filter.authc.AnonymousFilter类,而这个类中有个loginUrl属性,表示验证失败后将要请求的url映射,这个url映射与一个具体的servlet对应,读到这里,可以和上面的servlet配置对比一下就知道了。roles.unauthorizedUrl也是一样的道理,只不过这里验证失败直接请求一个具体的jsp页面而已。
[users]中是Subject认证主体,就不再赘述了,[urls]中定义需要拦截哪些请求,并做什么验证。比如/login的url映射请求不拦截,因为是登陆的,请求/admin的url映射的话做身份认证,请求/student的url映射的话要做角色认证,且必须是teacher角色才行,请求/teacher的url映射的话需要进行权限认证,必须有user:create权限的用户才可以通过验证。
4. 测试程序
接下来一个个测试上面的这些认证。
4.1 测试authc身份认证
测试authc,得有/admin请求,加上上面的servlet配置可知,首先完成LoginServlet和AdminServlet。
//LoginServlet.java
public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("login doGet");
String username = request.getParameter("username");
String password = request.getParameter("password"); Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try {
currentUser.login(token);
System.out.println("认证成功");
request.getSession().setAttribute("username", username);
request.getRequestDispatcher("/success.jsp").forward(request, response);
} catch (AuthenticationException e) {
e.printStackTrace();
System.out.println("认证失败");
request.getRequestDispatcher("/login.jsp").forward(request, response);
}
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response);
}
}
认证成功跳转到success.jsp页面,认证失败的话就进入登录页面,让用户先登录,看一下success.jsp和login.jsp
<form action="${pageContext.request.contextPath }/login" method="post">
username:<input type="text" name="username"/><br>
password:<input type="password" name="password"/><br>
<input type="submit" value="登陆">
</form>
因为登录提交请求的是/login,而/login=anon表示匿名验证,所以不会拦截认证,直接进入LoginServlet,执行我们自己写的认证代码。下面是success.jsp,很简单。
<body>
欢迎你${username }
<a href="${pageContext.request.contextPath }/logout">退出</a>
</body>
顺带把LogoutServlet写了:
public class LogoutServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.getSession().invalidate(); //直接让session失效
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response);
} }
然后就是/admin请求了,请求的是AdminServlet.jsp,如果认证成功就会进入该servlet:
public class AdminServlet extends HttpServlet { private static final long serialVersionUID = 1L; public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("admin doGet");
request.getRequestDispatcher("/success.jsp").forward(request, response);
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response);
} }
写好了之后,开启tomcat,在浏览器中访问:http://localhost:8080/ShiroWeb/admin来请求AdminServlet.Java,Shiro根据配置(/admin=authc)会去进行身份认证,但是此时肯定是认证失败,所以根据配置(authc.loginUrl=/login)去请求LoginServlet.java,Shiro不会去验证,因为/login=anon,但是LoginServlet.java程序中会验证,我们自己写的。因为没有用户名和密码,所以认证失败,会跳转到login.jsp登陆页面,输入用户名和密码后,再次请求/login,此时再次进入LoginServlet.java,认证成功,进入success.jsp页面。
因为Shiro中会默认有30分钟缓存时间,所以此时我们再次去访问http://localhost:8080/ShiroWeb/admin的时候,就可以访问到AdminServlet.java中了,可以在里面打断点验证,然后掉转到success.jsp。这就是身份认证的过程。
4.2 测试roles角色认证
根据配置文件,我们需要请求/student才能触发roles角色认证,所以根据servlet的映射,我们完成TeacherRoleServlet.java代码。
public class TeacherRoleServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("role deget");
Subject currentUser = SecurityUtils.getSubject();
//其实是不用判断了,因为只要进来了,肯定角色是对的,否则进不来
//判断当前用户是否具有teacher角色
if(currentUser.hasRole("teacher")) {
request.getRequestDispatcher("/success.jsp").forward(request, response);
} else {
request.getRequestDispatcher("/unauthorized.jsp").forward(request, response);
}
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response);
}
}
上面程序的注释中也提到了,其实可以不用再认证了,因为进入该servlet之前,Shiro已经帮我们认证了,只有认证成功才会进入到该servlet,否则会根据配置(roles.unauthorizedUrl=/unauthorized.jsp)会直接跳转到unauthorized.jsp页面显示。
<body>
认证未通过,或者权限不足
<a href="${pageContext.request.contextPath }/logout">退出</a>
</body>
然后我们在浏览器中输入http://localhost:8080/ShiroWeb/student来请求TeacherRoleServlet,这里需要注意的是,刚刚测试过后需要点击退出,否则还是当前用户,会影响这次的测试。在测试角色认证的时候,它会先进行身份认证,再进行角色认证。也就是说,Shiro会先跳转到登陆页面让我们登陆,我们可以尝试两个不同的用户csdn1(有teacher角色)和csdn3(没有teacher角色)来测试。
4.2 测试perms权限认证
和上面一样,先写TeacherPermsServlet.java:
public class TeacherPermsServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("perms doget");
Subject currentUser = SecurityUtils.getSubject();
// 其实是不用判断了,因为只要进来了,肯定角色是对的,否则进不来
// 判断当前用户是否具有teacher角色
if (currentUser.isPermitted("user:create")) {
request.getRequestDispatcher("/success.jsp").forward(request,
response);
} else {
request.getRequestDispatcher("/unauthorized.jsp").forward(request,
response);
}
} public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException { doGet(request, response);
}
}
然后我们在浏览器中输入http://localhost:8080/ShiroWeb/teacher来请求TeacherPermsServlet ,这里同样需要注意的是,刚刚测试过后需要点击退出,否则还是当前用户,会影响这次的测试。在测试权限认证的时候,它同样会先进行身份认证,再进行权限认证。也就是说,Shiro会先跳转到登陆页面让我们登陆,我们可以尝试两个不同的用户csdn1(有admin角色,从而有user:create权限)和csdn3(没有admin角色,从而没有user:create权限)来测试。
5. url匹配方式
这里提一下Shiro在集成web的时候,url可以不用向上面那样写的很死,它可以匹配的,比如:
/admin?=authc,表示可以请求以admin开头的字符串,如xxx/adminfefe,但无法匹配多个,即xxx/admindf/admin是不行的
/admin*=authc表示可以匹配零个或者多个字符,如/admin,/admin1,/admin123,但是不能匹配/admin/abc这种
/admin/**=authc表示可以匹配零个或者多个路径,如/admin,/admin/ad/adfdf等。
/admin*/**=authc这个就不多说了,结合上面两个就知道了。
【Shiro】Apache Shiro架构之集成web的更多相关文章
- 【Shiro】Apache Shiro架构之自定义realm
[Shiro]Apache Shiro架构之身份认证(Authentication) [Shiro]Apache Shiro架构之权限认证(Authorization) [Shiro]Apache S ...
- 【Shiro】Apache Shiro架构之权限认证(Authorization)
Shiro系列文章: [Shiro]Apache Shiro架构之身份认证(Authentication) [Shiro]Apache Shiro架构之集成web [Shiro]Apache Shir ...
- 【Shiro】Apache Shiro架构之身份认证(Authentication)
Shiro系列文章: [Shiro]Apache Shiro架构之权限认证(Authorization) [Shiro]Apache Shiro架构之集成web [Shiro]Apache Shiro ...
- Apache Shiro 使用手册(一)Shiro架构介绍 - kdboy - ITeye技术网站
转载 原文地址 http://kdboy.iteye.com/blog/1154644 一.什么是Shiro Apache Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理 ...
- Apache Shiro 使用手册(一)Shiro架构介绍
一.什么是Shiro Apache Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理等功能: 认证 - 用户身份识别,常被称为用户"登录": 授权 - ...
- Apache Shiro 使用手册(一)Shiro架构介绍(转发:http://kdboy.iteye.com/blog/1154644#bc2399255)
一.什么是Shiro Apache Shiro是一个强大易用的Java安全框架,提供了认证.授权.加密和会话管理等功能: 认证 - 用户身份识别,常被称为用户“登录”: 授权 - 访问控制: 密码加密 ...
- Apache Shiro系列一,概述 —— 初识
一.什么是Shiro Apache Shiro是一个强大.灵活.开源的安全框架,它支持用户认证.权限控制.企业会话管理以及加密等. Apache Shiro的第一个也是最重要的一个目标就是易于使用和理 ...
- Apache Shiro(一)-登录认证和权限管理初识
What is Apache Shiro? Apache Shiro是一个功能强大.灵活的,开源的安全框架.它可以干净利落地处理身份验证.授权.企业会话管理和加密. Apache Shiro的首要目标 ...
- Apache Shiro和Spring Security的详细对比
参考资料: 1)Apache Shiro Apache Shiro:http://shiro.apache.org/ 在Web项目中应用 Apache Shiro:http://www.ibm.com ...
随机推荐
- [xsy2880]取石子游戏
题意:有$n$堆石子,每堆石子数量相同,以质因数分解给出,不停地从$1$到$n$依次拿石子,使得取完后石子个数为原来的因数(不能不取),当一堆只剩$1$个时结束,问在每堆石子结束的方案数 记石子个数为 ...
- 【set】【Splay】【pb_ds】bzoj1208 [HNOI2004]宠物收养所
每次来的如果是人,且宠物数不为零,就从宠物中选出一个与其差距最小的,累加答案:若为零,就把他放入另一个集合里. 如果是宠物,则同上. 各种平衡树都可过,我蛋疼地用了pb_ds. Code: #incl ...
- Redis简单入门认识
写在前面: 最近一直都在按照老大的学习路线来进行学习,这几天看了下redis,从刚开始的摸不着头脑,到后面慢慢的查资料,对其逐渐有了简单的了解,也通过一个与ssm框架整合的小demo去动手实践 了,知 ...
- 都9102年了,还不会Docker?10分钟带你从入门操作到实战上手
Docker简述 Docker是一种OS虚拟化技术,是一个开源的应用容器引擎.它可以让开发者将应用打包到一个可移植的容器中,并且该容器可以运行在几乎所有linux系统中(Windows10目前也原生支 ...
- 第一个程序-Hello world
创建HelloWorld项目 1.在Android Studio的欢迎界面点击Start a new Android Studio project 2.填写Application name(表示应用名 ...
- Linux系统/etc/sysconfig目录下没有iptables文件
在新安装的linux系统中,防火墙默认是被禁掉的,一般也没有配置过任何防火墙的策略,所有不存在/etc/sysconfig/iptables文件. 解决办法: 1.键入以下命令,新建文件 2.复制以下 ...
- TCP协议中的重传、慢启动、SACK、窗口的概念
重传机制 慢启动相关的几个状态说明该 SACK机制 窗口在TCP传输机制中的作用
- HTTPS 信任证书
使用HttpsURLConnection访问HTTPS链接时一般需要引入证书,否则会产生异常. 但是也可以使用信任所有证书的方式来达到访问的目的. 经上网查询资料发现一个很好用的类来实现信任所有证书的 ...
- 《Go语言实战》笔记之第三章 ----包
原文地址: http://www.niu12.com/article/10 ####包 所有的.go 文件,除了空行和注释,都应该在第一行声明自己所属的包. 每个包都在一个单独的目录里. 不能把多个包 ...
- metal的gpu query
https://developer.apple.com/documentation/metal/mtlcommandbuffer/1639924-gpustarttime gpuStartTime 看 ...