2017.2.12 开涛shiro教程-第七章-与Web集成

2017.2.9 开涛shiro教程-第七章-与Web集成(一)

原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398

根据下载的pdf学习。

 

shiro提供了与Web集成的支持,通过ShiroFilter来拦截需要安全控制的URL。ShiroFilter是安全控制的入口点,负责读取配置文件,然后判断URL是否需要登录/权限工作。ShiroFilter 类似于如 Strut2/SpringMVC 这种 web 框架的前端控制器

 

1.准备环境

1.1 pom.xml

此处我们使用了 jetty-maven-plugin tomcat7-maven-plugin 插件;这样可以直接使用“mvn jetty:run ” 或 “ mvn tomcat7:run ” 运行webapp了 。 然后通过URL http://localhost:8080/chapter7/访问即可。

 1 <build>
 2         <finalName>chapter7</finalName>
 3         <plugins>
 4             <plugin>
 5                 <groupId>org.mortbay.jetty</groupId>
 6                 <artifactId>jetty-maven-plugin</artifactId>
 7                 <version>8.1.8.v20121106</version>
 8                 <configuration>
 9                     <webAppConfig>
10                         <contextPath>/${project.build.finalName}</contextPath>
11                     </webAppConfig>
12                 </configuration>
13             </plugin>
14 
15             <plugin>
16                 <groupId>org.apache.tomcat.maven</groupId>
17                 <artifactId>tomcat7-maven-plugin</artifactId>
18                 <version>2.2</version>
19                 <configuration>
20                     <path>/${project.build.finalName}</path>
21                 </configuration>
23             </plugin>
24         </plugins>
25     </build>

 

为了与web集成,加的两个依赖:

 1 <dependencies>
 2 ...
 3         <dependency>
 4             <groupId>org.apache.shiro</groupId>
 5             <artifactId>shiro-web</artifactId>
 6             <version>1.2.2</version>
 7         </dependency>
 8 
 9         <dependency>
10             <groupId>javax.servlet</groupId>
11             <artifactId>javax.servlet-api</artifactId>
12             <version>3.0.1</version>
13             <scope>provided</scope>
14         </dependency>
15 ...
16 </dependencies>

 

pom.xml文件的总览如下:

 1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 2          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 3     <parent>
 4         <artifactId>shiro-example</artifactId>
 5         <groupId>com.github.zhangkaitao</groupId>
 6         <version>1.0-SNAPSHOT</version>
 7     </parent>
 8     <modelVersion>4.0.0</modelVersion>
 9     <artifactId>shiro-example-chapter7</artifactId>
10     <packaging>war</packaging>
11     <name>shiro-example-chapter7</name>
12     <url>http://maven.apache.org</url>
13 
14 
15     <dependencies>
16         <dependency>
17             <groupId>junit</groupId>
18             <artifactId>junit</artifactId>
19             <version>4.9</version>
20             <scope>test</scope>
21         </dependency>
22         <dependency>
23             <groupId>commons-logging</groupId>
24             <artifactId>commons-logging</artifactId>
25             <version>1.1.3</version>
26         </dependency>
27         <dependency>
28             <groupId>org.apache.shiro</groupId>
29             <artifactId>shiro-core</artifactId>
30             <version>1.2.2</version>
31         </dependency>
32 
33         <dependency>
34             <groupId>org.apache.shiro</groupId>
35             <artifactId>shiro-web</artifactId>
36             <version>1.2.2</version>
37         </dependency>
38 
39 
40         <dependency>
41             <groupId>mysql</groupId>
42             <artifactId>mysql-connector-java</artifactId>
43             <version>5.1.25</version>
44         </dependency>
45         <dependency>
46             <groupId>com.alibaba</groupId>
47             <artifactId>druid</artifactId>
48             <version>0.2.23</version>
49         </dependency>
50 
51         <dependency>
52             <groupId>javax.servlet</groupId>
53             <artifactId>javax.servlet-api</artifactId>
54             <version>3.0.1</version>
55             <scope>provided</scope>
56         </dependency>
57 
58 
59     </dependencies>
60 
61     <build>
62         <finalName>chapter7</finalName>
63         <plugins>
64             <plugin>
65                 <groupId>org.mortbay.jetty</groupId>
66                 <artifactId>jetty-maven-plugin</artifactId>
67                 <version>8.1.8.v20121106</version>
68                 <configuration>
69                     <webAppConfig>
70                         <contextPath>/${project.build.finalName}</contextPath>
71                     </webAppConfig>
72                 </configuration>
73             </plugin>
74 
75             <plugin>
76                 <groupId>org.apache.tomcat.maven</groupId>
77                 <artifactId>tomcat7-maven-plugin</artifactId>
78                 <version>2.2</version>
79                 <configuration>
80                     <path>/${project.build.finalName}</path>
81                 </configuration>
82 
83             </plugin>
84         </plugins>
85 
86 
87     </build>
88 </project>
View Code

 

