⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 portletsessioncontextintegrationinterceptor.java

📁 acegi构造安全的java系统
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * Copyright 2005-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.acegisecurity.context;

import java.lang.reflect.Method;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.portlet.HandlerInterceptor;
import org.springframework.web.portlet.ModelAndView;

/**
 * <p>This interceptor populates the {@link SecurityContextHolder} with information obtained from the
 * <code>PortletSession</code>.  It is applied to both <code>ActionRequest</code>s and
 * <code>RenderRequest</code>s</p>
 *
 * <p>The <code>PortletSession</code> will be queried to retrieve the <code>SecurityContext</code> that should
 * be stored against the <code>SecurityContextHolder</code> for the duration of the portlet request. At the
 * end of the request, any updates made to the <code>SecurityContextHolder</code> will be persisted back to the
 * <code>PortletSession</code> by this interceptor.</p>
 *
 * <p> If a valid <code>SecurityContext</code> cannot be obtained from the <code>PortletSession</code> for
 * whatever reason, a fresh <code>SecurityContext</code> will be created and used instead. The created object
 * will be of the instance defined by the {@link #setContext(Class)} method (which defaults to
 * {@link org.acegisecurity.context.SecurityContextImpl}. </p>
 *
 * <p>A <code>PortletSession</code> may be created by this interceptor if one does not already exist.  If at the
 * end of the portlet request the <code>PortletSession</code> does not exist, one will <b>only</b> be created if
 * the current contents of the <code>SecurityContextHolder</code> are not the {@link java.lang.Object#equals}
 * to a <code>new</code> instance of {@link #context}.  This avoids needless <code>PortletSession</code> creation,
 * and automates the storage of changes made to the <code>SecurityContextHolder</code>. There is one exception to
 * this rule, that is if the {@link #forceEagerSessionCreation} property is <code>true</code>, in which case
 * sessions will always be created irrespective of normal session-minimization logic (the default is
 * <code>false</code>, as this is resource intensive and not recommended).</p>
 *
 * <p>If for whatever reason no <code>PortletSession</code> should <b>ever</b> be created, the
 * {@link #allowSessionCreation} property should be set to <code>false</code>. Only do this if you really need
 * to conserve server memory and ensure all classes using the <code>SecurityContextHolder</code> are designed to
 * have no persistence of the <code>SecurityContext</code> between web requests. Please note that if
 * {@link #forceEagerSessionCreation} is <code>true</code>, the <code>allowSessionCreation</code> must also be
 * <code>true</code> (setting it to <code>false</code> will cause a startup-time error).</p>

 * <p>This interceptor <b>must</b> be executed <b>before</p> any authentication processing mechanisms. These
 * mechanisms (specifically {@link org.acegisecurity.ui.portlet.PortletProcessingInterceptor}) expect the
 * <code>SecurityContextHolder</code> to contain a valid <code>SecurityContext</code> by the time they execute.</p>
 *
 * <p>An important nuance to this interceptor is that (by default) the <code>SecurityContext</code> is stored
 * into the <code>APPLICATION_SCOPE</code> of the <code>PortletSession</code>.  This doesn't just mean you will be
 * sharing it with all the other portlets in your webapp (which is generally a good idea).  It also means that (if
 * you have done all the other appropriate magic), you will share this <code>SecurityContext</code> with servlets in
 * your webapp.  This is very useful if you have servlets serving images or processing AJAX calls from your portlets
 * since they can now use the {@link HttpSessionContextIntegrationFilter} to access the same <code>SecurityContext<code>
 * object from the session.  This allows these calls to be secured as well as the portlet calls.</p>
 *
 * Much of the logic of this interceptor comes from the {@link HttpSessionContextIntegrationFilter} class which
 * fills the same purpose on the servlet side.  Ben Alex and Patrick Burlson are listed as authors here because they
 * are the authors of that class and there are blocks of code that essentially identical between the two. (Making this
 * a good candidate for refactoring someday.)
 *
 * <p>Unlike <code>HttpSessionContextIntegrationFilter</code>, this interceptor does not check to see if it is
 * getting applied multiple times.  This shouldn't be a problem since the application of interceptors is under the
 * control of the Spring Portlet MVC framework and tends to be more explicit and more predictable than the application
 * of filters.  However, you should still be careful to only apply this inteceptor to your request once.</p>
 *
 * @author John A. Lewis
 * @author Ben Alex
 * @author Patrick Burleson
 * @since 2.0
 * @version $Id$
 */
