主要内容
环境搭建
创建一个基于servlet
的javaweb项目,然后导入所需要的依赖,具体如下图所示
其中shiro库有两个,分别是shiro-core和shiro-web,shiro-web依赖于shiro-core。
配置web.xml文件
主要是在web.xml文件中配置shiro的拦截器类,配置方式有两种
- 基于IniShiroFilter的配置,在版本1.2之前使用
- 基于EnvironmentLoaderListener的配置,在版本1.2开始使用
基于IniShiroFilter的配置
IniShiroFilter
已经被废弃,因此shiro 1.2版本开始不再建议使用。为了完整性,在这里简单列出IniShiroFilter的使用方式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <filter> <filter-name>iniShiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> </filter> <filter-mapping> <filter-name>iniShiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app> |
IniShiroFilter默认配置文件为/WEB-INF/shiro.ini
或者classpath:shiro.ini
,如果你的配置文件不是这两个的其中之一,则需要在初始化参数中显式配置。
1 2 3 4 5 6 7 8 |
<filter> <filter-name>iniShiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.IniShiroFilter</filter-class> <init-param> <param-name>configPath</param-name> <param-value>/path/to/shiro.ini</param-value> </init-param> </filter> |
基于EnvironmentLoaderListener的配置
这种配置方式和之前的差不多,但有两个差别。第一个是,我们需要在web.xml中添加一个listener,它就是EnvironmentLoaderListener
;第二个差别是使用ShiroFilter
取代IniShiroFilter,ShiroFilter
的工作前提是环境中必须加载有WebEnvironment
,EnvironmentLoaderListener的其中一个作用就是创建并注册WebEnvironment到当前上下文。
详细配置文件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <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> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app> |
这种方式的默认配置文件和第一种方式的一样,都是/WEB-INF/shiro.ini
或者classpath:shiro.ini
。如果配置文件不是两者之一才需要自行配置。
配置页面访问权限
web中的权限也是分为验证和授权,我们关注的文件如下:
上图中的类分别是org.apache.shiro.web.filter.authc包和org.apache.shiro.web.filter.authz包中的类,用于web验证和授权。我们关注的是类中定义的一些属性,这些属性用来设置页面的访问规则。
org.apache.shiro.web.filter.authc包
先看org.apache.shiro.web.filter.authc中文件的继承关系图(只列重点类)
authc包中的类主要用于登录认证,AccessControlFilter类作为一个父类,它定义了默认的登录页面:
也就是说,只要这个属性没有被自定义设置所覆盖,所有未经过验证的登录用户都被跳转到/login.jsp
进行账号验证,验证结果可以有两个:
- 验证不通过,跳回default_login_url进行验证
- 验证通过,跳转到AuthenticationFilter定义的successUrl,默认值是”/”
org.apache.shiro.web.filter.authz
接下来是org.apache.shiro.web.filter.authz包,这个包中的类用于对账号进行页面授权管理。继承关系如下图
主要关注的是AuthorzationFilter
,类中定义了unauthorizedUrl
属性,该属性的作用类似404页面设置,即一旦用户访问了未被授权的页面,会被自动跳转到unauthorizedUrl定义的页面中去。
shiro.ini文件配置
了解了前面的基础知识之后,就可以着手编写配置文件。下面是一些详细的配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
[main] ; 覆盖默认登录页面 authc.loginUrl=/login ; 用户登录成功后跳转到的页面 authc.successUrl=/success ; 没有授权的用户跳转到的错误页 roles.unauthorizedUrl=/unauthorized ; 同上,但针对的是权限验证而不是角色验证 perms.unauthorizedUrl=/unauthorized [users] jack=123,admin john=456,user:create,user:delete [roles] admin=user:*,menu:* [urls] ;登录可以匿名访问 /login=anon ; 错误页面可以匿名访问 /unauthorized=anon ;后台管理页只能具有admin的角色访问 /admin=authc,roles[admin] ;删除数据页面只能具有user:delete权限的用户访问 /delete=authc,perms["user:delete"] |
[roles]和[users]前面已经是使用过。[main]部分配置了一些跳转页面,格式是:拦截器.property=url
。[urls]部分则是主要的设置,用于分配页面的访问权限。格式是:url=拦截器[参数],拦截器[参数]。例如authc
对应FormAuthenticationFilter
拦截器,roles
对应RolesAuthorizationFilter
拦截器,anon
对应AnonymousFilter
拦截器。
url模式匹配
url除了可以写全路径外,还可以使用通配符进行url匹配,可以使用的通配符包括?
、*
和**
。
?:匹配一个字符,如/admin?匹配/admin1
*:匹配零个或多个字符串,如/admin*匹配/admin、/admin1、/admin123,但不匹配/admin/1
**:匹配路径中的零个或多个路径,如/admin**匹配/admin/a或/admin/a/b
如果模式中有多个成功被匹配,第一个匹配成功的url模式生效,其他的则被忽略。
测试验证和授权
配置文件就绪之后,就可以对这些规则进行测试验证。首先创建一个登录页面,用于提交账号信息,login.jsp文件单纯是一个登录表单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
@WebServlet(name = "loginServlet", urlPatterns = {"/login"}) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); UsernamePasswordToken token = new UsernamePasswordToken(username, password); Subject subject = SecurityUtils.getSubject(); String error = null; try { subject.login(token); } catch (AuthenticationException e) { error = "username or password invalid"; request.setAttribute("error", error); request.getRequestDispatcher("login.jsp").forward(request, response); } if (error == null) { response.sendRedirect("/admin"); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getRequestDispatcher("login.jsp").forward(request, response); } } |
如果用户登录成功,则重定向到管理页面,否则跳转到登录页面重新进行用户登录验证。
其他两种验证方式
http基本认证(Basic Authencation)和基于表单的认证。
HTTP基本认证使用的拦截器类是BaseHttpAuthenticationFilter;基于表单的认证使用的拦截器是FormAuthenticationFilter。
配置http基本认证
1 2 3 4 5 6 |
[main] ;登录框提示信息。可选 authcBasic.applicationName=请先进行登录 [urls] /admin=authcBasic,roles[admin] |
配置文件中指定/admin使用的是Basic Authencation,当用户访问/admin页面的时候,浏览器就会弹出登录认证窗口:
表单认证
表单认证和第一个例子差不多,只不过更简单。配置文件中只需要配置loginUrl、表单参数名、登录成功后跳转到哪里,以及错误信息保存在哪个key中。
重要的是,/login页面现在不再是配置为匿名访问(anon),而是使用authc(FormAuthenticationFilter),这样,登录页面才能使用FormAuthentication的功能。
1 2 3 4 5 6 7 8 9 |
[main] authc.loginUrl=/login authc.usernameParam=username authc.passwordParam=password authc.successUrl=/admin authc.failureKeyAttribute=shiroLoginFailure [urls] /login=authc /admin=authc,roles[admin] |
因为FormAuthentication已经具有登录验证的逻辑,因此我们的登录页面不需要编写这些逻辑,但是登录失败的处理代码还是需要我们自己编写的:
LoginServlet代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
@WebServlet(name = "loginServlet", urlPatterns = {"/login"}) public class LoginServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String error = (String)request.getAttribute("shiroLoginFailure"); if (error != null){ doGet(request, response); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getRequestDispatcher("login.jsp").forward(request, response); } } |
login.jsp代码:
1 2 3 4 5 6 7 8 |
<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="login" /> </form> ${shiroLoginFailure} |
如果我们是从/login页面开始的,那么登录成功后就会跳转到/admin页面。如果我们是从/admin访问被重定向到/login页面的,那么登录成功后会跳转到上一个页面(这里是/admin),而不会跳转到配置文件中的successUrl。
转载请注明:Pure nonsense » shiro集成到web(Servlet)中