zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    Python操作Redis的实例(七)
    Python操作Redis(六)
    Redis的数据类型之set集合,zset有序集合类型操作 (五)
    Redis的数据类型之list列表类型操作 (四)
    Redis的数据类型之hash哈希类型操作 (三)
    Redis的数据类型之String字符串类型操作(二)
    Redis基础介绍以及编译安装过程(一)
    python操作IP---IPy模块
    安装cnpm报错
    vue-cli · Failed to download repo vuejs-templates/webpack: connect ECONNREF
  • 原文地址:https://www.cnblogs.com/lyh421/p/6392952.html
Copyright © 2011-2022 走看看