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/访问即可。
<build>
<finalName>chapter7</finalName>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.8.v20121106</version>
<configuration>
<webAppConfig>
<contextPath>/${project.build.finalName}</contextPath>
</webAppConfig>
</configuration>
</plugin> <plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/${project.build.finalName}</path>
</configuration>
</plugin>
</plugins>
</build>
为了与web集成,加的两个依赖:
<dependencies>
...
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.2</version>
</dependency> <dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
...
</dependencies>
pom.xml文件的总览如下:
<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">
<parent>
<artifactId>shiro-example</artifactId>
<groupId>com.github.zhangkaitao</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>shiro-example-chapter7</artifactId>
<packaging>war</packaging>
<name>shiro-example-chapter7</name>
<url>http://maven.apache.org</url> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.2</version>
</dependency> <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.2</version>
</dependency> <dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.25</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>0.2.23</version>
</dependency> <dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency> </dependencies> <build>
<finalName>chapter7</finalName>
<plugins>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>8.1.8.v20121106</version>
<configuration>
<webAppConfig>
<contextPath>/${project.build.finalName}</contextPath>
</webAppConfig>
</configuration>
</plugin> <plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/${project.build.finalName}</path>
</configuration> </plugin>
</plugins> </build>
</project>
1.2 web.xml
前面说过,shiroFilter是入口点,所以要在web.xml中配置shiroFilter及相关参数。
(1)读取配置文件:
从 Shiro 1.2 开始引入了 Environment/WebEnvironment 的概念,ShiroFilter 会自动找到 Environment 然后获取相应的依赖。
<web-app>
<!--- shiro 1.2 -->
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<context-param>
<param-name>shiroEnvironmentClass</param-name>
<param-value>org.apache.shiro.web.env.IniWebEnvironment</param-value><!-- 默认先从/WEB-INF/shiro.ini,如果没有找classpath:shiro.ini -->
</context-param>
<context-param>
<param-name>shiroConfigLocations</param-name>
<param-value>classpath:shiro.ini</param-value>
</context-param>
...
</web-app>
(2)配置shiroFilter:
<web-app>
...
<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.xml文件的总览:即配置文件的读取及拦截设置。
<?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_0.xsd"
version="3.0"
metadata-complete="false">
<!--- shiro 1.2 -->
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<context-param>
<param-name>shiroEnvironmentClass</param-name>
<param-value>org.apache.shiro.web.env.IniWebEnvironment</param-value><!-- 默认先从/WEB-INF/shiro.ini,如果没有找classpath:shiro.ini -->
</context-param>
<context-param>
<param-name>shiroConfigLocations</param-name>
<param-value>classpath:shiro.ini</param-value>
</context-param>
<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> <!--<error-page>-->
<!--<error-code>401</error-code>-->
<!--<location>/WEB-INF/jsp/unauthorized.jsp</location>-->
<!--</error-page>--> </web-app>
这是我的项目中提供的配置:已经与spring集成了。具体的不再说,第十二章详细说明。
<web-app>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
1.3 ini文件的配置
比之前的ini文件多出来的部分是url的配置。
...
[main]
#默认是/login.jsp
authc.loginUrl=/login
roles.unauthorizedUrl=/unauthorized
perms.unauthorizedUrl=/unauthorized [users]
zhang=123,admin
wang=123 [roles]
admin=user:*,menu:* [urls]
/login=anon
/unauthorized=anon
/static/**=anon
/authenticated=authc
/role=authc,roles[admin]
/permission=authc,perms["user:create"]
最重要的就是urls部分的参数。格式为:url=拦截器[参数],拦截器[参数]
anon表示可以匿名访问(不需要登录也可访问),authc表示身份认证通过就可以访问,roles[admin]表示有admin角色才可以访问,perms:["user:create"]表示需要有user的create权限才可以访问。
[urls]
/login=anon
/unauthorized=anon
/static/**=anon
/authenticated=authc
/role=authc,roles[admin]
/permission=authc,perms["user:create"]
2.身份验证
2.1 配置需要身份验证的url
访问这些地址(authc)的时候会判断用户有没有登录,即如果没有登录会跳转到登录页面,默认为/login.jsp,也可以自己自定义配置。
/authenticated=authc
/role=authc,roles[admin]
/permission=authc,perms["user:create"] authc.loginUrl=/login
2.2 LoginServlet
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject; import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException; @WebServlet(name = "loginServlet", urlPatterns = "/login")
public class LoginServlet extends HttpServlet { @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(req, resp);
} @Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String error = null;
String username = req.getParameter("username");
String password = req.getParameter("password");
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
token.setRememberMe(true);
try {
subject.login(token);
} catch (UnknownAccountException e) {
error = "用户名/密码错误";
} catch (IncorrectCredentialsException e) {
error = "用户名/密码错误";
} catch (AuthenticationException e) {
//其他错误,比如锁定,如果想单独处理请单独catch处理
error = "其他错误:" + e.getMessage();
} if(error != null) {//出错了,返回登录页面
req.setAttribute("error", error);
req.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(req, resp);
} else {//登录成功
req.getRequestDispatcher("/WEB-INF/jsp/loginSuccess.jsp").forward(req, resp);
}
}
}
2.3 测试
输入http://localhost:8080/chapter7/login 访问登录页面。
输入账号密码,登录成功后可以接着访问路径:http://localhost:8080/chapter7/authenticated
3 基于Basic与基于表单的拦截器身份验证
Shiro 内置了登录(身份验证)的实现:基于表单的和基于 Basic 的验证,其通过拦截器实现。
3.1 基于Basic的拦截器身份验证
(1)basicfilterlogin.ini文件
[main]
authcBasic.applicationName=please login
………省略 users
[urls]
/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指定登录成功后重定向的默认地址(默认是“/”)(如果有上一个地址会自动重定向带该地址);
[main]
authc.loginUrl=/formfilterlogin
authc.usernameParam=username
authc.passwordParam=password
authc.successUrl=/
authc.failureKeyAttribute=shiroLoginFailure
[urls]
/role=authc,roles[admin]
(2)web.xml
将web.xml中shiro的配置文件地址shiroConfigLocations 改为 shiro-formfilterlogin .ini 即可。
(3)loginServlet
@WebServlet(name = "formFilterLoginServlet", urlPatterns = "/formfilterlogin")
public class FormFilterLoginServlet extends HttpServlet {
...
}
(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是拦截器路径。
[main]
roles.unauthorizedUrl=/unauthorized
perms.unauthorizedUrl=/unauthorized
[urls]
/role=authc,roles[admin]
/permission=authc,perms["user:create"]
(2)web.xml
把 shiroConfigLocations 改为 shiro.ini 即可。
(3)RoleServlet/PermissionServlet
@WebServlet(name = "roleServlet", urlPatterns = "/role")
public class RoleServlet extends HttpServlet { @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Subject subject = SecurityUtils.getSubject();
subject.checkRole("admin");
req.getRequestDispatcher("/WEB-INF/jsp/hasRole.jsp").forward(req, resp);
}
}
@WebServlet(name = "permissionServlet", urlPatterns = "/permission")
public class PermissionServlet extends HttpServlet { @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Subject subject = SecurityUtils.getSubject();
subject.checkPermission("user:create");
req.getRequestDispatcher("/WEB-INF/jsp/hasPermission.jsp").forward(req, resp);
}
}
(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(不需登录即可访问)即可。
[urls]
/logout=anon
(2)web.xml
同样web.xml中shiro的配置文件改成对应的。
(3)LogoutServlet.xml
@WebServlet(name = "logoutServlet", urlPatterns = "/logout")
public class LogoutServlet extends HttpServlet { @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
SecurityUtils.getSubject().logout();
req.getRequestDispatcher("/WEB-INF/jsp/logoutSuccess.jsp").forward(req, resp);
}
}
(4)测试
输入http://localhost:8080/chapter7/login,使用帐号“zhang/123”进行登录,登录成功后访问/logout 即可退出。
(5)shiro提供的logout
配置如下:logout是org.apache.shiro.web.filter.authc.LogoutFilter 类型的实例。
这样配置后,当访问/logout2时,会重定向到/login页面。
[main]
logout.redirectUrl=/login
[urls]
/logout2=logout
2017.2.12 开涛shiro教程-第七章-与Web集成的更多相关文章
-
2017.2.15 开涛shiro教程-第二十一章-授予身份与切换身份(一) table、entity、service、dao
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 第二十一章 授予身份与切换身份(一) 1.使用场景 某个领导因为某 ...
-
2017.2.16 开涛shiro教程-第十七章-OAuth2集成(一)服务器端
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 开涛shiro教程-第十七章-OAuth2集成 1.OAuth2介 ...
-
2017.2.15 开涛shiro教程-第二十一章-授予身份与切换身份(二) controller
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 开涛shiro教程-第二十一章-授予身份与切换身份(二) 1.回顾 ...
-
2017.2.16 开涛shiro教程-第十七章-OAuth2集成(二)客户端
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 开涛shiro教程-第十七章-OAuth2集成 3.客户端 客户端 ...
-
2017.4.12 开涛shiro教程-第十八章-并发登录人数控制
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 开涛shiro教程-第十八章-并发登录人数控制 shiro中没有提 ...
-
2017.2.12 开涛shiro教程-第八章-拦截器机制
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 1.拦截器介绍 下图是shiro拦截器的基础类图: 1.Namea ...
-
2017.2.7 开涛shiro教程-第六章-Realm及相关对象(四)
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 第六章 Realm及相关对象(四) 1.Subject的代码结构 ...
-
2017.2.7 开涛shiro教程-第六章-Realm及相关对象(二)
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 第六章 Realm及相关对象(二) 1.Authenticatio ...
-
2017.2.7 开涛shiro教程-第六章-Realm及相关对象(一)
原博客地址:http://jinnianshilongnian.iteye.com/blog/2018398 根据下载的pdf学习. 第六章 Realm及相关对象 1.用户.角色.权限的关系 用户和角 ...
随机推荐
-
JAVA调用C语言写的SO文件
JAVA调用C语言写的SO文件 因为工作需要写一份SO文件,作为手机硬件IC读卡和APK交互的桥梁,也就是中间件,看了网上有说到JNI接口技术实现,这里转载了一个实例 // 用JNI实现 // 实例: ...
-
Sorting It All Out
Description An ascending sorted sequence of distinct values is one in which some form of a less-than ...
-
Azure PowerShell (二)云服务
. 浏览云服务Get-AzureService | Select-Object -Property ServiceName, Location,`@{Name='ProdIP';Expression ...
-
PERL高效代码摘录 - 数组
1. 2个数组找不同 ,,,,,,); ,); %seen=(); foreach(@a_hast_g){ ; } @unique=grep($seen{$_},@a_cl_g); } map { $ ...
-
perl中执行linux命令,及其区别
1. system("date '+%Y-%m-%d %H:%M:%S'") 该命令返回的是-1.(应该是date命令的main函数的返回值) 2. `date '+%Y-%m-% ...
-
适合入门自学服装裁剪滴书(更新ing)
[♣]适合入门自学服装裁剪滴书(更新ing) [♣]适合入门自学服装裁剪滴书(更新ing) 适合入门自学服装裁剪滴书(更新ing) 来自: 裁缝阿普(不为良匠,便为良医.) 2014-04-06 23 ...
-
解决IOS下不支持fixed的问题
我们公司有一个页面底部用到了fixed样式,每当弹出键盘的时候,IOS下fixed就会走样(据我所知android没有该问题). 为此之前我经过产品的同意做了简单的处理(方法1). 方法一: focu ...
-
如何用一张图片代替 &#39;input:file&#39; 上传本地文件??
今天去面试,碰到了一道题,也许是因为紧张或者喝水喝多了,一时竟然没有转过弯来,回来之后一细想原来这么简单,哭笑不得,特此记录一下! 原题是这样的: 如何用一张图片代替 'input:file' 上传 ...
-
深度学习之卷积神经网络(CNN)详解与代码实现(二)
用Tensorflow实现卷积神经网络(CNN) 本文系作者原创,转载请注明出处:https://www.cnblogs.com/further-further-further/p/10737065. ...
-
python字符串前面u,r,b的含义详解
u/U:表示unicode字符串 不是仅仅是针对中文, 可以针对任何的字符串,代表是对字符串进行unicode编码. 一般英文字符在使用各种编码下, 基本都可以正常解析, 所以一般不带u:但是中文, ...