apache shiro的工作流程分析
本文基于shiro的web环境,用宏观(也就是不精确)的角度去理解shiro的工作流程,先看shiro官方的一张图。

和应用程序直接交互的对象是Subject,securitymanager为Subject服务。可以把Subject看成一个用户,你的所有的代码都由用户来执行。suject.execute(callable),这个callable里面就是你的代码。
一、shiro如何介入你的webapp
它是如何初始化的?servletContextListener。它是如何在每个http请求中介入的?ServletFilter.
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener> <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>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
EnvironmentLoaderListener会根据你在web.xml中的配置读取对应的配置文件(默认读取/WEB-INF/shiro.ini,或者classroot的对应文件),构建一个shiro环境,该环境保存在servletcontext中,所有的filter都可以获取。里面就包括一个单例的securityManager,该securityManager已经根据ini的内容进行了配置。
再看shiroFilter:
@Override
public void init() throws Exception {
WebEnvironment env = WebUtils.getRequiredWebEnvironment(getServletContext()); setSecurityManager(env.getWebSecurityManager()); FilterChainResolver resolver = env.getFilterChainResolver();
if (resolver != null) {
setFilterChainResolver(resolver);
}
}
这样filter里面就可以使用securityManager了。
下面的一段代码就是本文开头提到的Subject(用户)的创建了,因为是web环境所以每次请求都需要创建一个subject对象,在filter里面给你准备好,在你的servlet里面就可以直接使用了。
final ServletRequest request = prepareServletRequest(servletRequest, servletResponse, chain);
final ServletResponse response = prepareServletResponse(request, servletResponse, chain); final Subject subject = createSubject(request, response); //noinspection unchecked
subject.execute(new Callable() {
public Object call() throws Exception {
updateSessionLastAccessTime(request, response);
executeChain(request, response, chain);
return null;
}
});
看一下subject.execute的javadoc,写道:
Associates the specified Callable with this Subject instance and then executes it on the currently running thread. If you want to execute the Callable on a different thread, it is better to use the associateWith(Callable)} method instead.
将callable(你的所有代码都在里面执行)和当前的subject实例相关联,并且在当前的thread中执行...
二、securityManage如何为subject服务
请注意看上面最后一段java代码,里面有一个createSubject(request,response)方法,也在filter里面,它的代码如下:
protected WebSubject createSubject(ServletRequest request, ServletResponse response) {
return new WebSubject.Builder(getSecurityManager(), request, response).buildWebSubject();
}
看到没有?subject的构造用到了securityManager,所有shiro的魔法都被隐藏在securityManager里面了。接下来提一些问题,试着发现securityManager需要完成哪些工作。
如果保证每次http请求得到同一个(确切说应该是一样的)subject?这里关系到session管理了吧。
如何登陆用户,subject.login?这里关系到认证,授权,用户realm了吧。
....
三、clojure-ring使用shiro的可行方案
clojure-ring SPEC中没有提供servlet环境,它的Adapters仅仅是封装了request和response,已经处于请求的最末端。所以shiro提供的servletfilter无法使用。来看看jetty-adapter的代码:
[handler options]
(let [^Server s (create-server (dissoc options :configurator))
^QueuedThreadPool p (QueuedThreadPool. ^Integer (options :max-threads 50))]
(.setMinThreads p (options :min-threads 8))
(when-let [max-queued (:max-queued options)]
(.setMaxQueued p max-queued))
(when (:daemon? options false)
(.setDaemon p true))
(doto s
(.setHandler (proxy-handler handler))
(.setThreadPool p))
(when-let [configurator (:configurator options)]
(configurator s))
(.start s)
(when (:join? options true)
(.join s))
s))
其中.setHandler,是一个实现了jetty的AbstractHandler的handler.
(defn- proxy-handler
"Returns an Jetty Handler implementation for the given Ring handler."
[handler]
(proxy [AbstractHandler] []
(handle [_ ^Request base-request request response]
(let [request-map (servlet/build-request-map request)
response-map (handler request-map)]
(when response-map
(servlet/update-servlet-response response response-map)
(.setHandled base-request true))))))
ring结构和SPEC都非常简洁,上面的代码中将jetty server修改成servletcontext,然后通过一个servlet来实现这个adapter,就可以了。
代码如下:
public void useServlet() throws Exception {
Server server = new Server(8080);
final ServletContextHandler servletContext = new ServletContextHandler(ServletContextHandler.SESSIONS);
servletContext.setClassLoader(Thread.currentThread().getContextClassLoader());
servletContext.addLifeCycleListener(new LifeCycle.Listener() {
@Override
public void lifeCycleStopping(LifeCycle arg0) {
}
@Override
public void lifeCycleStopped(LifeCycle arg0) {
}
@Override
public void lifeCycleStarting(LifeCycle arg0) {
}
@Override
public void lifeCycleStarted(LifeCycle arg0) {
servletContext.setContextPath("/");
servletContext.addServlet(new ServletHolder(new HelloServlet()), "/*");
servletContext.addServlet(new ServletHolder(new HelloServlet("Buongiorno Mondo")), "/it/*");
servletContext.addServlet(new ServletHolder(new HelloServlet("Bonjour le Monde")), "/fr/*");
servletContext.callContextInitialized(new EnvironmentLoaderListener(), new ServletContextEvent(servletContext.getServletContext()));
servletContext.addFilter(ShiroFilter.class, "/*", EnumSet.of(DispatcherType.INCLUDE,DispatcherType.REQUEST,DispatcherType.FORWARD,DispatcherType.ERROR));
}
@Override
public void lifeCycleFailure(LifeCycle arg0, Throwable arg1) {
}
});
server.setHandler(servletContext);
server.start();
server.join();
}
使用上面的代码,就完整的使用了shiro的web模块,但是上面的方法需要注意几个问题:
1、session和cookie和ring本身的机制不一样,需要特别处理。
2、这样个性化的adapter无法融入ring的生态圈,比如lein-ring
基于上面的考虑,不如不使用shiro的web模块,直接使用shiro-core,然后用ring-middleware的方式来实现。
apache shiro的工作流程分析的更多相关文章
- Struts2的工作流程分析
Struts2的工作流程分析 Posted on 2011-02-22 09:32 概述 本章讲述Struts2的工作原理. 读者如果曾经学习过Struts1.x或者有过Struts1.x的开发经验, ...
- 【转】Hostapd工作流程分析
[转]Hostapd工作流程分析 转自:http://blog.chinaunix.net/uid-30081165-id-5290531.html Hostapd是一个运行在用户态的守护进程,可以通 ...
- 第2章 rsync算法原理和工作流程分析
本文通过示例详细分析rsync算法原理和rsync的工作流程,是对rsync官方技术报告和官方推荐文章的解释. 以下是本文的姊妹篇: 1.rsync(一):基本命令和用法 2.rsync(二):ino ...
- [国嵌笔记][030][U-Boot工作流程分析]
uboot工作流程分析 程序入口 1.打开顶层目录的Makefile,找到目标smdk2440_config的命令中的第三项(smdk2440) 2.进入目录board/samsung/smdk244 ...
- rsync算法原理和工作流程分析
本文通过示例详细分析rsync算法原理和rsync的工作流程,是对rsync官方技术报告和官方推荐文章的解释.本文不会介绍如何使用rsync命令(见rsync基本用法),而是详细解释它如何实现高效的增 ...
- nodejs的Express框架源码分析、工作流程分析
nodejs的Express框架源码分析.工作流程分析 1.Express的编写流程 2.Express关键api的使用及其作用分析 app.use(middleware); connect pack ...
- Mysql工作流程分析
Mysql工作流程图 工作流程分析 1. 所有的用户连接请求都先发往连接管理器 2. 连接管理器 (1)一直处于侦听状态 (2)用于侦听用户请求 3. 线程管理器 (1)因为每个用户 ...
- u-boot分析(二)----工作流程分析
u-boot分析(二) 由于这两天家里有点事,所以耽误了点时间,没有按时更新,今天我首先要跟大家说说我对于u-boot分析的整体的思路,然后呢我以后的博客会按照这个内容更新,希望大家关注. 言归正传, ...
- rsync(三)算法原理和工作流程分析
在开始分析算法原理之前,简单说明下rsync的增量传输功能. 假设待传输文件为A,如果目标路径下没有文件A,则rsync会直接传输文件A,如果目标路径下已存在文件A,则发送端视情况决定是否要传输文件A ...
随机推荐
- 字符串函数 replace() 方法妙用
alert('10 12 14 16'.replace(/d+/g,function(match){ return parseInt(match,10) > 10 ? '*' : match; ...
- builtin_shaders-5.3.4f1学习-Unlit/Texture
// Unlit shader. Simplest possible textured shader. // - no lighting // - no lightmap support // - n ...
- 51nod1276(xjb)
题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1276 题意:中文题诶- 思路:xjb 通过画图可以发现对于当前 ...
- Mybatis源码解读-设计模式总结
虽然我们都知道有26个设计模式,但是大多停留在概念层面,真实开发中很少遇到,Mybatis源码中使用了大量的设计模式,阅读源码并观察设计模式在其中的应用,能够更深入的理解设计模式. Mybatis至少 ...
- Proteomes of paired human cerebrospinal fluid and plasma: Relation to blood-brain barrier permeability in older adults (文献分享一组-潘火珍)
题目:Proteomes of paired human cerebrospinal fluid and plasma: Relation to blood-brain barrier permeab ...
- IT兄弟连 JavaWeb教程 JSP经典案例
案例需求:定义一个javaBean叫XdlUser,有四个字段int id.String name.int age.double salary.写一个jsp页面,在页面中构建一个列表对象,里面存放几个 ...
- VMware虚拟机文件(后缀)详解
VMware虚拟机文件(后缀)详解 虚拟机的文件管理由VMware Workstation来执行,一个虚拟机一般以一系列文件的形式储存在宿主机中,这些文件一般在由workstation为虚拟机所创建的 ...
- python学习之序列化
序列化:不同编程语言之间传递对象需要序列化成标准格式,有XML /JSON,json格式化为字符串,UTF-8编码,速度快,切实标准格式.JSON 和 Python内置的数据类型对应如下: JSON ...
- C. Functions again DP + 分类讨论
http://codeforces.com/contest/789/problem/C 首先按题目要求处理出dis数组. 那么对于任意一个区间,[L, R],是dis[L] - dis[L + 1] ...
- 20 个案例教你在 Java 8 中如何处理日期和时间?
前言 前面一篇文章写了<SimpleDateFormat 如何安全的使用?>, 里面介绍了 SimpleDateFormat 如何处理日期/时间,以及如何保证线程安全,及其介绍了在 Jav ...