1.2 web.xml

前面说过,shiroFilter是入口点,所以要在web.xml中配置shiroFilter及相关参数。

(1)读取配置文件:

Shiro 1.2 开始引入了 Environment/WebEnvironment 的概念,ShiroFilter 会自动找到 Environment 然后获取相应的依赖。

 1 <web-app>
 2     <!--- shiro 1.2 -->
 3     <listener>
 4         <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
 5     </listener>
 6     <context-param>
 7         <param-name>shiroEnvironmentClass</param-name>
 8         <param-value>org.apache.shiro.web.env.IniWebEnvironment</param-value><!-- 默认先从/WEB-INF/shiro.ini,如果没有找classpath:shiro.ini -->
 9     </context-param>
10     <context-param>
11         <param-name>shiroConfigLocations</param-name>
12         <param-value>classpath:shiro.ini</param-value>
13     </context-param>
14 ...
15 </web-app>

 

(2)配置shiroFilter:

 1 <web-app>
 2 ...
 3     <filter>
 4         <filter-name>shiroFilter</filter-name>
 5         <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
 6     </filter>
 7     <filter-mapping>
 8         <filter-name>shiroFilter</filter-name>
 9         <url-pattern>/*</url-pattern>
10     </filter-mapping>
11 </web-app>

 

web.xml文件的总览:即配置文件的读取及拦截设置。

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app
 3         xmlns="http://java.sun.com/xml/ns/javaee"
 4         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 5         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
 6         version="3.0"
 7         metadata-complete="false">
 8     <!--- shiro 1.2 -->
 9     <listener>
10         <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
11     </listener>
12     <context-param>
13         <param-name>shiroEnvironmentClass</param-name>
14         <param-value>org.apache.shiro.web.env.IniWebEnvironment</param-value><!-- 默认先从/WEB-INF/shiro.ini,如果没有找classpath:shiro.ini -->
15     </context-param>
16     <context-param>
17         <param-name>shiroConfigLocations</param-name>
18         <param-value>classpath:shiro.ini</param-value>
19     </context-param>
20     <filter>
21         <filter-name>shiroFilter</filter-name>
22         <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
23     </filter>
24     <filter-mapping>
25         <filter-name>shiroFilter</filter-name>
26         <url-pattern>/*</url-pattern>
27     </filter-mapping>
28 
29     <!--<error-page>-->
30         <!--<error-code>401</error-code>-->
31         <!--<location>/WEB-INF/jsp/unauthorized.jsp</location>-->
32     <!--</error-page>-->
33 
34 </web-app>
View Code

 

这是我的项目中提供的配置:已经与spring集成了。具体的不再说,第十二章详细说明。

 1 <web-app>
 2     <listener>
 3         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 4     </listener>
 5     <filter>
 6         <filter-name>shiroFilter</filter-name>
 7         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
 8         <init-param>
 9             <param-name>targetFilterLifecycle</param-name>
10             <param-value>true</param-value>
11         </init-param>
12     </filter>
13     <filter-mapping>
14         <filter-name>shiroFilter</filter-name>
15         <url-pattern>/*</url-pattern>
16     </filter-mapping>
17 </web-app>

 

1.3 ini文件的配置

比之前的ini文件多出来的部分是url的配置。

 1 ...
 2 [main]
 3 #默认是/login.jsp
 4 authc.loginUrl=/login
 5 roles.unauthorizedUrl=/unauthorized
 6 perms.unauthorizedUrl=/unauthorized
 7 
 8 [users]
 9 zhang=123,admin
10 wang=123
11 
12 [roles]
13 admin=user:*,menu:*
14 
15 [urls]
16 /login=anon
17 /unauthorized=anon
18 /static/**=anon
19 /authenticated=authc
20 /role=authc,roles[admin]
21 /permission=authc,perms["user:create"]

 

最重要的就是urls部分的参数。格式为:url=拦截器[参数],拦截器[参数]

anon表示可以匿名访问(不需要登录也可访问),authc表示身份认证通过就可以访问,roles[admin]表示有admin角色才可以访问,perms:["user:create"]表示需要有user的create权限才可以访问。

1 [urls]
2 /login=anon
3 /unauthorized=anon
4 /static/**=anon
5 /authenticated=authc
6 /role=authc,roles[admin]
7 /permission=authc,perms["user:create"]
View Code

 

2.身份验证

2.1 配置需要身份验证的url

访问这些地址(authc)的时候会判断用户有没有登录,即如果没有登录会跳转到登录页面,默认为/login.jsp,也可以自己自定义配置。

1 /authenticated=authc
2 /role=authc,roles[admin]
3 /permission=authc,perms["user:create"]
4 
5 authc.loginUrl=/login

 

2.2 LoginServlet

 1 import org.apache.shiro.SecurityUtils;
 2 import org.apache.shiro.authc.AuthenticationException;
 3 import org.apache.shiro.authc.IncorrectCredentialsException;
 4 import org.apache.shiro.authc.UnknownAccountException;
 5 import org.apache.shiro.authc.UsernamePasswordToken;
 6 import org.apache.shiro.subject.Subject;
 7 
 8 import javax.servlet.ServletException;
 9 import javax.servlet.annotation.WebServlet;
10 import javax.servlet.http.HttpServlet;
11 import javax.servlet.http.HttpServletRequest;
12 import javax.servlet.http.HttpServletResponse;
13 import java.io.IOException;
14 
15 @WebServlet(name = "loginServlet", urlPatterns = "/login")
16 public class LoginServlet extends HttpServlet {
17 
18     @Override
19     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
20         req.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(req, resp);
21     }
22 
23     @Override
24     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
25         String error = null;
26         String username = req.getParameter("username");
27         String password = req.getParameter("password");
28         Subject subject = SecurityUtils.getSubject();
29         UsernamePasswordToken token = new UsernamePasswordToken(username, password);
30         token.setRememberMe(true);
31         try {
32             subject.login(token);
33         } catch (UnknownAccountException e) {
34             error = "用户名/密码错误";
35         } catch (IncorrectCredentialsException e) {
36             error = "用户名/密码错误";
37         } catch (AuthenticationException e) {
38             //其他错误,比如锁定,如果想单独处理请单独catch处理
39             error = "其他错误:" + e.getMessage();
40         }
41 
42         if(error != null) {//出错了,返回登录页面
43             req.setAttribute("error", error);
44             req.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(req, resp);
45         } else {//登录成功
46             req.getRequestDispatcher("/WEB-INF/jsp/loginSuccess.jsp").forward(req, resp);
47         }
48     }
49 }

 

2.3 测试

输入http://localhost:8080/chapter7/login 访问登录页面。

输入账号密码,登录成功后可以接着访问路径:http://localhost:8080/chapter7/authenticated

 

3 基于Basic与基于表单的拦截器身份验证

Shiro 内置了登录(身份验证)的实现:基于表单的和基于 Basic 的验证,其通过拦截器实现。

3.1 基于Basic的拦截器身份验证

(1)basicfilterlogin.ini文件

1 [main]
2 authcBasic.applicationName=please login
3 ………省略 users
4 [urls]
5 /role=authcBasic,roles[admin]

 

authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter 类型的实例,其用于实现基于 Basic 的身份验证;applicationName 用于弹出的登录框显示信息使用,如图:

 

[urls]部分配置了/role 地址需要走 authcBasic 拦截器,即如果访问/role 时还没有通过身份验证那么将弹出如上图的对话框进行登录,登录成功即可访问。

 

(2)web.xml

将web.xml中shiro的配置文件地址shiroConfigLocations 改为 shiro-basicfilterlogin.ini 即可。

(3)测试

输入http://localhost:8080/chapter7/role,弹出basic验证对话框,输入账号密码,即可访问/role。

3.2 基于表单的拦截器身份验证

(1)shiro-formfilterlogin.ini

authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter 类型的实例,其用于实现基于表单的身份验证;

注意,successUrl指定登录成功后重定向的默认地址(默认是“/”)(如果有上一个地址会自动重定向带该地址);

1 [main]
2 authc.loginUrl=/formfilterlogin
3 authc.usernameParam=username
4 authc.passwordParam=password
5 authc.successUrl=/
6 authc.failureKeyAttribute=shiroLoginFailure
7 [urls]
8 /role=authc,roles[admin]

 

(2)web.xml

将web.xml中shiro的配置文件地址shiroConfigLocations 改为 shiro-formfilterlogin .ini 即可。

 

(3)loginServlet

1 @WebServlet(name = "formFilterLoginServlet", urlPatterns = "/formfilterlogin")
2 public class FormFilterLoginServlet extends HttpServlet {
3 ...
4 }

 

(4)测试

输入http://localhost:8080/chapter7/role,页面跳转到/formfilterlogin,输入账户密码后,重定向到之前的/role。
输入http://localhost:8080/chapter7/formfilterlogin,将跳转到默认的successUrl。

 

4.授权(角色/权限验证)

(1)shiro.ini

unauthorizedUrl 属性,用于指定授权失败时的跳转地址。

roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter 类型的实例 Perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter 类型的实例。

如果使用多个角色,使用,分隔,比如role[admin,user],且使用的是hasAllRole验证。

/role和/permission是拦截器路径。

1 [main]
2 roles.unauthorizedUrl=/unauthorized
3 perms.unauthorizedUrl=/unauthorized
4 [urls]
5 /role=authc,roles[admin]
6 /permission=authc,perms["user:create"]

 

(2)web.xml

shiroConfigLocations 改为 shiro.ini 即可。

 

(3)RoleServlet/PermissionServlet

 1 @WebServlet(name = "roleServlet", urlPatterns = "/role")
 2 public class RoleServlet extends HttpServlet {
 3 
 4     @Override
 5     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 6         Subject subject = SecurityUtils.getSubject();
 7         subject.checkRole("admin");
 8         req.getRequestDispatcher("/WEB-INF/jsp/hasRole.jsp").forward(req, resp);
 9     }
10 }
 1 @WebServlet(name = "permissionServlet", urlPatterns = "/permission")
 2 public class PermissionServlet extends HttpServlet {
 3 
 4     @Override
 5     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 6         Subject subject = SecurityUtils.getSubject();
 7         subject.checkPermission("user:create");
 8         req.getRequestDispatcher("/WEB-INF/jsp/hasPermission.jsp").forward(req, resp);
 9     }
10 }

 

(4)测试

输入http://localhost:8080/chapter7/login,输入zhang/123(能成功验证)登录,再访问/role或/permission时,能跳转到对应页面。
输入http://localhost:8080/chapter7/login,输入li/123(不能成功验证)登录,再访问/role或/permission时,跳转到/unauthorized。

 

5 退出

(1)shiro.ini

登录使用anon(不需登录即可访问)即可。

1 [urls]
2 /logout=anon

 

(2)web.xml

同样web.xml中shiro的配置文件改成对应的。

 

(3)LogoutServlet.xml

1 @WebServlet(name = "logoutServlet", urlPatterns = "/logout")
2 public class LogoutServlet extends HttpServlet {
3 
4     @Override
5     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
6         SecurityUtils.getSubject().logout();
7         req.getRequestDispatcher("/WEB-INF/jsp/logoutSuccess.jsp").forward(req, resp);
8     }
9 }

 

(4)测试

输入http://localhost:8080/chapter7/login,使用帐号“zhang/123”进行登录,登录成功后访问/logout 即可退出。

 

(5)shiro提供的logout

配置如下:logout是org.apache.shiro.web.filter.authc.LogoutFilter 类型的实例。
这样配置后,当访问/logout2时,会重定向到/login页面。

1 [main]
2 logout.redirectUrl=/login
3 [urls]
4 /logout2=logout

 

posted @ 2017-02-13 11:08  七月流火嗞嗞嗞  阅读(1049)  评论(0编辑  收藏  举报