public class PortletSessionContextIntegrationInterceptor
		implements InitializingBean, HandlerInterceptor {

	//~ Static fields/initializers =====================================================================================

	protected static final Log logger = LogFactory.getLog(PortletSessionContextIntegrationInterceptor.class);

	public static final String ACEGI_SECURITY_CONTEXT_KEY = HttpSessionContextIntegrationFilter.ACEGI_SECURITY_CONTEXT_KEY;

	private static final String SESSION_EXISTED = PortletSessionContextIntegrationInterceptor.class.getName() + ".SESSION_EXISTED";
	private static final String CONTEXT_HASHCODE = PortletSessionContextIntegrationInterceptor.class.getName() + ".CONTEXT_HASHCODE";

	//~ Instance fields ================================================================================================

	private Class context = SecurityContextImpl.class;

	private Object contextObject;

	/**
	 * Indicates if this interceptor can create a <code>PortletSession</code> if
	 * needed (sessions are always created sparingly, but setting this value to
	 * <code>false</code> will prohibit sessions from ever being created).
	 * Defaults to <code>true</code>. Do not set to <code>false</code> if
	 * you are have set {@link #forceEagerSessionCreation} to <code>true</code>,
	 * as the properties would be in conflict.
	 */
	private boolean allowSessionCreation = true;

	/**
	 * Indicates if this interceptor is required to create a <code>PortletSession</code>
	 * for every request before proceeding through the request process, even if the
	 * <code>PortletSession</code> would not ordinarily have been created. By
	 * default this is <code>false</code>, which is entirely appropriate for
	 * most circumstances as you do not want a <code>PortletSession</code>
	 * created unless the interceptor actually needs one. It is envisaged the main
	 * situation in which this property would be set to <code>true</code> is
	 * if using other interceptors that depend on a <code>PortletSession</code>
	 * already existing. This is only required in specialized cases, so leave it set to
	 * <code>false</code> unless you have an actual requirement and aware of the
	 * session creation overhead.
	 */
	private boolean forceEagerSessionCreation = false;

	/**
	 * Indicates whether the <code>SecurityContext</code> will be cloned from
	 * the <code>PortletSession</code>. The default is to simply reference
	 * (the default is <code>false</code>). The default may cause issues if
	 * concurrent threads need to have a different security identity from other
	 * threads being concurrently processed that share the same
	 * <code>PortletSession</code>. In most normal environments this does not
	 * represent an issue, as changes to the security identity in one thread is
	 * allowed to affect the security identity in other threads associated with
	 * the same <code>PortletSession</code>. For unusual cases where this is not
	 * permitted, change this value to <code>true</code> and ensure the
	 * {@link #context} is set to a <code>SecurityContext</code> that
	 * implements {@link Cloneable} and overrides the <code>clone()</code>
	 * method.
	 */
	private boolean cloneFromPortletSession = false;

	/**
	 * Indicates wether the <code>APPLICATION_SCOPE</code> mode of the
	 * <code>PortletSession</code> should be used for storing the
	 * <code>SecurityContext</code>.  The default is </code>true</code>.
	 * This allows it to be shared between the portlets in the webapp and
	 * potentially with servlets in the webapp as well. If this is set to
	 * <code>false</code>, then the <code>PORTLET_SCOPE</code> will be used
	 * instead.
	 */
	private boolean useApplicationScopePortletSession = true;


	//~ Constructors ===================================================================================================

	public PortletSessionContextIntegrationInterceptor() throws PortletException {
		this.contextObject = generateNewContext();
	}

	//~ Methods ========================================================================================================

	public void afterPropertiesSet() throws Exception {

		// check that the value of context is legal
		if ((this.context == null) || (!SecurityContext.class.isAssignableFrom(this.context))) {
			throw new IllegalArgumentException("context must be defined and implement SecurityContext "
					+ "(typically use org.acegisecurity.context.SecurityContextImpl; existing class is "
					+ this.context + ")");
		}

		// check that session creation options make sense
		if ((forceEagerSessionCreation == true) && (allowSessionCreation == false)) {
			throw new IllegalArgumentException(
					"If using forceEagerSessionCreation, you must set allowSessionCreation to also be true");
		}
	}

	public boolean preHandleAction(ActionRequest request, ActionResponse response,
			Object handler) throws Exception {
		// call to common preHandle method
		return preHandle(request, response, handler);
	}

	public boolean preHandleRender(RenderRequest request, RenderResponse response,
			Object handler) throws Exception {
		// call to common preHandle method
		return preHandle(request, response, handler);
	}

	public void postHandleRender(RenderRequest request, RenderResponse response,
			Object handler, ModelAndView modelAndView) throws Exception {
		// no-op
	}

	public void afterActionCompletion(ActionRequest request, ActionResponse response,
			Object handler, Exception ex) throws Exception {
		// call to common afterCompletion method
		afterCompletion(request, response, handler, ex);
	}

	public void afterRenderCompletion(RenderRequest request, RenderResponse response,
			Object handler, Exception ex) throws Exception {
		// call to common afterCompletion method
		afterCompletion(request, response, handler, ex);
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -