<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>北风技术专栏 &#187; ikon999</title>
	<atom:link href="http://column.ibeifeng.com/wp-feed.php?author_name=51564&#038;feed=feed" rel="self" type="application/rss+xml" />
	<link>http://column.ibeifeng.com</link>
	<description>用技术点亮生活中每个亮点</description>
	<pubDate>Sun, 25 Jul 2010 12:28:34 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.6.2</generator>
	<language>en</language>
			<item>
		<title>深入dwr2之三   Dwr2页面请求处理机制分析之engine.js</title>
		<link>http://column.ibeifeng.com/51564/20081202235.shtml</link>
		<comments>http://column.ibeifeng.com/51564/20081202235.shtml#comments</comments>
		<pubDate>Tue, 02 Dec 2008 05:30:30 +0000</pubDate>
		<dc:creator>ikon999</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Web开发]]></category>

		<category><![CDATA[ajax]]></category>

		<category><![CDATA[dwr]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=235</guid>
		<description><![CDATA[DWREngine是dwr在客户端的存根，它其中的方法基本上不需要用户来直接调用；通常你会在服务器的dwr.xml定义需要暴露的java类及其可调用方法，dwr会根据这个配置文件自动生成一个dwr/interface/**.js文件，对应你暴露的java类及其方法，你会在本地调用**.js文件定义的方法，和调用java的方法一样，除了多了一个回调参数，然后这个方法会委托DWREngine._execute发出请求；
Engine.js与util.js不同之处在于，util.js是静态js文件，可以直接从jar文件中拿出来，页面可以直接引用；而engine.js则有部分动态内容，这决定了它必须经过servelt资源请求，在servelt为动态内容赋值之后，才可以返回给客户端；

/** The original page id sent from the server */
dwr.engine._origScriptSessionId = &#8220;${scriptSessionId}&#8221;;
 
/** The session cookie name */
dwr.engine._sessionCookieName = &#8220;${sessionCookieName}&#8221;; // JSESSIONID
 
/** Is GET enabled for the benefit of Safari? */
dwr.engine._allowGetForSafariButMakeForgeryEasier = &#8220;${allowGetForSafariButMakeForgeryEasier}&#8221;;
 
/** The script prefix to strip in the case of scriptTagProtection. */
dwr.engine._scriptTagProtection = &#8220;${scriptTagProtection}&#8221;;
 
/** The default path to the DWR [...]]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal" style="21pt;"><span style="black;" lang="EN-US"><span style="Times New Roman;">DWREngine</span></span><span style="'Times New Roman';">是</span><span style="black;" lang="EN-US"><span style="Times New Roman;">dwr</span></span><span style="'Times New Roman';">在客户端的存根，它其中的方法基本上不需要用户来直接调用；通常你会在服务器的</span><span style="black;" lang="EN-US"><span style="Times New Roman;">dwr.xml</span></span><span style="'Times New Roman';">定义需要暴露的</span><span style="black;" lang="EN-US"><span style="Times New Roman;">java</span></span><span style="'Times New Roman';">类及其可调用方法，</span><span style="black;" lang="EN-US"><span style="Times New Roman;">dwr</span></span><span style="'Times New Roman';">会根据这个配置文件自动生成一个</span><span style="black;" lang="EN-US"><span style="Times New Roman;">dwr/interface/**.js</span></span><span style="'Times New Roman';">文件，对应你暴露的</span><span style="black;" lang="EN-US"><span style="Times New Roman;">java</span></span><span style="'Times New Roman';">类及其方法，你会在本地调用</span><span style="black;" lang="EN-US"><span style="Times New Roman;">**.js</span></span><span style="'Times New Roman';">文件定义的方法，和调用</span><span style="black;" lang="EN-US"><span style="Times New Roman;">java</span></span><span style="'Times New Roman';">的方法一样，除了多了一个回调参数，然后这个方法会委托</span><span style="black;" lang="EN-US"><span style="Times New Roman;">DWREngine._execute</span></span><span style="'Times New Roman';">发出请求；</span></p>
<p class="MsoNormal" style="21pt;"><span style="black;" lang="EN-US"><span style="Times New Roman;">Engine.js</span></span><span style="'Times New Roman';">与</span><span style="black;" lang="EN-US"><span style="Times New Roman;">util.js</span></span><span style="'Times New Roman';">不同之处在于，</span><span style="black;" lang="EN-US"><span style="Times New Roman;">util.js</span></span><span style="'Times New Roman';">是静态</span><span style="black;" lang="EN-US"><span style="Times New Roman;">js</span></span><span style="'Times New Roman';">文件，可以直接从</span><span style="black;" lang="EN-US"><span style="Times New Roman;">jar</span></span><span style="'Times New Roman';">文件中拿出来，页面可以直接引用；而</span><span style="black;" lang="EN-US"><span style="Times New Roman;">engine.js</span></span><span style="'Times New Roman';">则有部分动态内容，这决定了它必须经过</span><span style="black;" lang="EN-US"><span style="Times New Roman;">servelt</span></span><span style="'Times New Roman';">资源请求，在</span><span style="black;" lang="EN-US"><span style="Times New Roman;">servelt</span></span><span style="'Times New Roman';">为动态内容赋值之后，才可以返回给客户端；</span></p>
<p class="MsoNormal" style="21pt;"><span id="more-235"></span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US">/** The original page id sent from the server */</span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US">dwr.engine._origScriptSessionId = </span><span style="0pt;" lang="EN-US">&#8220;${scriptSessionId}&#8221;</span><span style="0pt;" lang="EN-US">;</span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US">/** The session cookie name */</span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US">dwr.engine._sessionCookieName = </span><span style="0pt;" lang="EN-US">&#8220;${sessionCookieName}&#8221;</span><span style="0pt;" lang="EN-US">; </span><span style="0pt;" lang="EN-US">// JSESSIONID</span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US">/** Is GET enabled for the benefit of Safari? */</span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US">dwr.engine._allowGetForSafariButMakeForgeryEasier = </span><span style="0pt;" lang="EN-US">&#8220;${allowGetForSafariButMakeForgeryEasier}&#8221;</span><span style="0pt;" lang="EN-US">;</span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US">/** The script prefix to strip in the case of scriptTagProtection. */</span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US">dwr.engine._scriptTagProtection = </span><span style="0pt;" lang="EN-US">&#8220;${scriptTagProtection}&#8221;</span><span style="0pt;" lang="EN-US">;</span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US">/** The default path to the DWR servlet */</span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US">dwr.engine._defaultPath = </span><span style="0pt;" lang="EN-US">&#8220;${defaultPath}&#8221;</span><span style="0pt;" lang="EN-US">;</span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US">/** Do we use XHR for reverse ajax because we are not streaming? */</span></p>
<p class="MsoNormal" style="none;" align="left"><span style="0pt;" lang="EN-US">dwr.engine._pollWithXhr = </span><span style="0pt;" lang="EN-US">&#8220;${pollWithXhr}&#8221;</span><span style="0pt;" lang="EN-US">;</span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="'Courier New';">这些变量值，会在页面每次刷新时，服务器会重新赋值；</span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="list 19.5pt;"><span style="宋体;" lang="EN-US"><span style="Ignore;">一、</span></span><span style="'Courier New';">下面是</span><span style="0pt;" lang="EN-US">engine.js</span><span style="'Courier New';">中一些变量和方法的解释</span><span style="0pt;" lang="EN-US">:</span></p>
<p class="MsoNormal" style="list 18.0pt;"><span style="0pt;" lang="EN-US"><span style="Ignore;">1、<span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="0pt;" lang="EN-US">origScriptSessionId</span><span style="'Courier New';">：</span></p>
<p class="MsoNormal" style="18pt;"><span style="'Courier New';">原始脚本</span><span style="0pt;" lang="EN-US">sessionid,</span><span style="'Courier New';">随每次刷新而改变；它与我们所说的</span><span style="0pt;" lang="EN-US">httpsessionid</span><span style="'Courier New';">是有区别的，</span><span style="0pt;" lang="EN-US">httpsessionid</span><span style="'Courier New';">是保存在服务器端，</span><span style="0pt;" lang="EN-US">origScriptSessionId</span><span style="'Courier New';">是保存在客户端的；</span><span style="0pt;"> </span></p>
<p class="MsoNormal" style="list 18.0pt;"><span style="0pt;" lang="EN-US"><span style="Ignore;">2、<span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="0pt;" lang="EN-US">dwr.engine._getJSessionId</span></p>
<p class="MsoNormal" style="18pt;"><span style="'Courier New';">得到我们所说的</span><span style="0pt;" lang="EN-US">httpsessionid</span><span style="'Courier New';">，这个</span><span style="0pt;" lang="EN-US">id</span><span style="'Courier New';">在整个会话生命周期内不变；</span></p>
<p class="MsoNormal" style="list 18.0pt;"><span style="0pt;" lang="EN-US"><span style="Ignore;">3、<span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="0pt;" lang="EN-US">dwr.engine._sessionCookieName</span></p>
<p class="MsoNormal" style="18pt;"><span style="'Courier New';">由</span><span style="0pt;" lang="EN-US">_getJSessionId</span><span style="'Courier New';">方法引用，用来获取</span><span style="0pt;" lang="EN-US">httpsessionid</span><span style="'Courier New';">的；</span></p>
<p class="MsoNormal" style="list 18.0pt;"><span style="0pt;" lang="EN-US"><span style="Ignore;">4、<span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="0pt;" lang="EN-US">scriptSessionId</span></p>
<p class="MsoNormal" style="18pt;"><span style="'Courier New';">页面</span><span style="0pt;" lang="EN-US">sessionid</span><span style="'Courier New';">，由</span><span style="0pt;" lang="EN-US">origScriptSessionId</span><span style="'Courier New';">加上一个随机数生成；它是客户端发给</span><span style="0pt;" lang="EN-US">server</span><span style="'Courier New';">的；每次发送值都不相同；</span></p>
<p class="MsoNormal" style="list 18.0pt;"><span style="0pt;" lang="EN-US"><span style="Ignore;">5、<span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="0pt;" lang="EN-US">preHooks</span></p>
<p class="MsoNormal" style="18pt;"><span style="'Courier New';">前钩方法</span><span style="0pt;"> </span><span style="'Courier New';">在</span><span style="0pt;" lang="EN-US">dwr</span><span style="'Courier New';">进行远程方法调用的之前调用</span></p>
<p class="MsoNormal" style="list 18.0pt;"><span style="0pt;" lang="EN-US"><span style="Ignore;">6、<span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="0pt;" lang="EN-US">postHooks</span></p>
<p class="MsoNormal" style="18pt;"><span style="'Courier New';">后钩方法</span><span style="0pt;"> </span><span style="'Courier New';">在</span><span style="0pt;" lang="EN-US">dwr</span><span style="'Courier New';">进行远程方法调用的之后调用；</span></p>
<p class="MsoNormal" style="list 18.0pt;"><span style="0pt;" lang="EN-US"><span style="Ignore;">7、<span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="0pt;" lang="EN-US">DWREngine.beginBatch()</span></p>
<p class="MsoNormal" style="18pt;"><span style="'Courier New';">开始批处理</span><span style="0pt;" lang="EN-US">; </span><span style="'Courier New';">包装请求头</span></p>
<p class="MsoNormal" style="list 18.0pt;"><span style="0pt;" lang="EN-US"><span style="Ignore;">8、<span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="0pt;" lang="EN-US">DWREngine.endBatch()</span></p>
<p class="MsoNormal" style="18pt;"><span style="'Courier New';">提交批处理</span><span style="0pt;" lang="EN-US">; </span></p>
<p class="MsoNormal" style="list 18.0pt;"><span style="0pt;" lang="EN-US"><span style="Ignore;">9、<span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="0pt;" lang="EN-US">rpcType</span></p>
<p class="MsoNormal" style="18pt;"><span style="0pt;" lang="EN-US">dwr</span><span style="'Courier New';">的请求类型；</span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">DWREngine.defaultMessageHandler(abc);</span><span style="'Courier New';">默认的消息句柄</span><span style="0pt;" lang="EN-US">; </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">DWREngine.setTextHtmlHandler;</span><span style="'Courier New';">当接收到</span><span style="0pt;" lang="EN-US">html</span><span style="'Courier New';">时发生的事件</span><span style="0pt;" lang="EN-US">; </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">DWREngine.setErrorHandler(abc); </span><span style="'Courier New';">默认错误句柄</span><span style="0pt;" lang="EN-US">; </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">DWREngine.setWarningHandler(abc);</span><span style="'Courier New';">默认警告句柄</span><span style="0pt;" lang="EN-US">; </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">DWREngine.setTimeout(0); </span><span style="'Courier New';">超时时间设置</span><span style="0pt;" lang="EN-US">,</span><span style="'Courier New';">默认是</span><span style="0pt;" lang="EN-US">0; </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">//</span><span style="'Courier New';">三种调用方法</span><span style="0pt;" lang="EN-US">; </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">DWREngine.XMLHttpRequest = 1; </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">DWREngine.IFrame = 2; </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">DWREngine.ScriptTag = 3; </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">DWREngine.setMethod(&lt;1 or 2 or 3&gt;);</span><span style="'Courier New';">设置调用远程的方法</span><span style="0pt;" lang="EN-US">; </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">DWREngine.setVerb = function(&lt;&#8217;GET&#8217; or &#8216;POST&#8217;&gt;);</span><span style="'Courier New';">设置发送数据的方法</span><span style="0pt;" lang="EN-US">; </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">DWREngine.setOrdered(&lt;true or false&gt;);</span><span style="'Courier New';">设置</span><span style="0pt;" lang="EN-US">xhr</span><span style="'Courier New';">的请求按顺序执行</span><span style="0pt;" lang="EN-US">.&lt;</span><span style="'Courier New';">官方强烈建议不要用这个</span><span style="0pt;" lang="EN-US">,</span><span style="'Courier New';">会变的很慢而且无法预测</span><span style="0pt;" lang="EN-US">.&gt; </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US">DWREngine.setAsync (&lt;true or false&gt;);</span><span style="'Courier New';">设置</span><span style="0pt;" lang="EN-US">xhr</span><span style="'Courier New';">的请求方法是否异步</span><span style="0pt;" lang="EN-US">?</span><span style="'Courier New';">默认是</span><span style="0pt;" lang="EN-US">true</span><span style="'Courier New';">（异步）</span><span style="0pt;" lang="EN-US">;</span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="list 19.5pt;"><span style="宋体;" lang="EN-US"><span style="Ignore;">二、</span></span><span style="0pt;" lang="EN-US">url</span><span style="'Courier New';">对应的处理</span><span style="0pt;" lang="EN-US">handler</span></p>
<p class="MsoNormal" style="list 18.0pt;"><span style="Times New Roman;"><span style="'Times New Roman';" lang="EN-US"><span style="Ignore;"><span style="small;">1、</span><span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span lang="EN-US"><span style="small;">createUrlMapping(container, &#8220;/engine.js&#8221;, &#8220;engineHandlerUrl&#8221;, EngineHandler.class);</span></span></span></p>
<p class="MsoNormal" style="list 18.0pt;"><span style="Times New Roman;"><span style="'Times New Roman';" lang="EN-US"><span style="Ignore;"><span style="small;">2、</span><span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span lang="EN-US"><span style="small;">org.directwebremoting.servlet.EngineHandler.java</span></span></span></p>
<p class="MsoNormal" style="18pt;"><span style="'Times New Roman';"><span style="small;">继承了</span></span><span style="silver;" lang="EN-US">FileHandler</span><span style="'Courier New';">，并且</span><span style="0pt;" lang="EN-US">setDynamic(true);</span></p>
<p class="MsoNormal" style="18pt;"><span style="small;"><span style="'Times New Roman';">首先根据</span><span lang="EN-US"><span style="Times New Roman;">/engine.js </span></span><span style="'Times New Roman';">从</span><span lang="EN-US"><span style="Times New Roman;">scriptCache </span></span><span style="'Times New Roman';">里取，如果没有的话根据</span><span lang="EN-US"><span style="Times New Roman;">/org/directwebremoting/engine.js,</span></span><span style="'Times New Roman';">从</span><span lang="EN-US"><span style="Times New Roman;">classpath</span></span><span style="'Times New Roman';">路径加载；从输入流每行过滤</span><span lang="EN-US"><span style="Times New Roman;">${}</span></span><span style="'Times New Roman';">的字符，由</span><span lang="EN-US"><span style="Times New Roman;">LocalUtil</span></span><span style="'Times New Roman';">类替换成真正的内容；</span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">scriptCompressed </span></span><span style="'Times New Roman';">：是否保留</span><span lang="EN-US"><span style="Times New Roman;">javascrpt</span></span><span style="'Times New Roman';">文件中的空行和注释</span><span lang="EN-US"><span style="Times New Roman;">;</span></span></span></p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/51564/20081202235.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>认识安全框架acegi（5）</title>
		<link>http://column.ibeifeng.com/51564/20081114226.shtml</link>
		<comments>http://column.ibeifeng.com/51564/20081114226.shtml#comments</comments>
		<pubDate>Fri, 14 Nov 2008 02:13:27 +0000</pubDate>
		<dc:creator>ikon999</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Web开发]]></category>

		<category><![CDATA[acegi]]></category>

		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=226</guid>
		<description><![CDATA[Acegi称受保护的应用资源为“安全对象”，这包括URL资源和业务类方法。我们知道在Spring AOP中有前置增强、后置增强、异常增强和环绕增强，其中环绕增强的功能最为强大——它不但可以在目标方法被访问前拦截调用，还可以在调用返回前改变返回的结果，甚至抛出异常。Acegi使用环绕增强对安全对象进行保护。 
Acegi通过AbstractSecurityInterceptor（Interceptor：拦截器）为安全对象访问提供一致的工作模型，它按照以下流程进行工作：

 1． 从SecurityContext中取出已经认证过的Authentication（包括权限信息）； 
 2． 通过反射机制，根据目标安全对象和“配置属性”得到访问目标安全对象所需的权限； 
 3． AccessDecisionManager根据Authentication的授权信息和目标安全对象所需权限做出是否有权访问的判断。如果无权访问，Acegi将抛出AccessDeniedException异常，否则到下一步； 
4． 访问安全对象并获取结果（返回值或HTTP响应）； 
5． AbstractSecurityInterceptor可以在结果返回前进行处理：更改结果或抛出异常。 
Acegi称受保护的应用资源为“安全对象”，这包括URL资源和业务类方法。我们知道在Spring AOP中有前置增强、后置增强、异常增强和环绕增强，其中环绕增强的功能最为强大——它不但可以在目标方法被访问前拦截调用，还可以在调用返回前改变返回的结果，甚至抛出异常。Acegi使用环绕增强对安全对象进行保护。 
 Acegi通过AbstractSecurityInterceptor为安全对象访问提供一致的工作模型，它按照以下流程进行工作： 
1． 从SecurityContext中取出已经认证过的Authentication（包括权限信息）； 
2． 通过反射机制，根据目标安全对象和“配置属性”得到访问目标安全对象所需的权限； 
3． AccessDecisionManager根据Authentication的授权信息和目标安全对象所需权限做出是否有权访问的判断。如果无权访问，Acegi将抛出AccessDeniedException异常，否则到下一步； 
4． 访问安全对象并获取结果（返回值或HTTP响应）； 5． AbstractSecurityInterceptor可以在结果返回前进行处理：更改结果或抛出异常。

 
 安全对象和一般对象的区别在于前者通过Acegi的“配置属性”进行了描述，如“/view.jsp=PRIV_COMMON”配置属性就将“/view.jsp”这个URL资源标识为安全对象，它表示用户在访问/view.jsp时，必须拥有PRIV_COMMON这个权限。配置属性通过XML配置文件，注解、数据库等方式提供。安全对象通过配置属性表示为一个权限，这样，Acegi就可以根据Authentication的权限信息获知用户可以访问的哪些安全对象。 
 根据安全对象的性质以及具体实现技术，AbstractSecurityInterceptor拥有以下三个实现类： 
l FilterSecurityInterceptor：对URL资源的安全对象进行调用时，通过该拦截器实施环绕切面。该拦截器使用Servlet过滤器实现AOP切面，它本身就是一个Servlet过滤器； 
l MethodSecurityInterceptor：当调用业务类方法的安全对象时，可通过该拦截器类实施环绕切面； 
AspectJSecurityInterceptor：和MethodSecurityInterceptor类似，它是针对业务类方法的拦截器，只不过它通过AspectJ实施AOP切面。 
]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">称受保护的应用资源为“安全对象”，这包括</span><span lang="EN-US"><span style="Times New Roman;">URL</span></span><span style="'Times New Roman';">资源和业务类方法。我们知道在</span><span lang="EN-US"><span style="Times New Roman;">Spring AOP</span></span><span style="'Times New Roman';">中有前置增强、后置增强、异常增强和环绕增强，其中环绕增强的功能最为强大——它不但可以在目标方法被访问前拦截调用，还可以在调用返回前改变返回的结果，甚至抛出异常。</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">使用环绕增强对安全对象进行保护。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">通过</span><span lang="EN-US"><span style="Times New Roman;">AbstractSecurityInterceptor</span></span><span style="'Times New Roman';">（</span><span lang="EN-US"><span style="Times New Roman;">Interceptor</span></span><span style="'Times New Roman';">：拦截器）为安全对象访问提供一致的工作模型，它按照以下流程进行工作：</span></span></p>
<p class="MsoNormal" style="21.75pt;"><span id="more-226"></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>1</span></span><span style="'Times New Roman';">．</span><span style="Times New Roman;"> </span><span style="'Times New Roman';">从</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">中取出已经认证过的</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">（包括权限信息）；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>2</span></span><span style="'Times New Roman';">．</span><span style="Times New Roman;"> </span><span style="'Times New Roman';">通过反射机制，根据目标安全对象和“配置属性”得到访问目标安全对象所需的权限；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>3</span></span><span style="'Times New Roman';">．</span><span lang="EN-US"><span style="Times New Roman;"> AccessDecisionManager</span></span><span style="'Times New Roman';">根据</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">的授权信息和目标安全对象所需权限做出是否有权访问的判断。如果无权访问，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">将抛出</span><span lang="EN-US"><span style="Times New Roman;">AccessDeniedException</span></span><span style="'Times New Roman';">异常，否则到下一步；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">4</span></span><span style="'Times New Roman';">．</span><span style="Times New Roman;"> </span><span style="'Times New Roman';">访问安全对象并获取结果（返回值或</span><span lang="EN-US"><span style="Times New Roman;">HTTP</span></span><span style="'Times New Roman';">响应）；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">5</span></span><span style="'Times New Roman';">．</span><span lang="EN-US"><span style="Times New Roman;"> AbstractSecurityInterceptor</span></span><span style="'Times New Roman';">可以在结果返回前进行处理：更改结果或抛出异常。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">称受保护的应用资源为“安全对象”，这包括</span><span lang="EN-US"><span style="Times New Roman;">URL</span></span><span style="'Times New Roman';">资源和业务类方法。我们知道在</span><span lang="EN-US"><span style="Times New Roman;">Spring AOP</span></span><span style="'Times New Roman';">中有前置增强、后置增强、异常增强和环绕增强，其中环绕增强的功能最为强大——它不但可以在目标方法被访问前拦截调用，还可以在调用返回前改变返回的结果，甚至抛出异常。</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">使用环绕增强对安全对象进行保护。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>Acegi</span></span><span style="'Times New Roman';">通过</span><span lang="EN-US"><span style="Times New Roman;">AbstractSecurityInterceptor</span></span><span style="'Times New Roman';">为安全对象访问提供一致的工作模型，它按照以下流程进行工作：</span><span lang="EN-US"><span style="yes;"><span style="Times New Roman;"> </span></span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">1</span></span><span style="'Times New Roman';">．</span><span style="Times New Roman;"> </span><span style="'Times New Roman';">从</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">中取出已经认证过的</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">（包括权限信息）；</span><span lang="EN-US"><span style="yes;"><span style="Times New Roman;"> </span></span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">2</span></span><span style="'Times New Roman';">．</span><span style="Times New Roman;"> </span><span style="'Times New Roman';">通过反射机制，根据目标安全对象和“配置属性”得到访问目标安全对象所需的权限；</span><span lang="EN-US"><span style="yes;"><span style="Times New Roman;"> </span></span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">3</span></span><span style="'Times New Roman';">．</span><span lang="EN-US"><span style="Times New Roman;"> AccessDecisionManager</span></span><span style="'Times New Roman';">根据</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">的授权信息和目标安全对象所需权限做出是否有权访问的判断。如果无权访问，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">将抛出</span><span lang="EN-US"><span style="Times New Roman;">AccessDeniedException</span></span><span style="'Times New Roman';">异常，否则到下一步；</span><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">4</span></span><span style="'Times New Roman';">．</span><span style="Times New Roman;"> </span><span style="'Times New Roman';">访问安全对象并获取结果（返回值或</span><span lang="EN-US"><span style="Times New Roman;">HTTP</span></span><span style="'Times New Roman';">响应）；</span><span lang="EN-US"><span style="Times New Roman;"> 5</span></span><span style="'Times New Roman';">．</span><span lang="EN-US"><span style="Times New Roman;"> AbstractSecurityInterceptor</span></span><span style="'Times New Roman';">可以在结果返回前进行处理：更改结果或抛出异常。</span></span></p>
<p class="MsoNormal" style="center;" align="center">
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="small;"><span lang="EN-US"><span style="yes;"><span style="Times New Roman;"> </span></span></span><span style="'Times New Roman';">安全对象和一般对象的区别在于前者通过</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">的“配置属性”进行了描述，如“</span><span lang="EN-US"><span style="Times New Roman;">/view.jsp=PRIV_COMMON</span></span><span style="'Times New Roman';">”配置属性就将“</span><span lang="EN-US"><span style="Times New Roman;">/view.jsp</span></span><span style="'Times New Roman';">”这个</span><span lang="EN-US"><span style="Times New Roman;">URL</span></span><span style="'Times New Roman';">资源标识为安全对象，它表示用户在访问</span><span lang="EN-US"><span style="Times New Roman;">/view.jsp</span></span><span style="'Times New Roman';">时，必须拥有</span><span lang="EN-US"><span style="Times New Roman;">PRIV_COMMON</span></span><span style="'Times New Roman';">这个权限。配置属性通过</span><span lang="EN-US"><span style="Times New Roman;">XML</span></span><span style="'Times New Roman';">配置文件，注解、数据库等方式提供。安全对象通过配置属性表示为一个权限，这样，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">就可以根据</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">的权限信息获知用户可以访问的哪些安全对象。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="small;"><span lang="EN-US"><span style="yes;"><span style="Times New Roman;"> </span></span></span><span style="'Times New Roman';">根据安全对象的性质以及具体实现技术，</span><span lang="EN-US"><span style="Times New Roman;">AbstractSecurityInterceptor</span></span><span style="'Times New Roman';">拥有以下三个实现类：</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="list 26.7pt;"><span style="Wingdings;" lang="EN-US"><span style="Ignore;"><span style="small;">l</span><span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="small;"><span lang="EN-US"><span style="Times New Roman;">FilterSecurityInterceptor</span></span><span style="'Times New Roman';">：对</span><span lang="EN-US"><span style="Times New Roman;">URL</span></span><span style="'Times New Roman';">资源的安全对象进行调用时，通过该拦截器实施环绕切面。该拦截器使用</span><span lang="EN-US"><span style="Times New Roman;">Servlet</span></span><span style="'Times New Roman';">过滤器实现</span><span lang="EN-US"><span style="Times New Roman;">AOP</span></span><span style="'Times New Roman';">切面，它本身就是一个</span><span lang="EN-US"><span style="Times New Roman;">Servlet</span></span><span style="'Times New Roman';">过滤器；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="list 26.7pt;"><span style="Wingdings;" lang="EN-US"><span style="Ignore;"><span style="small;">l</span><span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="small;"><span lang="EN-US"><span style="Times New Roman;">MethodSecurityInterceptor</span></span><span style="'Times New Roman';">：当调用业务类方法的安全对象时，可通过该拦截器类实施环绕切面；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p><span style="AR-SA;" lang="EN-US">AspectJSecurityInterceptor</span><span style="AR-SA;">：和</span><span style="AR-SA;" lang="EN-US">MethodSecurityInterceptor</span><span style="AR-SA;">类似，它是针对业务类方法的拦截器，只不过它通过</span><span style="AR-SA;" lang="EN-US">AspectJ</span><span style="AR-SA;">实施</span><span style="AR-SA;" lang="EN-US">AOP</span><span style="AR-SA;">切面。</span><span style="AR-SA;"> </span></p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/51564/20081114226.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>认识安全框架acegi（4）</title>
		<link>http://column.ibeifeng.com/51564/20081114224.shtml</link>
		<comments>http://column.ibeifeng.com/51564/20081114224.shtml#comments</comments>
		<pubDate>Fri, 14 Nov 2008 02:11:36 +0000</pubDate>
		<dc:creator>ikon999</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Web开发]]></category>

		<category><![CDATA[acegi]]></category>

		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=224</guid>
		<description><![CDATA[Acegi支持多种方式的用户认证：如典型的基于数据库的认证、基于LDAP的认证、基于Yale中心认证等方式。不同的认证环境拥有不同的用户认证方式，现在我们先抛开这些具体的细节，考察一下Acegi对受限资源进行访问控制的典型过程： 
 1．你点击一个链接访问一个网页； 
 2．浏览器发送一个请求到服务器，服务器判断出你正在访问一个受保护的资源；

 3．如果此时你并未通过身份认证，服务器发回一个响应提示你进行认证——这个响应可能是一个HTTP响应代码，抑或重定向到一个指定页面； 
 4．根据系统使用认证机制的不同，浏览器或者重定向到一个登录页面中，或者由浏览器通过一些其它的方式获取你的身份信息（如通过BASIC认证对话框、一个Cookie或一个X509证书）； 
 5．浏览器再次将用户身份信息发送到服务器上（可能是一个用户登录表单的HTTP POST信息、也可能是包含认证信息的HTTP报文头）； 
 6．服务器判断用户认证信息是否有效，如果无效，一般情况下，浏览器会要求你继续尝试，这意味着返回第3步。如果有效，则到达下一步； 
 7．服务器重新响应第2步所提交的原始请求，并判断该请求所访问的程序资源是否在你的权限范围内，如果你有权访问，请求将得到正确的执行并返回结果。否则，你将收到一个HTTP 403错误，这意味着你被禁止访问。 
在Acegi框架里，你可以找到对应以上大多数步骤的类，其中ExceptionTranslationFilter、AuthenticationEntryPoint、AuthenticationProvider以及Acegi的认证机制是其中的代表者。 
ExceptionTranslationFilter是一个Acegi的Servlet过滤器，它负责探测抛出的安全异常。当一个未认证用户访问服务器时，Acegi将引发一个Java异常。Java异常本身对HTTP请求以及如何认证用户是一无所知的，ExceptionTranslationFilter适时登场，对这个异常进行处理，启动用户认证的步骤（第3步）。如果已认证用户越权访问一个资源，Acegi也将引发一个Java异常，ExceptionTranslationFilter则将这个异常转换为HTTP 403响应码（第7步）。可见，Acegi通过异常进行通讯，ExceptionTranslationFilter接收这些异常并作出相应的动作。 
当ExceptionTranslationFilter通过Java异常发现用户还未认证时，它到底会将请求重定向哪个页面以要求用户提供认证信息呢？这通过咨询AuthenticationEntryPoint来达到目的——Acegi通过AuthenticationEntryPoint描述登录页面。 
当你的浏览器通过HTTP表单或HTTP报文头向服务器提供用户认证信息时，Acegi需要将这些信息收集到Authentication中，Acegi用“认证机制”描述这一过程。此时，这个新生成Authentication只包含用户提供的认证信息，但并未通过认证。
AuthenticationProvider负责对Authentication进行认证。AuthenticationProvider究竟如何完成这一过程呢？请回忆一下上节我们所介绍的UserDetails和UserDetailsService，大多数AuthenticationProvider通过UserDetailsService获取和未认证的Authentication对应的UserDetails并进行匹配比较来完成这一任务。当用户认证信息匹配时，Authentication被认为是有效的，AuthenticationProvider进一步将UserDetails中权限、ACL等信息拷贝到Authentication。 
当Acegi通过认证机制收集到用户认证信息并填充好Authentication后，Authentication将被保存到SecurityContextHolder中并处理用户的原始请求（第7步）。 
你完全可以抛开Acegi的安全机制，编写自己的Servlet过滤器，使用自己的方案构建Authentication对象并将其放置到SecurityContextHolder中。也许你使用了CMA（Container Managed Authentication：容器管理认证），CMA允许你从ThreadLocal或JNDI中获取用户认证信息，这时你只要获取这些信息并将其转换为Authentication就可以了。
]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">支持多种方式的用户认证：如典型的基于数据库的认证、基于</span><span lang="EN-US"><span style="Times New Roman;">LDAP</span></span><span style="'Times New Roman';">的认证、基于</span><span lang="EN-US"><span style="Times New Roman;">Yale</span></span><span style="'Times New Roman';">中心认证等方式。不同的认证环境拥有不同的用户认证方式，现在我们先抛开这些具体的细节，考察一下</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">对受限资源进行访问控制的典型过程：</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>1</span></span><span style="'Times New Roman';">．你点击一个链接访问一个网页；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>2</span></span><span style="'Times New Roman';">．浏览器发送一个请求到服务器，服务器判断出你正在访问一个受保护的资源；</span></span></p>
<p class="MsoNormal" style="21.75pt;"><span id="more-224"></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>3</span></span><span style="'Times New Roman';">．如果此时你并未通过身份认证，服务器发回一个响应提示你进行认证——这个响应可能是一个</span><span lang="EN-US"><span style="Times New Roman;">HTTP</span></span><span style="'Times New Roman';">响应代码，抑或重定向到一个指定页面；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>4</span></span><span style="'Times New Roman';">．根据系统使用认证机制的不同，浏览器或者重定向到一个登录页面中，或者由浏览器通过一些其它的方式获取你的身份信息（如通过</span><span lang="EN-US"><span style="Times New Roman;">BASIC</span></span><span style="'Times New Roman';">认证对话框、一个</span><span lang="EN-US"><span style="Times New Roman;">Cookie</span></span><span style="'Times New Roman';">或一个</span><span lang="EN-US"><span style="Times New Roman;">X509</span></span><span style="'Times New Roman';">证书）；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>5</span></span><span style="'Times New Roman';">．浏览器再次将用户身份信息发送到服务器上（可能是一个用户登录表单的</span><span lang="EN-US"><span style="Times New Roman;">HTTP POST</span></span><span style="'Times New Roman';">信息、也可能是包含认证信息的</span><span lang="EN-US"><span style="Times New Roman;">HTTP</span></span><span style="'Times New Roman';">报文头）；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>6</span></span><span style="'Times New Roman';">．服务器判断用户认证信息是否有效，如果无效，一般情况下，浏览器会要求你继续尝试，这意味着返回第</span><span lang="EN-US"><span style="Times New Roman;">3</span></span><span style="'Times New Roman';">步。如果有效，则到达下一步；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>7</span></span><span style="'Times New Roman';">．服务器重新响应第</span><span lang="EN-US"><span style="Times New Roman;">2</span></span><span style="'Times New Roman';">步所提交的原始请求，并判断该请求所访问的程序资源是否在你的权限范围内，如果你有权访问，请求将得到正确的执行并返回结果。否则，你将收到一个</span><span lang="EN-US"><span style="Times New Roman;">HTTP 403</span></span><span style="'Times New Roman';">错误，这意味着你被禁止访问。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">在</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">框架里，你可以找到对应以上大多数步骤的类，其中</span><span lang="EN-US"><span style="Times New Roman;">ExceptionTranslationFilter</span></span><span style="'Times New Roman';">、</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationEntryPoint</span></span><span style="'Times New Roman';">、</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationProvider</span></span><span style="'Times New Roman';">以及</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">的认证机制是其中的代表者。</span><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">ExceptionTranslationFilter</span></span><span style="'Times New Roman';">是一个</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">的</span><span lang="EN-US"><span style="Times New Roman;">Servlet</span></span><span style="'Times New Roman';">过滤器，它负责探测抛出的安全异常。当一个未认证用户访问服务器时，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">将引发一个</span><span lang="EN-US"><span style="Times New Roman;">Java</span></span><span style="'Times New Roman';">异常。</span><span lang="EN-US"><span style="Times New Roman;">Java</span></span><span style="'Times New Roman';">异常本身对</span><span lang="EN-US"><span style="Times New Roman;">HTTP</span></span><span style="'Times New Roman';">请求以及如何认证用户是一无所知的，</span><span lang="EN-US"><span style="Times New Roman;">ExceptionTranslationFilter</span></span><span style="'Times New Roman';">适时登场，对这个异常进行处理，启动用户认证的步骤（第</span><span lang="EN-US"><span style="Times New Roman;">3</span></span><span style="'Times New Roman';">步）。如果已认证用户越权访问一个资源，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">也将引发一个</span><span lang="EN-US"><span style="Times New Roman;">Java</span></span><span style="'Times New Roman';">异常，</span><span lang="EN-US"><span style="Times New Roman;">ExceptionTranslationFilter</span></span><span style="'Times New Roman';">则将这个异常转换为</span><span lang="EN-US"><span style="Times New Roman;">HTTP 403</span></span><span style="'Times New Roman';">响应码（第</span><span lang="EN-US"><span style="Times New Roman;">7</span></span><span style="'Times New Roman';">步）。可见，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">通过异常进行通讯，</span><span lang="EN-US"><span style="Times New Roman;">ExceptionTranslationFilter</span></span><span style="'Times New Roman';">接收这些异常并作出相应的动作。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">当</span><span lang="EN-US"><span style="Times New Roman;">ExceptionTranslationFilter</span></span><span style="'Times New Roman';">通过</span><span lang="EN-US"><span style="Times New Roman;">Java</span></span><span style="'Times New Roman';">异常发现用户还未认证时，它到底会将请求重定向哪个页面以要求用户提供认证信息呢？这通过咨询</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationEntryPoint</span></span><span style="'Times New Roman';">来达到目的——</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">通过</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationEntryPoint</span></span><span style="'Times New Roman';">描述登录页面。</span><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">当你的浏览器通过</span><span lang="EN-US"><span style="Times New Roman;">HTTP</span></span><span style="'Times New Roman';">表单或</span><span lang="EN-US"><span style="Times New Roman;">HTTP</span></span><span style="'Times New Roman';">报文头向服务器提供用户认证信息时，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">需要将这些信息收集到</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">中，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">用“认证机制”描述这一过程。此时，这个新生成</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">只包含用户提供的认证信息，但并未通过认证。</span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">AuthenticationProvider</span></span><span style="'Times New Roman';">负责对</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">进行认证。</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationProvider</span></span><span style="'Times New Roman';">究竟如何完成这一过程呢？请回忆一下上节我们所介绍的</span><span lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">和</span><span lang="EN-US"><span style="Times New Roman;">UserDetailsService</span></span><span style="'Times New Roman';">，大多数</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationProvider</span></span><span style="'Times New Roman';">通过</span><span lang="EN-US"><span style="Times New Roman;">UserDetailsService</span></span><span style="'Times New Roman';">获取和未认证的</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">对应的</span><span lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">并进行匹配比较来完成这一任务。当用户认证信息匹配时，</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">被认为是有效的，</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationProvider</span></span><span style="'Times New Roman';">进一步将</span><span lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">中权限、</span><span lang="EN-US"><span style="Times New Roman;">ACL</span></span><span style="'Times New Roman';">等信息拷贝到</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">当</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">通过认证机制收集到用户认证信息并填充好</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">后，</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">将被保存到</span><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder</span></span><span style="'Times New Roman';">中并处理用户的原始请求（第</span><span lang="EN-US"><span style="Times New Roman;">7</span></span><span style="'Times New Roman';">步）。</span><span style="Times New Roman;"> </span></span></p>
<p><span style="AR-SA;">你完全可以抛开</span><span style="AR-SA;" lang="EN-US">Acegi</span><span style="AR-SA;">的安全机制，编写自己的</span><span style="AR-SA;" lang="EN-US">Servlet</span><span style="AR-SA;">过滤器，使用自己的方案构建</span><span style="AR-SA;" lang="EN-US">Authentication</span><span style="AR-SA;">对象并将其放置到</span><span style="AR-SA;" lang="EN-US">SecurityContextHolder</span><span style="AR-SA;">中。也许你使用了</span><span style="AR-SA;" lang="EN-US">CMA</span><span style="AR-SA;">（</span><span style="AR-SA;" lang="EN-US">Container Managed Authentication</span><span style="AR-SA;">：容器管理认证），</span><span style="AR-SA;" lang="EN-US">CMA</span><span style="AR-SA;">允许你从</span><span style="AR-SA;" lang="EN-US">ThreadLocal</span><span style="AR-SA;">或</span><span style="AR-SA;" lang="EN-US">JNDI</span><span style="AR-SA;">中获取用户认证信息，这时你只要获取这些信息并将其转换为</span><span style="AR-SA;" lang="EN-US">Authentication</span><span style="AR-SA;">就可以了。</span></p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/51564/20081114224.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>认识安全框架acegi（3）</title>
		<link>http://column.ibeifeng.com/51564/20081114222.shtml</link>
		<comments>http://column.ibeifeng.com/51564/20081114222.shtml#comments</comments>
		<pubDate>Fri, 14 Nov 2008 02:09:59 +0000</pubDate>
		<dc:creator>ikon999</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Web开发]]></category>

		<category><![CDATA[acegi]]></category>

		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=222</guid>
		<description><![CDATA[每个框架都有一些核心的概念，这些概念被固化为类和接口，成为框架的重要组件类。框架的管理类、操作类都在这些组件类的基础上进行操作。在进入Acegi框架的具体学习前，有必要事先了解一下这些承载Acegi框架重要概念的组件类。 
首先，我们要接触是UserDetails接口，它代表一个应用系统的用户，该接口定义了用户安全相关的信息，如用户名/密码，用户是否有效等信息，你可以根据以下接口方法进行相关信息的获取：

String getUsername()：获取用户名； 
String getPassword()：获取密码； 
boolean isAccountNonExpired()：用户帐号是否过期； 
boolean isAccountNonLocked()：用户帐号是否锁定； 
boolean isCredentialsNonExpired()：用户的凭证是否过期； 
boolean isEnabled()：用户是否处于激活状态。 
当以上任何一个判断用户状态的方法都返回false时，用户凭证就被视为无效。 
UserDetails还定义了获取用户权限信息的方法：GrantedAuthority[] getAuthorities()，GrantedAuthority代表用户权限信息，它定义了一个获取权限描述信息（以字符串表示，如PRIV_COMMON）的方法：String getAuthority()。

 
在未使用Acegi之前，我们可能通过类似User、Customer等领域对象表示用户的概念，并在程序中编写相应的用户认证的逻辑。现在，你要做的一个调整是让原先这些代表用户概念的领域类实现UserDetails接口，这样，Acegi就可以通过UserDetails接口访问到用户的信息了。 
UserDetails可能从数据库、LDAP等用户信息资源中返回，这要求有一种机制来完成这项工作，UserDetailsService正是充当这一角色的接口。UserDetailsService接口很简单，仅有一个方法：UserDetails loadUserByUsername(String username) ，这个方法通过用户名获取整个UserDetails对象。 
Authentication代表一个和应用程序交互的待认证用户，Acegi从类似于登录页面、Cookie等处获取待认证的用户信息（一般是用户名密码）自动构造Authentication实例。 


Authentication可以通过Object getPrincipal()获取一个代表用户的对象，这个对象一般可以转换为UserDetails，从中可以取得用户名/密码等信息。在Authentication被AuthenticationManager认证之前，没有任何权限的信息。在通过认证之后，Acegi通过UserDetails将用户对应的权限信息加载到Authentication中。Authentication拥有一个GrantedAuthority[] getAuthorities()方法，通过该方法可以得到用户对应的权限信息。 
Authentication和UserDetails很容易被混淆，因为两者都有用户名/密码及权限的信息，接口方法也很类似。其实Authentication是Acegi进行安全访问控制真正使用的用户安全信息的对象，它拥有两个状态：未认证和已认证。UserDetails是代表一个从用户安全信息源（数据库、LDAP服务器、CA中心）返回的真正用户，Acegi需要将未认证的Authentication和代表真实用户的UserDetails进行匹配比较，通过匹配比较（简单的情况下是用户名/密码是否一致）后，Acegi将UserDetails中的其它安全信息（如权限、ACL等）拷贝到Authentication中。这样，Acegi安全控制组件在后续的安全访问控制中只和Authentication进行交互。 
由于Acegi对程序资源进行访问安全控制时，一定要事先获取和请求用户对应的Authentication，Acegi框架必须为Authentication提供一个“寓所”，以便在需要时直接从“寓所”把它请出来，作为各种安全管理器决策的依据。 
SecurityContextHolder就是Authentication容身的“寓所”，你可以通过SecurityContextHolder.getContext().getAuthenication()代码获取Authentication。细心观察一下这句代码，你会发现在SecurityContextHolder和Authentication之间存在一个getContext()中介，这个方法返回SecurityContext对象。SecurityContext这个半路杀出来的程咬金有什么特殊的用途呢？我们知道Authentication是用户安全相关的信息，请求线程其它信息（如登录验证码等）则放置在SecurityContext中，构成了一个完整的安全信息上下文。SecurityContext接口提供了获取和设置Authentication的方法： 
u Authentication getAuthentication() 
u void setAuthentication(Authentication authentication)

 
SecurityContextHolder是Acegi框架级的对象，它在内部通过ThreadLocal为请求线程提供线程绑定的SecurityContext对象。这样，任何参与当前请求线程的Acegi安全管理组件、业务服务对象等都可以直接通过SecurityContextHolder.getContext()获取线程绑定的SecurityContext，避免通过方法入参的方式获取用户相关的SecurityContext。 
线程绑定模式对于大多数应用来说是适合的，但是应用本身会创建其它的线程，那么只有主线程可以获得线程绑定SecurityContext，而主线程衍生出的新线程则无法得到线程绑定的SecurityContext。Acegi考虑到了这些不同应用情况，提供了三种绑定SecurityContext的模式： 
n SecurityContextHolder.MODE_THREADLOCAL：SecurityContext绑定到主线程，这是默认的模式； 
n SecurityContextHolder.MODE_GLOBAL：SecurityContext绑定到JVM中，所有线程都使用同一个SecurityContext； 
n SecurityContextHolder.MODE_INHERITABLETHREADLOCAL：：SecurityContext绑定到主线程及由主线程衍生的线程中。 
你可以通过SecurityContextHolder.setStrategyName(String strategyName)方法指定SecurityContext的绑定模式。 
]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">每个框架都有一些核心的概念，这些概念被固化为类和接口，成为框架的重要组件类。框架的管理类、操作类都在这些组件类的基础上进行操作。在进入</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">框架的具体学习前，有必要事先了解一下这些承载</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">框架重要概念的组件类。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">首先，我们要接触是</span><span lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">接口，它代表一个应用系统的用户，该接口定义了用户安全相关的信息，如用户名</span><span lang="EN-US"><span style="Times New Roman;">/</span></span><span style="'Times New Roman';">密码，用户是否有效等信息，你可以根据以下接口方法进行相关信息的获取：</span></span></p>
<p class="MsoNormal" style="21.75pt;"><span id="more-222"></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">String getUsername()</span></span><span style="'Times New Roman';">：获取用户名；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">String getPassword()</span></span><span style="'Times New Roman';">：获取密码；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">boolean isAccountNonExpired()</span></span><span style="'Times New Roman';">：用户帐号是否过期；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">boolean isAccountNonLocked()</span></span><span style="'Times New Roman';">：用户帐号是否锁定；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">boolean isCredentialsNonExpired()</span></span><span style="'Times New Roman';">：用户的凭证是否过期；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">boolean isEnabled()</span></span><span style="'Times New Roman';">：用户是否处于激活状态。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21pt;"><span style="small;"><span style="'Times New Roman';">当以上任何一个判断用户状态的方法都返回</span><span lang="EN-US"><span style="Times New Roman;">false</span></span><span style="'Times New Roman';">时，用户凭证就被视为无效。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">还定义了获取用户权限信息的方法：</span><span lang="EN-US"><span style="Times New Roman;">GrantedAuthority[] getAuthorities()</span></span><span style="'Times New Roman';">，</span><span lang="EN-US"><span style="Times New Roman;">GrantedAuthority</span></span><span style="'Times New Roman';">代表用户权限信息，它定义了一个获取权限描述信息（以字符串表示，如</span><span lang="EN-US"><span style="Times New Roman;">PRIV_COMMON</span></span><span style="'Times New Roman';">）的方法：</span><span lang="EN-US"><span style="Times New Roman;">String getAuthority()</span></span><span style="'Times New Roman';">。</span></span></p>
<p class="MsoNormal" style="center;" align="center">
<p class="MsoNormal" style="21.75pt;"><span lang="EN-US"><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">在未使用</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">之前，我们可能通过类似</span><span lang="EN-US"><span style="Times New Roman;">User</span></span><span style="'Times New Roman';">、</span><span lang="EN-US"><span style="Times New Roman;">Customer</span></span><span style="'Times New Roman';">等领域对象表示用户的概念，并在程序中编写相应的用户认证的逻辑。现在，你要做的一个调整是<span style="red;">让原先这些代表用户概念的领域类实现</span></span><span style="red;" lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">接口</span><span style="'Times New Roman';">，这样，</span><span style="red;" lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">就可以通过</span><span style="red;" lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">接口访问到用户的信息了</span><span style="'Times New Roman';">。</span><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">可能从数据库、</span><span lang="EN-US"><span style="Times New Roman;">LDAP</span></span><span style="'Times New Roman';">等用户信息资源中返回，这要求有一种机制来完成这项工作，</span><span lang="EN-US"><span style="Times New Roman;">UserDetailsService</span></span><span style="'Times New Roman';">正是充当这一角色的接口。</span><span style="red;" lang="EN-US"><span style="Times New Roman;">UserDetailsService</span></span><span style="'Times New Roman';">接口很简单，仅有一个方法：</span><span style="red;" lang="EN-US"><span style="Times New Roman;">UserDetails loadUserByUsername(String username) </span></span><span style="'Times New Roman';">，这个方法通过用户名获取整个</span><span style="red;" lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">对象。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">代表一个和应用程序交互的待认证用户，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">从类似于登录页面、</span><span lang="EN-US"><span style="Times New Roman;">Cookie</span></span><span style="'Times New Roman';">等处获取待认证的用户信息（一般是用户名密码）自动构造</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">实例。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;">
<p class="MsoNormal" style="center;" align="center">
<p class="MsoNormal"><span style="small;"><span style="red;" lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">可以通过</span><span style="red;" lang="EN-US"><span style="Times New Roman;">Object getPrincipal()</span></span><span style="'Times New Roman';">获取一个代表用户的对象，这个对象一般可以转换为</span><span style="red;" lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">，从中可以取得用户名</span><span lang="EN-US"><span style="Times New Roman;">/</span></span><span style="'Times New Roman';">密码等信息。在</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">被</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationManager</span></span><span style="'Times New Roman';">认证之前，没有任何权限的信息。在通过认证之后，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">通过</span><span lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">将用户对应的权限信息加载到</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">中。</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">拥有一个</span><span lang="EN-US"><span style="Times New Roman;">GrantedAuthority[] getAuthorities()</span></span><span style="'Times New Roman';">方法，通过该方法可以得到用户对应的权限信息。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">和</span><span lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">很容易被混淆，因为两者都有用户名</span><span lang="EN-US"><span style="Times New Roman;">/</span></span><span style="'Times New Roman';">密码及权限的信息，接口方法也很类似。其实</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">是</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">进行安全访问控制真正使用的用户安全信息的对象，它拥有两个状态：未认证和已认证。</span><span lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">是代表一个从用户安全信息源（数据库、</span><span lang="EN-US"><span style="Times New Roman;">LDAP</span></span><span style="'Times New Roman';">服务器、</span><span lang="EN-US"><span style="Times New Roman;">CA</span></span><span style="'Times New Roman';">中心）返回的真正用户，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">需要将未认证的</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">和代表真实用户的</span><span lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">进行匹配比较，通过匹配比较（简单的情况下是用户名</span><span lang="EN-US"><span style="Times New Roman;">/</span></span><span style="'Times New Roman';">密码是否一致）后，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">将</span><span lang="EN-US"><span style="Times New Roman;">UserDetails</span></span><span style="'Times New Roman';">中的其它安全信息（如权限、</span><span lang="EN-US"><span style="Times New Roman;">ACL</span></span><span style="'Times New Roman';">等）拷贝到</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">中。这样，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">安全控制组件在后续的安全访问控制中只和</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">进行交互。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">由于</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">对程序资源进行访问安全控制时，一定要事先获取和请求用户对应的</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">框架必须为</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">提供一个“寓所”，以便在需要时直接从“寓所”把它请出来，作为各种安全管理器决策的依据。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder</span></span><span style="'Times New Roman';">就是</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">容身的“寓所”，你可以通过</span><span style="red;" lang="EN-US"><span style="Times New Roman;">SecurityContextHolder.getContext().getAuthenication()</span></span><span style="'Times New Roman';">代码获取</span><span style="red;" lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">。细心观察一下这句代码，你会发现在</span><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder</span></span><span style="'Times New Roman';">和</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">之间存在一个</span><span lang="EN-US"><span style="Times New Roman;">getContext()</span></span><span style="'Times New Roman';">中介，这个方法返回</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">对象。</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">这个半路杀出来的程咬金有什么特殊的用途呢？我们知道</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">是用户安全相关的信息，请求线程其它信息（如登录验证码等）则放置在</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">中，构成了一个完整的安全信息上下文。</span></span><span style="small;"><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">接口提供了获取和设置</span><span lang="EN-US"><span style="Times New Roman;">Authentication</span></span><span style="'Times New Roman';">的方法：</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="list 63.0pt;"><span style="Wingdings;" lang="EN-US"><span style="Ignore;"><span style="small;">u</span><span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span lang="EN-US"><span style="Times New Roman;">Authentication getAuthentication() </span></span></p>
<p class="MsoNormal" style="list 63.0pt;"><span style="Wingdings;" lang="EN-US"><span style="Ignore;"><span style="small;">u</span><span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span lang="EN-US"><span style="Times New Roman;">void setAuthentication(Authentication authentication)</span></span></p>
<p class="MsoNormal" style="center;" align="center">
<p class="MsoNormal" style="21.75pt;"><span lang="EN-US"><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder</span></span><span style="'Times New Roman';">是</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">框架级的对象，它在内部通过</span><span lang="EN-US"><span style="Times New Roman;">ThreadLocal</span></span><span style="'Times New Roman';">为请求线程提供线程绑定的</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">对象。这样，任何参与当前请求线程的</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">安全管理组件、业务服务对象等都可以直接通过</span><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder.getContext()</span></span><span style="'Times New Roman';">获取线程绑定的</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">，避免通过方法入参的方式获取用户相关的</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">线程绑定模式对于大多数应用来说是适合的，但是应用本身会创建其它的线程，那么只有主线程可以获得线程绑定</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">，而主线程衍生出的新线程则无法得到线程绑定的</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">。</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">考虑到了这些不同应用情况，提供了三种绑定</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">的模式：</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="list 42.0pt;"><span style="Wingdings;" lang="EN-US"><span style="Ignore;"><span style="small;">n</span><span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="small;"><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder.MODE_THREADLOCAL</span></span><span style="'Times New Roman';">：</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">绑定到主线程，这是默认的模式；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="list 42.0pt;"><span style="Wingdings;" lang="EN-US"><span style="Ignore;"><span style="small;">n</span><span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="small;"><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder.MODE_GLOBAL</span></span><span style="'Times New Roman';">：</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">绑定到</span><span lang="EN-US"><span style="Times New Roman;">JVM</span></span><span style="'Times New Roman';">中，所有线程都使用同一个</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">；</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="list 42.0pt;"><span style="Wingdings;" lang="EN-US"><span style="Ignore;"><span style="small;">n</span><span style="7pt &quot;Times New Roman&quot;;"> </span></span></span><span style="small;"><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder.MODE_INHERITABLETHREADLOCAL</span></span><span style="'Times New Roman';">：：</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">绑定到主线程及由主线程衍生的线程中。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">你可以通过</span><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder.setStrategyName(String strategyName)</span></span><span style="'Times New Roman';">方法指定</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">的绑定模式。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/51564/20081114222.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>认识安全框架acegi（2）</title>
		<link>http://column.ibeifeng.com/51564/20081114219.shtml</link>
		<comments>http://column.ibeifeng.com/51564/20081114219.shtml#comments</comments>
		<pubDate>Fri, 14 Nov 2008 02:05:43 +0000</pubDate>
		<dc:creator>ikon999</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Web开发]]></category>

		<category><![CDATA[acegi]]></category>

		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=219</guid>
		<description><![CDATA[乘飞机前需要通过安检，乘客必须提供身份证以验证其身份。在通过安检进入候机室后，国航、海航、南航等不同航空公司的飞机陆续到达，但你只能登上机票上对应航班的飞机。在登机后，只能坐在机票对应的座位上——你不能抢占他人的座位，你不能在座位上刻字留念、你不能要求空姐打开机窗…… 
乘飞机的过程最能体现安全控制的流程，我们可以从中找到身份认证、资源访问控制、领域对象安全控制的对应物：安检对应身份认证，登机对应资源访问控制，而按号就座则对应领域对象安全控制。

Acegi通过两个组件对象完成以上安全问题的处理：AuthenticationManager（认证管理器）、AccessDecisionManager（访问控制管理器）。

SecurityContextHolder是框架级的容器，它保存着和所有用户关联SecurityContext实例，SecurityContext承载着用户（也称认证主体）的身份信息的权限信息， AuthenticationManager、AccessDecisionManager将据此进行安全访问控制。 
SecurityContext的认证主体安全信息在一个HTTP请求线程的多个调用之间是共享的（通过ThreadLocal），但它不能在多个请求之间保持共享。为了解决这个问题，Acegi将认证主体安全信息缓存于HttpSession中，当用户请求一个受限的资源时，Acegi通过HttpSessionContextIntegrationFilter（Integration：集成、整合）将认证主体信息从HttpSession中加载到SecurityContext实例中，认证主体关联的SecurityContext实例保存在Acegi容器级的SecurityContextHolder里。当请求结束之后，HttpSessionContextIntegrationFilter执行相反的操作，将SecurityContext中的认证主体安全信息重新转存到HttpSession中，然后从SecurityContextHolder中清除对应的SecurityContext实例。通过HttpSession转存机制，用户的安全信息就可以在多个HTTP请求间共享，同时保证SecurityContextHolder中仅保存当前有用的用户安全信息。

当用户请求一个受限的资源时，AuthenticationManager首先开始工作，它象一个安检入口，对用户身份进行核查，用户必须提供身份认证的凭证（一般是用户名/密码）。在进行身份认证时，AuthenticationManager将身份认证的工作委托给多个AuthenticationProvider。因为在具体的系统中，用户身份可能存储在不同的用户信息安全系统中（如数据库、CA中心、LDAP服务器），不同用户信息安全系统需要不同的AuthenticationProvider执行；诸如用户信息查询、用户身份判断、用户授权信息获取等工作。只要有一个AuthenticationProvider可以识别用户的身份，AuthenticationManager就通过用户身份认证，并将用户的授权信息放入到SecurityContext中。 
当用户通过身份认证后，试图访问某个受限的程序资源时，AccessDecisionManager开始工作。AccessDecisionManager采用民主决策机制判断用户是否有权访问目标程序资源，它包含了多个AccessDecisionVoter。在访问决策时每个AccessDecisionVoter都拥有投票权，AccessDecisionManager统计投票结果，并按照某种决策方式根据这些投票结果决定最终是否向用户开放受限资源的访问。
]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal" style="21pt;"><span style="small;"><span style="'Times New Roman';">乘飞机前需要通过安检，乘客必须提供身份证以验证其身份。在通过安检进入候机室后，国航、海航、南航等不同航空公司的飞机陆续到达，但你只能登上机票上对应航班的飞机。在登机后，只能坐在机票对应的座位上——你不能抢占他人的座位，你不能在座位上刻字留念、你不能要求空姐打开机窗……</span><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="21pt;"><span style="small;"><span style="'Times New Roman';">乘飞机的过程最能体现安全控制的流程，我们可以从中找到身份认证、资源访问控制、领域对象安全控制的对应物：安检对应身份认证，登机对应资源访问控制，而按号就座则对应领域对象安全控制。</span></span></p>
<p class="MsoNormal" style="21pt;"><span id="more-219"></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">通过两个组件对象完成以上安全问题的处理：</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationManager</span></span><span style="'Times New Roman';">（认证管理器）、</span><span lang="EN-US"><span style="Times New Roman;">AccessDecisionManager</span></span><span style="'Times New Roman';">（访问控制管理器）。</span></span></p>
<p class="MsoNormal" style="21.75pt;">
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder</span></span><span style="'Times New Roman';">是框架级的容器，它保存着和所有用户关联</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">实例，</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">承载着用户（也称认证主体）的身份信息的权限信息，</span><span lang="EN-US"><span style="Times New Roman;"> AuthenticationManager</span></span><span style="'Times New Roman';">、</span><span lang="EN-US"><span style="Times New Roman;">AccessDecisionManager</span></span><span style="'Times New Roman';">将据此进行安全访问控制。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">的认证主体安全信息在一个</span><span lang="EN-US"><span style="Times New Roman;">HTTP</span></span><span style="'Times New Roman';">请求线程的多个调用之间是共享的（通过</span><span lang="EN-US"><span style="Times New Roman;">ThreadLocal</span></span><span style="'Times New Roman';">），但它不能在多个请求之间保持共享。为了解决这个问题，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">将认证主体安全信息缓存于</span><span lang="EN-US"><span style="Times New Roman;">HttpSession</span></span><span style="'Times New Roman';">中，当用户请求一个受限的资源时，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">通过</span><span lang="EN-US"><span style="Times New Roman;">HttpSessionContextIntegrationFilter</span></span><span style="'Times New Roman';">（</span><span lang="EN-US"><span style="Times New Roman;">Integration</span></span><span style="'Times New Roman';">：集成、整合）将认证主体信息从</span><span lang="EN-US"><span style="Times New Roman;">HttpSession</span></span><span style="'Times New Roman';">中加载到</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">实例中，认证主体关联的</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">实例保存在</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">容器级的</span><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder</span></span><span style="'Times New Roman';">里。当请求结束之后，</span><span lang="EN-US"><span style="Times New Roman;">HttpSessionContextIntegrationFilter</span></span><span style="'Times New Roman';">执行相反的操作，将</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">中的认证主体安全信息重新转存到</span><span lang="EN-US"><span style="Times New Roman;">HttpSession</span></span><span style="'Times New Roman';">中，然后从</span><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder</span></span><span style="'Times New Roman';">中清除对应的</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">实例。通过</span><span lang="EN-US"><span style="Times New Roman;">HttpSession</span></span><span style="'Times New Roman';">转存机制，用户的安全信息就可以在多个</span><span lang="EN-US"><span style="Times New Roman;">HTTP</span></span><span style="'Times New Roman';">请求间共享，同时保证</span><span lang="EN-US"><span style="Times New Roman;">SecurityContextHolder</span></span><span style="'Times New Roman';">中仅保存当前有用的用户安全信息。</span></span></p>
<p class="MsoNormal" style="21.75pt;">
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">当用户请求一个受限的资源时，</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationManager</span></span><span style="'Times New Roman';">首先开始工作，它象一个安检入口，对用户身份进行核查，用户必须提供身份认证的凭证（一般是用户名</span><span lang="EN-US"><span style="Times New Roman;">/</span></span><span style="'Times New Roman';">密码）。在进行身份认证时，</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationManager</span></span><span style="'Times New Roman';">将身份认证的工作委托给多个</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationProvider</span></span><span style="'Times New Roman';">。因为在具体的系统中，用户身份可能存储在不同的用户信息安全系统中（如数据库、</span><span lang="EN-US"><span style="Times New Roman;">CA</span></span><span style="'Times New Roman';">中心、</span><span lang="EN-US"><span style="Times New Roman;">LDAP</span></span><span style="'Times New Roman';">服务器），不同用户信息安全系统需要不同的</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationProvider</span></span><span style="'Times New Roman';">执行；诸如用户信息查询、用户身份判断、用户授权信息获取等工作。只要有一个</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationProvider</span></span><span style="'Times New Roman';">可以识别用户的身份，</span><span lang="EN-US"><span style="Times New Roman;">AuthenticationManager</span></span><span style="'Times New Roman';">就通过用户身份认证，并将用户的授权信息放入到</span><span lang="EN-US"><span style="Times New Roman;">SecurityContext</span></span><span style="'Times New Roman';">中。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">当用户通过身份认证后，试图访问某个受限的程序资源时，</span><span lang="EN-US"><span style="Times New Roman;">AccessDecisionManager</span></span><span style="'Times New Roman';">开始工作。</span><span lang="EN-US"><span style="Times New Roman;">AccessDecisionManager</span></span><span style="'Times New Roman';">采用民主决策机制判断用户是否有权访问目标程序资源，它包含了多个</span><span lang="EN-US"><span style="Times New Roman;">AccessDecisionVoter</span></span><span style="'Times New Roman';">。在访问决策时每个</span><span lang="EN-US"><span style="Times New Roman;">AccessDecisionVoter</span></span><span style="'Times New Roman';">都拥有投票权，</span><span lang="EN-US"><span style="Times New Roman;">AccessDecisionManager</span></span><span style="'Times New Roman';">统计投票结果，并按照某种决策方式根据这些投票结果决定最终是否向用户开放受限资源的访问。</span></span></p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/51564/20081114219.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>认识安全框架acegi（1）</title>
		<link>http://column.ibeifeng.com/51564/20081110209.shtml</link>
		<comments>http://column.ibeifeng.com/51564/20081110209.shtml#comments</comments>
		<pubDate>Mon, 10 Nov 2008 09:01:21 +0000</pubDate>
		<dc:creator>ikon999</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[acegi]]></category>

		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=209</guid>
		<description><![CDATA[本系列是讲acegi的基本概念，下系列是acegi实战，主要讲acegi在项目中的具体应用；感兴趣的可以关注
一、 概述 
 对于任何一个完整的应用系统，完善的认证和授权机制是必不可少的。Acegi Security（以下简称Acegi）是一个能为基于Spring的企业应用提供强大而灵活安全访问控制解决方案的框架，Acegi已经成为Spring官方的一个子项目，所以也称为Spring Security。它通过在Spring容器中配置一组Bean，充分利用Spring的IoC和AOP功能，提供声明式安全访问控制的功能。虽然，现在Acegi也可以应用到非Spring的应用程序中，但在Spring中使用Acegi是最自然的方式。 Acegi可以实现业务对象方法级的安全访问控制粒度，它提供了以下三方面的应用程序的安全：

 
URL资源的访问控制 
 如所有用户（包括其名用户）可以访问index.jsp登录页面，而只有授权的用户可以访问/user/addUser.jsp页面。Acegi允许通过正则表达式或Ant风格的路径表达式定义URL模式，让授权用户访问某一URL匹配模式下的对应URL资源。 
业务类方法的访问控制 
 Spring容器中所有Bean的方法都可以被Acegi管理，如所有用户可以调用BbtForum#getRefinedTopicCount()方法，而只有授权用户可以调用BbtForum#addTopic()方法。 
领域对象的访问控制 
 业务类方法代表一个具体的业务操作，比如更改、删除、审批等，业务类方法访问控制解决了用户是否有调用某种操作的权限，但并未对操作的客体（领域对象）进行控制。对于我们的论坛应用来说，用户可以调用BbtForum#updateUser(User user)方法更改用户注册信息，但应该仅限于更改自己的用户信息，也即调用BbtForum#updateUser()所操作的User这个领域对象必须是受限的。 
 
 Acegi通过多个不同用途的Servlet过滤器对URL资源进行保护，在请求受保护的URL资源前，Acegi的Servlet过滤器判断用户是否有权访问目标资源，授权者被开放访问，而未未被授权者将被阻挡在大门之外。 
 Acegi通过Spring AOP对容器中Bean的受控方法进行拦截，当用户的请求引发调用Bean的受控方法时，Acegi的方法拦截器开始工作，阻止未授权者的调用。  
 对领域对象的访问控制建立在对Bean方法保护的基础上，在最终开放目标Bean方法的执行前，Acegi将检查用户的ACL（Aeccess Control List：访问控制列表）是否包含正要进行操作的领域对象，只有领域对象被授权时，用户才可以使用Bean方法对领域对象进行处理。此外，Acegi还可以对Bean方法返回的结果进行过滤，将一些不在当前用户访问权限范围内的领域对象剔除掉——即传统的数据可视域范围的控制。一般来说，使用Acegi控制数据可视域未非理想的选择，相反通过传统的动态SQL的解决方案往往更加简单易行。 
从本质特性上来说，Servlet过滤器就是最原始的原生态AOP，所以我们可以说Acegi不但对业务类方法、领域对象访问控制采用了AOP技术方案，对URL资源的访问控制也使用了AOP的技术方案。使用AOP技术方案的框架是令人振奋的，这意味着，开发者可以在应用程序业务功能开发完毕后，轻松地通过Acegi给应用程序穿上安全保护的“铁布衫”。 
]]></description>
			<content:encoded><![CDATA[<p><strong>本系列是讲acegi的基本概念，下系列是acegi实战，主要讲acegi在项目中的具体应用；感兴趣的可以关注</strong></p>
<p class="MsoNormal" style="list 21.0pt;"><strong><span style="宋体;" lang="EN-US"><span style="Ignore;"><span style="Times New Roman;"><span style="small;">一、</span><span style="7pt &quot;Times New Roman&quot;;"> </span></span></span></span></strong><strong><span style="small;"><span style="'Times New Roman';">概述</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></strong></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="small;"><span lang="EN-US"><span style="yes;"><span style="Times New Roman;"> </span></span></span><span style="'Times New Roman';">对于任何一个完整的应用系统，完善的认证和授权机制是必不可少的。</span><span lang="EN-US"><span style="Times New Roman;">Acegi Security</span></span><span style="'Times New Roman';">（以下简称</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">）是一个能为基于</span><span lang="EN-US"><span style="Times New Roman;">Spring</span></span><span style="'Times New Roman';">的企业应用提供强大而灵活安全访问控制解决方案的框架，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">已经成为</span><span lang="EN-US"><span style="Times New Roman;">Spring</span></span><span style="'Times New Roman';">官方的一个子项目，所以也称为</span><span lang="EN-US"><span style="Times New Roman;">Spring Security</span></span><span style="'Times New Roman';">。它通过在</span><span lang="EN-US"><span style="Times New Roman;">Spring</span></span><span style="'Times New Roman';">容器中配置一组</span><span lang="EN-US"><span style="Times New Roman;">Bean</span></span><span style="'Times New Roman';">，充分利用</span><span lang="EN-US"><span style="Times New Roman;">Spring</span></span><span style="'Times New Roman';">的</span><span lang="EN-US"><span style="Times New Roman;">IoC</span></span><span style="'Times New Roman';">和</span><span lang="EN-US"><span style="Times New Roman;">AOP</span></span><span style="'Times New Roman';">功能，提供声明式安全访问控制的功能。虽然，现在</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">也可以应用到非</span><span lang="EN-US"><span style="Times New Roman;">Spring</span></span><span style="'Times New Roman';">的应用程序中，但在</span><span lang="EN-US"><span style="Times New Roman;">Spring</span></span><span style="'Times New Roman';">中使用</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">是最自然的方式。</span><span lang="EN-US"><span style="Times New Roman;"> Acegi</span></span><span style="'Times New Roman';">可以实现业务对象方法级的安全访问控制粒度，它提供了以下三方面的应用程序的安全：</span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span id="more-209"></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="list 11.35pt;"><span style="Wingdings;" lang="EN-US"><span style="Ignore;"></span></span><span style="small;"><strong><span lang="EN-US"><span style="Times New Roman;">URL</span></span><span style="'Times New Roman';">资源的访问控制</span></strong><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="small;"><span lang="EN-US"><span style="yes;"><span style="Times New Roman;"> </span></span></span><span style="'Times New Roman';">如所有用户（包括其名用户）可以访问</span><span lang="EN-US"><span style="Times New Roman;">index.jsp</span></span><span style="'Times New Roman';">登录页面，而只有授权的用户可以访问</span><span lang="EN-US"><span style="Times New Roman;">/user/addUser.jsp</span></span><span style="'Times New Roman';">页面。</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">允许通过正则表达式或</span><span lang="EN-US"><span style="Times New Roman;">Ant</span></span><span style="'Times New Roman';">风格的路径表达式定义</span><span lang="EN-US"><span style="Times New Roman;">URL</span></span><span style="'Times New Roman';">模式，让授权用户访问某一</span><span lang="EN-US"><span style="Times New Roman;">URL</span></span><span style="'Times New Roman';">匹配模式下的对应</span><span lang="EN-US"><span style="Times New Roman;">URL</span></span><span style="'Times New Roman';">资源。</span><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="list 11.35pt;"><span style="Wingdings;" lang="EN-US"><span style="Ignore;"></span></span><span style="small;"><strong><span style="'Times New Roman';">业务类方法的访问控制</span></strong><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>Spring</span></span><span style="'Times New Roman';">容器中所有</span><span lang="EN-US"><span style="Times New Roman;">Bean</span></span><span style="'Times New Roman';">的方法都可以被</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">管理，如所有用户可以调用</span><span lang="EN-US"><span style="Times New Roman;">BbtForum#getRefinedTopicCount()</span></span><span style="'Times New Roman';">方法，而只有授权用户可以调用</span><span lang="EN-US"><span style="Times New Roman;">BbtForum#addTopic()</span></span><span style="'Times New Roman';">方法。</span><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="list 11.35pt;"><span style="Wingdings;" lang="EN-US"><span style="Ignore;"></span></span><span style="small;"><strong><span style="'Times New Roman';">领域对象的访问控制</span></strong><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="small;"><span lang="EN-US"><span style="yes;"><span style="Times New Roman;"> </span></span></span><span style="'Times New Roman';">业务类方法代表一个具体的业务操作，比如更改、删除、审批等，业务类方法访问控制解决了用户是否有调用某种操作的权限，但并未对操作的客体（领域对象）进行控制。对于我们的论坛应用来说，用户可以调用</span><span lang="EN-US"><span style="Times New Roman;">BbtForum#updateUser(User user)</span></span><span style="'Times New Roman';">方法更改用户注册信息，但应该仅限于更改自己的用户信息，也即调用</span><span lang="EN-US"><span style="Times New Roman;">BbtForum#updateUser()</span></span><span style="'Times New Roman';">所操作的</span><span lang="EN-US"><span style="Times New Roman;">User</span></span><span style="'Times New Roman';">这个领域对象必须是受限的。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>Acegi</span></span><span style="'Times New Roman';">通过多个不同用途的</span><span lang="EN-US"><span style="Times New Roman;">Servlet</span></span><span style="'Times New Roman';">过滤器对</span><span lang="EN-US"><span style="Times New Roman;">URL</span></span><span style="'Times New Roman';">资源进行保护，在请求受保护的</span><span lang="EN-US"><span style="Times New Roman;">URL</span></span><span style="'Times New Roman';">资源前，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">的</span><span lang="EN-US"><span style="Times New Roman;">Servlet</span></span><span style="'Times New Roman';">过滤器判断用户是否有权访问目标资源，授权者被开放访问，而未未被授权者将被阻挡在大门之外。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="small;"><span lang="EN-US"><span style="Times New Roman;"><span style="yes;"> </span>Acegi</span></span><span style="'Times New Roman';">通过</span><span lang="EN-US"><span style="Times New Roman;">Spring AOP</span></span><span style="'Times New Roman';">对容器中</span><span lang="EN-US"><span style="Times New Roman;">Bean</span></span><span style="'Times New Roman';">的受控方法进行拦截，当用户的请求引发调用</span><span lang="EN-US"><span style="Times New Roman;">Bean</span></span><span style="'Times New Roman';">的受控方法时，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">的方法拦截器开始工作，阻止未授权者的调用。</span><span style="Times New Roman;"> <span lang="EN-US"><span style="yes;"> </span></span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="small;"><span lang="EN-US"><span style="yes;"><span style="Times New Roman;"> </span></span></span><span style="'Times New Roman';">对领域对象的访问控制建立在对</span><span lang="EN-US"><span style="Times New Roman;">Bean</span></span><span style="'Times New Roman';">方法保护的基础上，在最终开放目标</span><span lang="EN-US"><span style="Times New Roman;">Bean</span></span><span style="'Times New Roman';">方法的执行前，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">将检查用户的</span><span lang="EN-US"><span style="Times New Roman;">ACL</span></span><span style="'Times New Roman';">（</span><span lang="EN-US"><span style="Times New Roman;">Aeccess Control List</span></span><span style="'Times New Roman';">：访问控制列表）是否包含正要进行操作的领域对象，只有领域对象被授权时，用户才可以使用</span><span lang="EN-US"><span style="Times New Roman;">Bean</span></span><span style="'Times New Roman';">方法对领域对象进行处理。此外，</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">还可以对</span><span lang="EN-US"><span style="Times New Roman;">Bean</span></span><span style="'Times New Roman';">方法返回的结果进行过滤，将一些不在当前用户访问权限范围内的领域对象剔除掉——即传统的数据可视域范围的控制。一般来说，使用</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">控制数据可视域未非理想的选择，相反通过传统的动态</span><span lang="EN-US"><span style="Times New Roman;">SQL</span></span><span style="'Times New Roman';">的解决方案往往更加简单易行。</span><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="21.75pt;"><span style="small;"><span style="'Times New Roman';">从本质特性上来说，</span><span lang="EN-US"><span style="Times New Roman;">Servlet</span></span><span style="'Times New Roman';">过滤器就是最原始的原生态</span><span lang="EN-US"><span style="Times New Roman;">AOP</span></span><span style="'Times New Roman';">，所以我们可以说</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">不但对业务类方法、领域对象访问控制采用了</span><span lang="EN-US"><span style="Times New Roman;">AOP</span></span><span style="'Times New Roman';">技术方案，对</span><span lang="EN-US"><span style="Times New Roman;">URL</span></span><span style="'Times New Roman';">资源的访问控制也使用了</span><span lang="EN-US"><span style="Times New Roman;">AOP</span></span><span style="'Times New Roman';">的技术方案。使用</span><span lang="EN-US"><span style="Times New Roman;">AOP</span></span><span style="'Times New Roman';">技术方案的框架是令人振奋的，这意味着，开发者可以在应用程序业务功能开发完毕后，轻松地通过</span><span lang="EN-US"><span style="Times New Roman;">Acegi</span></span><span style="'Times New Roman';">给应用程序穿上安全保护的“铁布衫”。</span><span lang="EN-US"><span style="Times New Roman;"> </span></span></span></p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/51564/20081110209.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>深入dwr2之二   Dwr2页面请求处理机制分析之util.js</title>
		<link>http://column.ibeifeng.com/51564/20081017168.shtml</link>
		<comments>http://column.ibeifeng.com/51564/20081017168.shtml#comments</comments>
		<pubDate>Fri, 17 Oct 2008 07:32:49 +0000</pubDate>
		<dc:creator>ikon999</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Web开发]]></category>

		<category><![CDATA[ajax]]></category>

		<category><![CDATA[dwr]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=168</guid>
		<description><![CDATA[ 前一篇分析了dwr2对log的处理，请参见dwr2的日志代码分析；那么下面我们来进一步来分析一下它对页面的请求是如何处理的；这一章主要来讲解一下util.js文件。
 大家都知道util.js文件是包含在dwr.jar文件的org.directwebremoting包里，那么页面是如何访问到它的呢？
1、  首先，我们在某个页面需要使用dwr功能时，需要引入
&#60;script type=&#8221;text/javascript&#8221; src=&#8221;dwr/util.js&#8221;&#62;&#60;/script&#62;
这样对&#8221;dwr/util.js&#8221;的请求，统一由org.directwebremoting.servlet.DwrServlet的doget（）、doPost（）方法来处理；

2、  dopost方法调用UrlProcessor的handle（）方法处理；
UrlProcessor的handle方法在执行时，先取得请求路径，然后根据请求路径，从urlMapping里取得相应的页面处理handler类，由这个handler类来处理请求和响应，也就是说&#8221;dwr/util.js&#8221;请求对应一个handler类来处理，&#8221;dwr/engine.js&#8221;由另外一个handler来处理，关于对engine.js的请求处理，我们在下一章里来讲解；
UrlProcessor的urlMapping类里的key 、value数据，是dwrservlet在container初始化时填入的；DefaultContainer――》setupFinished（）――》callInitializingBeans（）（这个方法是把container里的实现了InitializingBean接口的bean都执行了afterContainerSetup方法；UrlProcessor是实现了InitializingBean接口，它的afterContainerSetup方法，就是将DefaultContainer初始化时，初始的urlmapping值注入到自己的urlmap里）；
3、  dwr/util.js对应的处理handler
处理util.js的handler是：org.directwebremoting.servlet.UtilHandler
在org.directwebremoting.impl.ContainerUtill类里你可以看到，它们之间的对应关系
createUrlMapping(container, &#8220;/util.js&#8221;, &#8220;utilHandlerUrl&#8221;, UtilHandler.class);
UtilHandler继承了FileHandler，它寻找到jar下的util.js,然后以文件流的形式读入，最后作为响应输出到页面；通常只读取一次，因为在第一次读取时，它会把文件内容保存到一个map类型的scriptCache里，缓存起来；以后访问的时候就直接从scriptCache里取；
具体详细细节请参见FileHandler的public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException方法；
Util.js作为静态js文件，适合于缓存起来，没必要每次都去从文件里读取，提高效率；
]]></description>
			<content:encoded><![CDATA[<p> 前一篇分析了dwr2对log的处理，请参见dwr2的日志代码分析；那么下面我们来进一步来分析一下它对页面的请求是如何处理的；这一章主要来讲解一下util.js文件。<br />
 大家都知道util.js文件是包含在dwr.jar文件的org.directwebremoting包里，那么页面是如何访问到它的呢？</p>
<p>1、  首先，我们在某个页面需要使用dwr功能时，需要引入<br />
&lt;script type=&#8221;text/javascript&#8221; src=&#8221;dwr/util.js&#8221;&gt;&lt;/script&gt;<br />
这样对&#8221;dwr/util.js&#8221;的请求，统一由org.directwebremoting.servlet.DwrServlet的doget（）、doPost（）方法来处理；</p>
<p><span id="more-168"></span></p>
<p>2、  dopost方法调用UrlProcessor的handle（）方法处理；<br />
UrlProcessor的handle方法在执行时，先取得请求路径，然后根据请求路径，从urlMapping里取得相应的页面处理handler类，由这个handler类来处理请求和响应，也就是说&#8221;dwr/util.js&#8221;请求对应一个handler类来处理，&#8221;dwr/engine.js&#8221;由另外一个handler来处理，关于对engine.js的请求处理，我们在下一章里来讲解；<br />
UrlProcessor的urlMapping类里的key 、value数据，是dwrservlet在container初始化时填入的；DefaultContainer――》setupFinished（）――》callInitializingBeans（）（这个方法是把container里的实现了InitializingBean接口的bean都执行了afterContainerSetup方法；UrlProcessor是实现了InitializingBean接口，它的afterContainerSetup方法，就是将DefaultContainer初始化时，初始的urlmapping值注入到自己的urlmap里）；</p>
<p>3、  dwr/util.js对应的处理handler<br />
处理util.js的handler是：org.directwebremoting.servlet.UtilHandler<br />
在org.directwebremoting.impl.ContainerUtill类里你可以看到，它们之间的对应关系<br />
createUrlMapping(container, &#8220;/util.js&#8221;, &#8220;utilHandlerUrl&#8221;, UtilHandler.class);<br />
UtilHandler继承了FileHandler，它寻找到jar下的util.js,然后以文件流的形式读入，最后作为响应输出到页面；通常只读取一次，因为在第一次读取时，它会把文件内容保存到一个map类型的scriptCache里，缓存起来；以后访问的时候就直接从scriptCache里取；<br />
具体详细细节请参见FileHandler的public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException方法；<br />
Util.js作为静态js文件，适合于缓存起来，没必要每次都去从文件里读取，提高效率；</p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/51564/20081017168.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>修改对象私有属性</title>
		<link>http://column.ibeifeng.com/51564/20081013112.shtml</link>
		<comments>http://column.ibeifeng.com/51564/20081013112.shtml#comments</comments>
		<pubDate>Mon, 13 Oct 2008 09:54:53 +0000</pubDate>
		<dc:creator>ikon999</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[java反射]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=112</guid>
		<description><![CDATA[如果类没有定义修改私有属性的方法；那么借助java反射机制，通过Class，取得Field，通过设置Field.setAccessible(true) ,就可以调用set方法为私有属性设值；

import java.lang.reflect.Field;
public class ReflectionTest{
 public static void main(String[] args) throws Exception{
 PrivateTest pt = new PrivateTest();
 Class&#60;?&#62; clazz = PrivateTest.class;
 Field field = clazz.getDeclaredField(&#8221;name&#8221;);
 field.setAccessible(true);
 field.set(pt,&#8221;world&#8221;);
 System.out.println(pt.getName());
 }
}
 
class PrivateTest{
 private String name=&#8221;hello&#8221;;
 public String getName(){
 return name;
 }
}
]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal" style="0cm 0cm 0pt;"><span style="small;"><span style="'Times New Roman';">如果类没有定义修改私有属性的方法；那么借助</span><span lang="EN-US"><span style="Times New Roman;">java</span></span><span style="'Times New Roman';">反射机制，通过</span><span lang="EN-US"><span style="Times New Roman;">Class</span></span><span style="'Times New Roman';">，取得</span><span lang="EN-US"><span style="Times New Roman;">Field</span></span><span style="'Times New Roman';">，通过设置</span><span lang="EN-US"><span style="Times New Roman;">Field.setAccessible(true) ,</span></span><span style="'Times New Roman';">就可以调用</span><span lang="EN-US"><span style="Times New Roman;">set</span></span><span style="'Times New Roman';">方法为私有属性设值；</span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span id="more-112"></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="Times New Roman;">import java.lang.reflect.Field;</span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="Times New Roman;">public class ReflectionTest{</span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="small;"><span style="Times New Roman;"><span style="1;"> </span>public static void main(String[] args) throws Exception{</span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="small;"><span style="Times New Roman;"><span style="2;"> </span>PrivateTest pt = new PrivateTest();</span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="small;"><span style="Times New Roman;"><span style="2;"> </span>Class&lt;?&gt; clazz = PrivateTest.class;</span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="small;"><span style="Times New Roman;"><span style="2;"> </span>Field field = clazz.getDeclaredField(&#8221;name&#8221;);</span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="small;"><span style="Times New Roman;"><span style="2;"> </span>field.setAccessible(true);</span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="small;"><span style="Times New Roman;"><span style="2;"> </span>field.set(pt,&#8221;world&#8221;);</span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="small;"><span style="Times New Roman;"><span style="2;"> </span>System.out.println(pt.getName());</span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="small;"><span style="Times New Roman;"><span style="1;"> </span>}</span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="Times New Roman;">}</span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="Times New Roman;"> </span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="Times New Roman;">class PrivateTest{</span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="small;"><span style="Times New Roman;"><span style="1;"> </span>private String name=&#8221;hello&#8221;;</span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="small;"><span style="Times New Roman;"><span style="1;"> </span>public String getName(){</span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="small;"><span style="Times New Roman;"><span style="2;"> </span>return name;</span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="small;"><span style="Times New Roman;"><span style="1;"> </span>}</span></span></span></p>
<p class="MsoNormal" style="0cm 0cm 0pt;"><span lang="EN-US"><span style="Times New Roman;">}</span></span></p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/51564/20081013112.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>ikon999原创：JsUnit测试之三</title>
		<link>http://column.ibeifeng.com/51564/20081009103.shtml</link>
		<comments>http://column.ibeifeng.com/51564/20081009103.shtml#comments</comments>
		<pubDate>Thu, 09 Oct 2008 07:06:22 +0000</pubDate>
		<dc:creator>ikon999</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Web开发]]></category>

		<category><![CDATA[jsunit]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=103</guid>
		<description><![CDATA[十一、 浏览器自动化测试
访问file:///c:/test/jsunit/testRunner.html?testPage=c:/test/test1.html&#38;autoRun=true，就会自动测试test1.html页面里的测试函数；
十二、  根据访问参数改变测试逻辑
1、 访问
file:///c:/test/jsunit/testRunner.html?testPage=c:/test/test1.html&#38;autoRun=true&#38;suite=test2
2、 测试函数：

function suite()
{
 var testSuite = new top.jsUnitTestSuite();
 testSuite.addTestPage(&#8221;../test1.html&#8221;);
 testSuite.addTestPage(&#8221;../test2.html&#8221;);
 testSuite.addTestSuite(secondSuite ());
 return testSuite;
}
function secondSuite(){
 var testSuite = new top.jsUnitTestSuite();
   //取得浏览器访问参数的值，根据此值改变测试逻辑
//1) top.jsUnitParmHash.parameterName;
   //2) top.jsUnitParmHash[‘parameterName’];
   Var suiteToRun = top. jsUnitParmHash.suite;
   If(suiteToRun==’test1’){
   testSuite.addTestPage(&#8221;../test1.html&#8221;);
 }else{
   testSuite.addTestPage(&#8221;../test2.html&#8221;);
 }
 return testSuite;
}
十三、  Ant自动化测试
1、 修改jsunit下的build.xml文件
配置property属性
（1） browserFileNames：浏览器地址；多个可以用逗号隔开；
（2） closeBrowsersAfterTestRuns：执行测试后，是否关闭浏览器；默认true
（3） logsDirectory：日志存放目录
（4） url：测试文件地址；如：
   file:///c:/jsunit/testRunner.html?testPage=c:/jsunit/tests/jsUnitTestSuite.html
 
2、 运行ant standalone_test ，在单机上行运行测试；distributed_test：是分布式远程测试；
]]></description>
			<content:encoded><![CDATA[<p>十一、 浏览器自动化测试<br />
访问<a href="/test/test1.html&amp;autoRun=true">file:///c:/test/jsunit/testRunner.html?testPage=c:/test/test1.html&amp;autoRun=true</a>，就会自动测试test1.html页面里的测试函数；<br />
十二、  根据访问参数改变测试逻辑<br />
1、 访问<br />
<a href="/test/test1.html&amp;autoRun=true&amp;suite=test2">file:///c:/test/jsunit/testRunner.html?testPage=c:/test/test1.html&amp;autoRun=true&amp;suite=test2</a><br />
2、 测试函数：</p>
<p><span id="more-103"></span><br />
function suite()<br />
{<br />
 var testSuite = new top.jsUnitTestSuite();<br />
 testSuite.addTestPage(&#8221;../test1.html&#8221;);<br />
 testSuite.addTestPage(&#8221;../test2.html&#8221;);<br />
 testSuite.addTestSuite(secondSuite ());</p>
<p> return testSuite;<br />
}<br />
function secondSuite(){<br />
 var testSuite = new top.jsUnitTestSuite();<br />
   //取得浏览器访问参数的值，根据此值改变测试逻辑<br />
//1) top.jsUnitParmHash.parameterName;<br />
   //2) top.jsUnitParmHash[‘parameterName’];<br />
   Var suiteToRun = top. jsUnitParmHash.suite;<br />
   If(suiteToRun==’test1’){<br />
   testSuite.addTestPage(&#8221;../test1.html&#8221;);<br />
 }else{<br />
   testSuite.addTestPage(&#8221;../test2.html&#8221;);<br />
 }</p>
<p> return testSuite;<br />
}<br />
十三、  Ant自动化测试<br />
1、 修改jsunit下的build.xml文件<br />
配置property属性<br />
（1） browserFileNames：浏览器地址；多个可以用逗号隔开；<br />
（2） closeBrowsersAfterTestRuns：执行测试后，是否关闭浏览器；默认true<br />
（3） logsDirectory：日志存放目录<br />
（4） url：测试文件地址；如：<br />
   <a href="/jsunit/tests/jsUnitTestSuite.html">file:///c:/jsunit/testRunner.html?testPage=c:/jsunit/tests/jsUnitTestSuite.html</a><br />
 <br />
2、 运行ant standalone_test ，在单机上行运行测试；distributed_test：是分布式远程测试；</p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/51564/20081009103.shtml/feed</wfw:commentRss>
		</item>
		<item>
		<title>ikon999原创：JsUnit测试之二</title>
		<link>http://column.ibeifeng.com/51564/20081008101.shtml</link>
		<comments>http://column.ibeifeng.com/51564/20081008101.shtml#comments</comments>
		<pubDate>Wed, 08 Oct 2008 03:23:09 +0000</pubDate>
		<dc:creator>ikon999</dc:creator>
		
		<category><![CDATA[Java]]></category>

		<category><![CDATA[Web开发]]></category>

		<category><![CDATA[jsunit]]></category>

		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://column.ibeifeng.com/?p=101</guid>
		<description><![CDATA[六、 组织测试函数
 一般地，JsUnit会自动发现测试函数，就像JUnit会发现所有测试方法一样。不过，有些操作系统/浏览器不能合作。如果你发现不能如你所愿地发现测试函数，使用exposeTestFunctionNames()方法就能解决这个问题。
 在测试页面里定义exposeTestFunctionNames方法，jsunit运行器在执行时会寻找exposeTestFunctionNames方法，只执行在此方法内指定的方法；

//向JsUnit框架显式暴露测试函数名
function exposeTestFunctionNames(){
 var tests = new Array();
 tests[0] = &#8220;testAdd&#8221;;
 tests[1] = &#8220;testMinus&#8221;;
 tests[2] = &#8220;testMultiply&#8221;;
 tests[3] = &#8220;testDivide&#8221;;
 return tests;
}
七、  setUpPage函数
此函数会在页面加载后首先执行，并且只执行一次，类似于JUnit4中的@BeforeClass注解
function setUpPage(){
 arg1 = 3;
 arg2 = 6;
//此行代码必须放置在setUpPage的最后，在完成资源加载后告诉JsUnit该函数已执行完毕
 setUpPageStatus = &#8220;complete&#8221;;
}
八、  测试实例
&#60;script type=&#8221;text/javascript&#8221;&#62;
function addNumbers(){
 var v1 = document.getElementById(&#8221;value1&#8243;).value;
 var v2 = document.getElementById(&#8221;value2&#8243;).value;
 var result = addTwoNumbers(v1, v2); 
 
 return result;
}
function addTwoNumbers(value1, value2){
 return parseInt(value1) + parseInt(value2);
}
function setUp() //类比于JUnit中的setUp
{
 document.getElementById(&#8221;value1&#8243;).value = 6;
 document.getElementById(&#8221;value2&#8243;).value = 7;
}
function tearDown() //类比于JUnit中的tearDown
{
 document.getElementById(&#8221;value1&#8243;).value = &#8220;&#8221;;
 document.getElementById(&#8221;value2&#8243;).value = &#8220;&#8221;;
}
function testAddNumbers(){
 var [...]]]></description>
			<content:encoded><![CDATA[<p>六、 组织测试函数<br />
 一般地，JsUnit会自动发现测试函数，就像JUnit会发现所有测试方法一样。不过，有些操作系统/浏览器不能合作。如果你发现不能如你所愿地发现测试函数，使用exposeTestFunctionNames()方法就能解决这个问题。<br />
 在测试页面里定义exposeTestFunctionNames方法，jsunit运行器在执行时会寻找exposeTestFunctionNames方法，只执行在此方法内指定的方法；</p>
<p><span id="more-101"></span><br />
//向JsUnit框架显式暴露测试函数名<br />
function exposeTestFunctionNames(){<br />
 var tests = new Array();</p>
<p> tests[0] = &#8220;testAdd&#8221;;<br />
 tests[1] = &#8220;testMinus&#8221;;<br />
 tests[2] = &#8220;testMultiply&#8221;;<br />
 tests[3] = &#8220;testDivide&#8221;;</p>
<p> return tests;<br />
}<br />
七、  setUpPage函数<br />
此函数会在页面加载后首先执行，并且只执行一次，类似于JUnit4中的@BeforeClass注解<br />
function setUpPage(){<br />
 arg1 = 3;<br />
 arg2 = 6;</p>
<p>//此行代码必须放置在setUpPage的最后，在完成资源加载后告诉JsUnit该函数已执行完毕<br />
 setUpPageStatus = &#8220;complete&#8221;;<br />
}<br />
八、  测试实例<br />
&lt;script type=&#8221;text/javascript&#8221;&gt;<br />
function addNumbers(){<br />
 var v1 = document.getElementById(&#8221;value1&#8243;).value;<br />
 var v2 = document.getElementById(&#8221;value2&#8243;).value;<br />
 var result = addTwoNumbers(v1, v2); <br />
 <br />
 return result;<br />
}</p>
<p>function addTwoNumbers(value1, value2){<br />
 return parseInt(value1) + parseInt(value2);<br />
}<br />
function setUp() //类比于JUnit中的setUp<br />
{<br />
 document.getElementById(&#8221;value1&#8243;).value = 6;<br />
 document.getElementById(&#8221;value2&#8243;).value = 7;</p>
<p>}</p>
<p>function tearDown() //类比于JUnit中的tearDown<br />
{<br />
 document.getElementById(&#8221;value1&#8243;).value = &#8220;&#8221;;<br />
 document.getElementById(&#8221;value2&#8243;).value = &#8220;&#8221;;<br />
}</p>
<p>function testAddNumbers(){<br />
 var result = addNumbers();<br />
 assertEquals(13, result);<br />
}<br />
&lt;/script&gt;<br />
&lt;BODY&gt;</p>
<p>&lt;form&gt;<br />
&lt;input type=&#8221;text&#8221; id=&#8221;value1&#8243;&gt;&lt;br&gt;<br />
&lt;input type=&#8221;text&#8221; id=&#8221;value2&#8243;&gt;&lt;br&gt;<br />
&lt;input type=&#8221;text&#8221; id=&#8221;result&#8221;&gt;&lt;br&gt;<br />
&lt;input type=&#8221;button&#8221; value=&#8221;Add&#8221; onclick=&#8221;addNumbers()&#8221;&gt;</p>
<p>&lt;/BODY&gt;<br />
九、  日志跟踪<br />
? 分3个级别：warn、info和debug<br />
? 测试函数应用<br />
function testAdd()<br />
{<br />
 var result = add(4, 2);<br />
 assertEquals(6, result);<br />
 warn(&#8221;result &#8221; , result);<br />
}<br />
? 在testRunner.htmll里有显示日志级别跟踪的选择；<br />
十、 Jsunit的测试套件<br />
测试套件的函数名一定为suite；<br />
function suite()<br />
{<br />
 var testSuite = new top.jsUnitTestSuite();<br />
//增加的测试页面的路径是相对于测试运行器的路径的（testRunner.html），而不是相对于当前的页面<br />
 testSuite.addTestPage(&#8221;../test1.html&#8221;);<br />
 testSuite.addTestPage(&#8221;../test2.html&#8221;);<br />
   //套件里还可以在包含套件<br />
 testSuite.addTestSuite(secondSuite ());</p>
<p> return testSuite;<br />
}<br />
function secondSuite() //需要与suite定义在同一个页面中<br />
{<br />
 var testSuite = new top.jsUnitTestSuite();</p>
<p> testSuite.addTestPage(&#8221;../test1.html&#8221;);<br />
 testSuite.addTestPage(&#8221;../test2.html&#8221;);</p>
<p> return testSuite;<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://column.ibeifeng.com/51564/20081008101.shtml/feed</wfw:commentRss>
		</item>
	</channel>
</rss>
