戒色诗: 二八佳人体似酥,腰间仗剑斩凡夫。虽然不见人头落,暗里教君骨髓枯。
一. Shiro 配置文件的四大部分
在 shiro.ini 这个配置文件中, 有四个部分, [main], [users],[roles], 还有一个 [urls], 前面三个部分,我们都讲解了,只剩下一个 urls。这儿进行讲解一下。
一. 一 [main] 部分
提供了对根对象securityManager及其依赖对象的配置。
如,前面的 jdbc 配置 和策略配置。
[main]#配置数据源dataSource=com.mchange.v2.c3p0.ComboPooledDataSource#配置数据库的信息dataSource.driverClass=com.mysql.jdbc.DriverdataSource.jdbcUrl=jdbc:mysql://localhost:3306/shiro?characterEncoding=utf8dataSource.user=rootdataSource.password=abc123#配置 realmjdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm#配置数据源jdbcRealm.dataSource=$dataSource#注入多个realm 到securityManager里面securityManager.realm=$jdbcRealm#配置验证器authenticationStrategy=org.apache.shiro.authc.pam.FirstSuccessfulStrategysecurityManager.authenticator.authenticationStrategy=$authenticationStrategy
在与 Servlet 进行整合时, [main] 部分也常常添加 如下两个部分:
authc.loginUrl=/User/toLoginroles.unauthorizedUrl=/NoPermission/NoPermissionperms.unauthorizedUrl=/NoPermission/NoPermission
authc.loginUrl=/User/toLogin, 是配置没有通过认证时,跳转的页面, 通常是 登录页面
roles.unauthorizedUrl=/NoPermission/NoPermission 是没有配置要求的角色时跳转的页面, 通常是权限不足页面
perms.unauthorizedUrl=/NoPermission/NoPermission 是没有当前要求的权限时跳转的页面, 通常是权限不足页面。
一.二 [users] 部分
主要是配置用户的信息, 用户名=密码,角色1,角色2 ... 角色可以省略。
[users]#用户名=密码,角色1,角色2yuejl=1234,role1,role3yuezl=1234,role2
一.三 [roles] 部分
主要是配置角色与权限的信息, 角色=权限1,权限2
[roles]role1=user:add,user:deleterole2=user:*role3=user:select
一.四 [urls] 部分
配置 url 及相应的拦截器之间的关系, url=拦截器1[参数],拦截器2[参数]
[urls]/static/**=anon/User/toLogin=anon/User/login=anon/Main/toMain=authc/User/add=authc,perms["user:add"]/User/update=authc,perms["user:update"]/User/select=authc,perms["user:select"]/User/delete=authc,perms["user:delete"]
即 访问 /static/ 路径时, 被 anon 拦截器拦截,
访问 /Main/toMain 路径时,被 authc 拦截器拦截
访问 /User/add 路径时, 被authc 拦截器拦截,并且被拦截器 perms 拦截器 进行拦截
其中, anon, authc,perms 都是拦截器的别名缩写,分别代表着不同的功能。
二. Shiro 的拦截器
关于拦截器的详细使用,可以看 张开涛前辈写得文章: 第八章 拦截器机制——《跟我学Shiro》
Shiro 为了方便 认证和授权,提供了好多默认拦截器。
二.一 拦截器定义位置
拦截器 被定义在 org.apache.shiro.web.filter.mgt.DefaultFilter 类下。
public enum DefaultFilter { anon(AnonymousFilter.class), authc(FormAuthenticationFilter.class), authcBasic(BasicHttpAuthenticationFilter.class), logout(LogoutFilter.class), noSessionCreation(NoSessionCreationFilter.class), perms(PermissionsAuthorizationFilter.class), port(PortFilter.class), rest(HttpMethodPermissionFilter.class), roles(RolesAuthorizationFilter.class), ssl(SslFilter.class), user(UserFilter.class);... }
前面的 anon,authc 就是别名缩写, AnonymousFilter,FormAuthenticationFilter 是其对应的拦截器类。
二.二 各个拦截器的意义
| 默认拦截器名 | 对应类 | 说明 |
|---|---|---|
| 认证有关的 | ||
| authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter | 基于表单的拦截器;如“/**=authc”,如果没有登录会跳到相应的登录页面登录;主要属性:usernameParam:表单提交的用户名参数名( username);passwordParam:表单提交的密码参数名(password);rememberMeParam:表单提交的密码参数名(rememberMe); loginUrl:登录页面地址(/login.jsp);successUrl:登录成功后的默认重定向地址; failureKeyAttribute:登录失败后错误信息存储key( shiroLoginFailure); |
| anon | org.apache.shiro.web.filter.authc.AnonymousFilter | 匿名拦截器,即不需要登录即可访问;一般用于静态资源过滤;示例“/static/**=anon” |
| authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter | Basic HTTP身份验证拦截器,主要属性:applicationName:弹出登录框显示的信息(application); |
| logout | org.apache.shiro.web.filter.authc.LogoutFilter | 退出拦截器,主要属性:redirectUrl:退出成功后重定向的地址(/);示例“/logout=logout” |
| user | org.apache.shiro.web.filter.authc.UserFilter | 用户拦截器,用户已经身份验证/记住我登录的都可;示例“/**=user” |
| 授权有关的 | ||
| roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter | 角色授权拦截器,验证用户是否拥有所有角色;主要属性:loginUrl:登录页面地址(/login.jsp);unauthorizedUrl:未授权后重定向的地址;示例“/admin/**=roles[admin]” |
| perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter | 权限授权拦截器,验证用户是否拥有所有权限;属性和roles一样;示例“/user/**=perms["user:create"]” |
| port | org.apache.shiro.web.filter.authz.PortFilter | 端口拦截器,主要属性:port(80):可以通过的端口;示例“/test= port[80]”,如果用户访问该页面是非80, 将自动将请求端口改为80并重定向到该80端口,其他路径/参数等都一样 |
| rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter | rest风格拦截器,自动根据请求方法构建权限字符串(GET=read, POST=create,PUT=update,DELETE=delete,HEAD=read,TRACE=read,OPTIONS=read, MKCOL=create)构建权限字符串;示例“/users=rest[user]”,会自动拼出“user:read,user:create,user:update,user:delete”权限字符串进行权限匹配(所有都得匹配,isPermittedAll); |
| ssl | org.apache.shiro.web.filter.authz.SslFilter | SSL拦截器,只有请求协议是https才能通过;否则自动跳转会https端口(443);其他和port拦截器一样; |
| 其他 | ||
| noSessionCreation | org.apache.shiro.web.filter.session.NoSessionCreationFilter | 不创建会话拦截器,调用 subject.getSession(false)不会有什么问题,但是如果 subject.getSession(true)将抛出 DisabledSessionException异常; |
可以通过 配置文件 来做一个简单的 小Demo. 由于还没有学习自定义Realm, 故先用配置文件的形式获取数据。
三. Servlet 整合 Shiro
三.一 添加依赖
需要添加 关于 shiro 的依赖,日志的依赖,还有tomcat 的依赖。用到了 json,需要添加 json的依赖。
javax.servlet.jsp javax.servlet.jsp-api 2.3.1 provided javax.servlet javax.servlet-api 3.1.0 provided javax.servlet jstl 1.2 taglibs standard 1.1.2 org.apache.shiro shiro-all 1.2.2 junit junit 4.12 org.slf4j slf4j-log4j12 1.7.25 commons-logging commons-logging 1.2 net.sf.json-lib json-lib 2.4 org.apache.commons commons-lang3 3.1 commons-collections commons-collections 3.2.2 org.apache.maven.plugins maven-compiler-plugin 3.1 1.8 1.8 org.apache.tomcat.maven tomcat7-maven-plugin 2.2 8080 /Shiro_Web UTF-8
三.二 配置 web.xml
需要配置监听器,配置文件的路径,添加过滤器。
org.apache.shiro.web.env.EnvironmentLoaderListener shiroEnvironmentClass org.apache.shiro.web.env.IniWebEnvironment shiroConfigLocations classpath:shiro.ini ShiroFilter org.apache.shiro.web.servlet.ShiroFilter ShiroFilter /*
有的教程说,1.2版本以上不用配置过滤器,但没有配置时,老蝴蝶这项目运行报错,创建securityManager 报错,添加上就没有问题了。故老蝴蝶这儿添加上shiro 过滤器。
三.三 编写配置文件 shiro.ini
[main]#没有登录时,跳转到登录的路径authc.loginUrl=/User/toLogin#跳转到权限不足的路径roles.unauthorizedUrl=/NoPermission/NoPermissionperms.unauthorizedUrl=/NoPermission/NoPermission# 配置用户的信息[users]#用户名=密码,角色1,角色2yuejl=1234,role1,role3yuezl=1234,role2# 定义角色的信息, 角色,权限, *表示全部的权限[roles]role1=user:add,user:deleterole2=user:*role3=user:select[urls]#静态页面可以访问/static/**=anon#跳转到登录页面和登录方法可以访问/User/toLogin=anon/User/login=anon#跳转到主页,需要认证/Main/toMain=authc#执行方法,不仅需要认证,还需要有相应的方法/User/add=authc,perms["user:add"]/User/update=authc,perms["user:update"]/User/select=authc,perms["user:select"]/User/delete=authc,perms["user:delete"]#退出登录/User/logout=logout
由于配置文件中,用的是 key=value, 所以在访问路径时,不能用以前的 /User?jsp=toLogin, 和 /User?method=login 了。
BaseServlet 不能使用了, 需要用原始的一个方法,一个Servlet的形式了。
yuejl 没有修改的权限, yuezl 具有全部的权限。
三.四 编写后台控制
后台类结构:

三.四.一 跳转到登录的类
@WebServlet("/User/toLogin")public class UserToLoginServlet extends HttpServlet{private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(req, resp); }}
三.四.二 登录类
@WebServlet("/User/login")public class UserLoginServlet extends HttpServlet{private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //找到相应的Subject Subject subject=SecurityUtils.getSubject(); UsernamePasswordToken token=new UsernamePasswordToken(req.getParameter("code"), req.getParameter("password")); try{ subject.login(token); boolean2Json(resp, true); }catch(Exception e){ //代码为001,表示用户名或者密码错误 map2Json(resp,"001"); }}/** * 将状态返回到前台,通常是添加,删除,更新的操作,如果错误,则传入错误代码。 * @param o * @param exclueds */public void map2Json(HttpServletResponse resp,String ... code){ //指定哪些属性不需要转json JSONObject objMap=new JSONObject(); if(code==null||code.length<1){ objMap.put("status",true); }else{ objMap.put("status",false); objMap.put("error_code",code[0]); } resp.setContentType("text/json;charset=utf-8"); try { resp.getWriter().print(objMap.toString()); } catch (IOException e) { e.printStackTrace(); }}/** * 传入是否成功,只返回状态 * @param o * @param exclueds */public void boolean2Json(HttpServletResponse resp,boolean flag){ //指定哪些属性不需要转json JSONObject objMap=new JSONObject(); objMap.put("status",true); objMap.put("flag",flag); resp.setContentType("text/json;charset=utf-8"); try { resp.getWriter().print(objMap.toString()); } catch (IOException e) { e.printStackTrace(); }}}
注意,这两个Json 转换的方法是通用的,每一个需要转换的类里面都有,避免代码过多,老蝴蝶这不重复写了。
三.四.三 登录成功后跳转到主页
@WebServlet("/Main/toMain")public class MainServlet extends HttpServlet{private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getRequestDispatcher("/WEB-INF/pages/main.jsp").forward(req, resp); }}
三.四.四 退出方法
@WebServlet("/User/logout")public class UserLoginOutServlet extends HttpServlet{private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Subject subject=SecurityUtils.getSubject(); //退出登录 subject.logout(); req.getRequestDispatcher("/WEB-INF/pages/login.jsp").forward(req, resp);}}
三.四.五 跳转到员工页面
@WebServlet("/User/toList")public class UserToListServlet extends HttpServlet{private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.getRequestDispatcher("/WEB-INF/pages/user.jsp").forward(req, resp); }}
三.四.六 员工添加
@WebServlet("/User/add")public class UserAddServlet extends HttpServlet{private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("执行添加的方法"); boolean2Json(resp, true);}...//json 转换的方法,具体见登录方法}
三.四.七 员工修改
@WebServlet("/User/update")public class UserUpdateServlet extends HttpServlet{private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("执行修改的方法"); boolean2Json(resp, true);}}
三.四.八 员工删除
@WebServlet("/User/delete")public class UserDeleteServlet extends HttpServlet{private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("执行删除的方法"); boolean2Json(resp, true);}}
三.四.九 员工查询
@WebServlet("/User/select")public class UserSelectServlet extends HttpServlet{private static final long serialVersionUID = 1L;@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("执行查询的方法"); boolean2Json(resp, true);}}
三.五 编写前端静态页面
结构目录如下所示:

三.五.一 编写 index.jsp
谢谢您访问我,我是两个蝴蝶飞
三.五.二 编写登录页面 login.jsp
两个蝴蝶飞登录页面
用户名:
name="code" value=""/>
密码:
name="password"/>
ajax 方法,进行提交跳转
$(function(){ $("#submit").click(function(){ var code=$("#code").val(); var password=$("#password").val(); var info=new Object(); //传入进去,员工的id编号 info.code=code; info.password=password; $.post("${pageContext.request.contextPath}/User/login",info,function(data){ if(data.status){ alert("登录成功"); window.location.href="${pageContext.request.contextPath}/Main/toMain"; }else{ if(data.error_code=="001"){ alert("用户名或者密码错误"); } } }) }) })
三.五.三 主页 main.jsp
进入到主页 欢迎[]登录,退出
三.五.四 权限不足页面 noPrivilege.jsp
抱歉,您没有权限访问!!!
三.五.五 员工按钮显示页面 user.jsp
是否有查询权限: 有查询权限是否有添加权限: 有添加权限是否有修改权限: 有修改权限是否有删除权限: 有删除权限
shiro:user, shiro:hasPermission 是shiro 提供的标签库, 通过判断是否有权限,来显示页面元素的显示和隐藏。
注意, 不要忘记引用 shiro 标签库

关于 shiro 标签库的使用,可以看 第九章 JSP标签——《跟我学Shiro》
记住常用的 shiro:user, shiro:hasPermission 即可。
三.六 验证
三.六.一 用户 yuejl 验证
输入网址: http://localhost:8080/Shiro_Web/
填写账号 yuejl, 密码是 123456, 错误的密码

填写账号 yuejl, 密码是 1234, 正确的密码


员工yuejl 正常登录, 输入网址,跳转到员工的界面
http://localhost:8080/Shiro_Web/User/toList
员工yuejl 没有修改的权限,故修改那一块的元素不显示

手动输入网址,看是否可以访问:
输入添加的网址: http://localhost:8080/Shiro_Web/User/add

员工具有添加的权限,故可以执行添加的操作。
输入修改的网址,http://localhost:8080/Shiro_Web/User/update

员工不具有修改的权限,故不可以执行修改的操作,会显示权限不足。
点击退出,退出之后, 输入刚才的 添加的那个网址,会跳转到登录的页面

三.六.二 用户 yuezl 验证
前面的测试,与yuejl 一样。
yuezl 具有修改的权限:
http://localhost:8080/Shiro_Web/User/toList

当手动输入修改的网址时: http://localhost:8080/Shiro_Web/User/update

Servlet 整合 Shiro, 控制权限成功。
本章节代码链接为:
链接:https://pan.baidu.com/s/1dMQkpcxU04WKLnIdbsm-Aw 提取码:kmji
谢谢您的观看,我是两个蝴蝶飞, 如果喜欢,请关注我,再次感谢 !!!
Servlet整合Shiro去除登录提示框详解
本文详细介绍了如何在Servlet中整合Shiro以去掉登录提示框,涉及Shiro配置文件的四大板块:[main]、[users]、[roles]、[urls],并解析了各部分的作用。讲解了Shiro的拦截器机制和具体使用,包括配置url及拦截器的关系。此外,还阐述了Servlet整合Shiro的步骤,从添加依赖、配置web.xml到编写后台控制和前端页面,以及详细的验证过程,展示了如何实现权限控制。
2101

被折叠的 条评论
为什么被折叠?



