前面的文章中为大家介绍了 Shrio 的基础概念。可能比較笼统。没有深入到开发过程的一些问题。如今集中在本帖中归纳一下有关问题。

FormAuthenticationFilter 表单过滤器

表单过滤器的问题,是本人在实现验证码组件时候遇到的,亦以前一度让我“抓狂”。虽然有便捷的方法实现验证码,比如在控制器中就能够推断验证码逻辑了,可是那有违 Shiro 结构体系的思想;本人也想籍此了解 Shiro 扩展实现方法,——假设都走捷径。那么学习的目的就达不到了。于是,本人就把遇到问题逐一罗列出来。

首先啰嗦下。为什么不写在控制器?

Shiro 提供丰富的过滤器,FormAuthenticationFilter 就是一种过滤器。既然使用了安全框架。那么我们就应该依照框架的方法去编码。我们知道,经典 Web MVC 中,过滤器是优于 Servlet 运行的,也是一般用作安全检測、权限校验之用的。

所以 Shiro 组件基于过滤器的思想就“名正言顺”了(所以说 Filter 能做的,Shiro 也能做,Filter 做不了的或者不适合做的, Shiro 过滤器也不会僭越)。实际从作用功效上,过滤器与 Servlet 彼此替代可能性蛮大的。也就是说,Servlet 的逻辑用在 Filter 之上亦能够,效果看起来不会差太多——反之亦然。只是,我们还是要回想下它们之间的差别:首先是前面说的。Filter 优于 Servlet 运行,Filter 拦截了,Servlet 也不会运行;其次,编码风格上 Filter 基于责任链式模式,Servlet 却不是;最后就是 Filter 不像 Servlet,它不能产生一个请求或者响应。Filter 通常仅仅是返回 true/false。当然,它们是如此地相像。以至于把 Filter 觉得是 Servlet 变种的一种亦未尝不可。

所以,我们会看到 Shiro 的一些案例中,既有 Filter。又有 Controller。比如以下我们绑定会员登录的 url 到 FormAuthenticationFilter,然后又声明有控制器。

CaptchaFormAuthenticationFilter 是扩展 FormAuthenticationFilter 的验证码过滤器。

/service/user/access/login = authcaptcha 这句就是绑定了验证码过滤器。

这样如此。应该是不用编码就能够调用 CaptchaFormAuthenticationFilter 了。

这个完整的请求还有 Controller 部分:

@RequestMapping(value = "/login", method = RequestMethod.POST)
public void loginAction(User user, HttpServletRequest request, HttpServletResponse response) {
String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");
Throwable exObj = (Throwable) request.getAttribute("exObj"); String error = null;
LOGGER.info("client " + user.getName() + "登录..." + exceptionClassName); if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
error = "未知用户错误";
} else if (IncorrectCredentialsException.class.getName().equals(exceptionClassName)) {
error = "用户名/password错误";
} else if (IncorrectCaptchaException.class.getName().equals(exceptionClassName)) {
error = "验证码错误";
} else if (exObj != null && exObj.getClass().getName().equals(IllegalArgumentException.class.getName())) {
error = exObj.getMessage(); // 缺少某个字段
} else if (exceptionClassName != null) {
error = "其它错误:" + exceptionClassName;
} // 输出 JSON
ResponseHelper rsp = new ResponseHelper(response);
boolean isOk = error == null;
String msg = error == null ? "登录成功!" : error + "详细原因:" + (exObj != null ? exObj.getMessage() : "N/A");
rsp.outputAction(isOk, msg);
}

可见,这个控制器好像“打杂”的,作用比較简单,像是一些善后的工作。

可是,为什么过滤器运行不起来?

遗憾的是,声明过滤器之后却运行不起来,不能正确跳转。

訪问这个 url。即使输入合法也跳到“登录”页面(也就是未登录的页面)。然后重复搜索相关资料和样例,得知表单是 AccessControlFilter 的子类,假设訪问了一定回 isAccessAllowed() 方法,试了下果然能够,表示是否同意訪问。然后我下意识地调用验证码的 executeLogin() 方法,也就是封装的 getSubject().login(token); 的方法。难道是这样调用控制器的吗?我覺得我这样的方法有点“简单粗暴”。框架不至于推荐这么做——后来的測试也证明此法不可行,报了一个两次 redirect 重定向的异常。——这肯定是我的方法不正确!

百搜不得其解下。我十分灰心。甚至想放弃,后来我想到把 Shiro 源代码和文档附加到 jar 中,看看里面的源代码和凝视。果然人家就说明须要 POST 请求。并且要指定登陆 URL(这个是 Action 接受请求的地址。假设不设置默认是 /login.jsp,这就是导致非常多人不能成功调用过滤器的原因!)才干调用过滤器,有条件限制的,并且根本不须要运行 isAccessAllowed() 方法。

后来又发现个小插曲,——偶尔登录成功后,在尝试登录是不会运行过滤器。因此 Shiro 定义是“一次运行的”。详细原理我就没有深究了仅仅是知道有这么一个机制。測试相应的方法也非常easy。把浏览器缓存清掉,令其 session 去掉。

另外表单 POST 字段的映射,FormAuthenticationFilter 也考虑到了,參见配置中的 <property name="usernameParam" value="name" />:

	<bean id="captchaFormAuthenticationFilter"
class="com.ajaxjs.framework.user.captcha.CaptchaFormAuthenticationFilter">
<property name="usernameParam" value="name" />
<property name="loginUrl" value="/service/user/access/login" />
</bean>

这里的是 Spring 的配置方法。

小结一下 Shiro 认证

Shiro 就是这样,提供现成的组件方便我们调用,我们也能够从中了解其机制,——反正都是开源的。

过滤器是认证的第一板斧,是创建 token 的那一步。有了 token 才干运行 AuthenticatingRealm.doGetAuthenticationInfo(AuthenticationToken authcToken),最后到控制器。网上有些样例把创建 token 那一步写在控制器中。虽然做法有点简单粗暴,但道理还是一样的。

Shiro 学习应用(续)的更多相关文章

  1. Shiro学习笔记(5)——web集成

    Web集成 shiro配置文件shiroini 界面 webxml最关键 Servlet 測试 基于 Basic 的拦截器身份验证 Web集成 大多数情况.web项目都会集成spring.shiro在 ...

  2. Shiro学习

    Shiro学习资源 Shiro官网,http://shiro.apache.org/index.html 学习网站链接,http://blog.java1234.com/blog/articles/4 ...

  3. Apache Shiro学习-2-Apache Shiro Web Support

     Apache Shiro Web Support  1. 配置 将 Shiro 整合到 Web 应用中的最简单方式是在 web.xml 的 Servlet ContextListener 和 Fil ...

  4. shiro学习笔记_0600_自定义realm实现授权

    博客shiro学习笔记_0400_自定义Realm实现身份认证 介绍了认证,这里介绍授权. 1,仅仅通过配置文件来指定权限不够灵活且不方便.在实际的应用中大多数情况下都是将用户信息,角色信息,权限信息 ...

  5. Apache shiro学习总结

    Apache shiro集群实现 (一) shiro入门介绍 Apache shiro集群实现 (二) shiro 的INI配置 Apache shiro集群实现 (三)shiro身份认证(Shiro ...

  6. Shiro学习笔记总结,附加" 身份认证 "源码案例(一)

    Shiro学习笔记总结 内容介绍: 一.Shiro介绍 二.subject认证主体 三.身份认证流程 四.Realm & JDBC reaml介绍 五.Shiro.ini配置介绍 六.源码案例 ...

  7. SpringBoot+Shiro学习(七):Filter过滤器管理

    SpringBoot+Shiro学习(七):Filter过滤器管理 Hiwayz 关注  0.5 2018.09.06 19:09* 字数 1070 阅读 5922评论 1喜欢 20 先从我们写的一个 ...

  8. Apache Shiro 学习记录5

    本来这篇文章是想写从Factory加载ini配置到生成securityManager的过程的....但是貌似涉及的东西有点多...我学的又比较慢...很多类都来不及研究,我又怕等我后面的研究了前面的都 ...

  9. Apache Shiro 学习记录4

    今天看了教程的第三章...是关于授权的......和以前一样.....自己也研究了下....我觉得看那篇教程怎么说呢.....总体上是为数不多的精品教程了吧....但是有些地方确实是讲的太少了.... ...

随机推荐

  1. Spark Streaming概念学习系列之SparkStreaming性能调优

    SparkStreaming性能调优 合理的并行度 减少批处理所消耗时间的常见方式还有提高并行度.有以下三种方式可以提高并行度: 1.增加接收器数目 有时如果记录太多导致单台机器来不及读入并分发的话, ...

  2. 整体刷新和局部刷新frameset窗口

    在项目中,经常会遇到页面分割,最常见的系统或网站的主界面.主页面分为,上面系统简介.下面作者简介.左边系统功能菜单.右边则是菜单真正展示的界面. 遇到这种这种分割页面,大家首先想到是frameset, ...

  3. Jenkins 打包 java项目时 丢失 配置文件(resource)

    使用IDEA开发的spring boot 项目在本地打包运行可以,但是利用Jenkins打包运行提示读取不到配置文件中的变量,打开jar包发现里面没有配置文件.解决方法是在pom中增加如下配置 < ...

  4. [原创]C++中一些重要概念

    1.虚函数 虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数.当把基类的某个成员函数声明为虚函数后,允许在其派生类中对该函数重新定义,赋予 ...

  5. 使用JDK和axis2发布webservice

    最近使用webservice进行远程调用一直很火,自从JDK1.6版本发布后,发布一个webservice项目变得更加简单了 笔者由于工作的需要针对JDK和axis2如何发布webservice做过相 ...

  6. 数组、ArrayList、HashTable

    相同点:都可以存储一组数据 不同点: 1)数组,必须要先分配空间,存储数据固定 2)ArrayList,存储数据可以自由扩展 3)HashTable与ArrayList一样,但是它是有意义的,键值对形 ...

  7. 使用UMDH进行内心泄露分析

    事前准备 1.安装windbg,安装好后在path中添加其安装目录(目的是为了执行命令行简单) 2.(设置符号路径,一般为接口所在路径)运行cmd,执行命令:set _NT_SYMBOL_PATH=d ...

  8. Spring boot application.properties 配置

    原文链接: http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.ht ...

  9. 【从零开始】【Java】【0】装软件些

    闲聊 其实最先写的是1,所以拐回头写的只能是0了. 因为要在不同的电脑上搞这个东西,必然涉及到装机,当然只是装我们用的这些,且是最基础的部分了. 大晚上的睡不着觉,起来,大概1个小时全部搞定,随便记下 ...

  10. Windows负载机JVM 远程监控Linux服务器下tomcat

    基本是跟着网上的操作进行的,除了遇到一个Local host name unknown的问题: 一.Linux服务器操作部分 服务器地址:10.64.111.68 首先配置JMX: 1.找到jdk目录 ...