acegi security



<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
  
  
  
  <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
    <property name="filterInvocationDefinitionSource">
      <value>
        PATTERN_TYPE_APACHE_ANT
        /**=httpSessionContextIntegrationFilter,logoutFilter,authenticationProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
      value>
    property>
  bean>
    
  <bean id="httpSessionContextIntegrationFilter" 
      class="org.acegisecurity.context.HttpSessionContextIntegrationFilter" />	
      
   
   <bean id="logoutFilter"  class="org.acegisecurity.ui.logout.LogoutFilter">
    
    <constructor-arg value="/login.jsp"/> 
    
    <constructor-arg>  
      <list>  
          <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>  
      list>  
    constructor-arg>  
   bean>
      
   
    <bean id="authenticationProcessingFilter" class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilter">  
      
      <property name="authenticationManager" ref="authenticationManager"/>  
      
      <property name="authenticationFailureUrl" value="/login.jsp?login_error=1"/>  
      
      <property name="defaultTargetUrl" value="/userinfo.jsp"/>  
      
      <property name="filterProcessesUrl" value="/j_acegi_security_check"/>  
   bean> 
  
  <bean id="authenticationManager"
    class="org.acegisecurity.providers.ProviderManager">
    <property name="providers">
      <list>
        <ref local="daoAuthenticationProvider" />
      list>
    property>
  bean>
  
  
   
  <bean id="daoAuthenticationProvider"
    class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
    <property name="userDetailsService" ref="inMemDaoImpl" />
  bean>

   
  <bean id="inMemDaoImpl"
    class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
    <property name="userMap">
      <value>
        test=1,ROLE_USER
        lisi=1,ROLE_SUPERVISOR
        zhangsan=1,ROLE_SUPERVISOR,disabled
      value>
    property>
  bean>
  
  
  <bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
      
      <property name="authenticationEntryPoint">  
        <bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">  
           <property name="loginFormUrl" value="/login.jsp"/>  
           <property name="forceHttps" value="false"/>  
        bean>  
      property> 
     
      <property name="accessDeniedHandler">  
        <bean class="org.acegisecurity.ui.AccessDeniedHandlerImpl">  
           <property name="errorPage" value="/accessDenied.jsp"/>  
        bean>  
      property>  
   bean>		
  
  <bean id="filterInvocationInterceptor"
    class="org.acegisecurity.intercept.web.FilterSecurityInterceptor">
    <property name="authenticationManager" ref="authenticationManager" />
    <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager" />
    <property name="objectDefinitionSource">
      <value>        CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
        PATTERN_TYPE_APACHE_ANT
        /userinfo.jsp=ROLE_SUPERVISOR
      ]]>value>
    property>
  bean>

  <bean id="httpRequestAccessDecisionManager"
    class="org.acegisecurity.vote.AffirmativeBased">
    <property name="decisionVoters">
      <list>
        <bean class="org.acegisecurity.vote.RoleVoter"/>
      list>
    property>
  bean>
beans>

  讲解如下:

  那注销过滤器logoutFilter应用如下:

      
    <bean id="logoutFilter"  class="org.acegisecurity.ui.logout.LogoutFilter">
     
     <constructor-arg value="/login.jsp"/> 
     
      <constructor-arg>  
         <list>  
              <bean class="org.acegisecurity.ui.logout.SecurityContextLogoutHandler"/>  
         list>  
      constructor-arg>  
    bean>

  acegi配置文件中logoutFilter在httpSessionContextIntegrationFilter之后。

  spring为啥这么注入呢?这得看logoutFilter具体的类信息【下面截取半截】。

  
  public class LogoutFilter implements Filter {
  //~ Static fields/initializers =====================================================================================

  private static final Log logger = LogFactory.getLog(LogoutFilter.class);

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

  private String filterProcessesUrl = "/j_acegi_logout";
  private String logoutSuccessUrl;
  private LogoutHandler[] handlers;

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

  public LogoutFilter(String logoutSuccessUrl, LogoutHandler[] handlers) {
    Assert.hasText(logoutSuccessUrl, "LogoutSuccessUrl required");
    Assert.notEmpty(handlers, "LogoutHandlers are required");
    this.logoutSuccessUrl = logoutSuccessUrl;
    this.handlers = handlers;
  }

  LogoutFilter有三个属性,还有带有参数的构造器,所以在配置spring注入时,必须注入构造器,因为LogoutFilter没有默认的无参构造函数。若spring配置constructor,当启动tomcat时,会提示没有默认构造函数错误信息。

  对于属性使用property来注入,其中filterProcessesUrl类已经有默认值了,可以不配置。至于logoutSuccessUrl,handlers属性,也可以不配置。直接在constructor中配置即可,因为constructor是必须配置的。

  logoutSuccessUrl是注销后转向的页面。handlers是个数组,主要是主要处理注销功能,我们配置默认的注销器即可。

  配置完成后,根据acegi配置,那我们在表单中添加注销按钮。

  页面如下:

  那我们在登陆进去的userinfo.jsp中添加注销按钮,配置如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
  pageEncoding="UTF-8"%>
<%@ page import="org.acegisecurity.context.SecurityContextHolder"%>  
<%@ page import="org.acegisecurity.userdetails.*"%>  

   <%		 Object obj = SecurityContextHolder.getContext().getAuthentication();		  
      if (null != obj){  
        Object userDetail = SecurityContextHolder.getContext().getAuthentication().getPrincipal();  
        String username = "";  
        String pwd="";
        if (userDetail instanceof UserDetails) {  
          username = ((UserDetails) userDetail).getUsername();  
          pwd = ((UserDetails) userDetail).getPassword();  
        } else {  
          username = userDetail.toString();  
        }  
        out.print("当前用户:"+username+",密码:"+pwd);  
      } 
    %>  
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>当前用户的具体信息title>
head>

<form action="j_acegi_logout" method="post">
  <input type="submit" value="注销系统"/>
form>
html>

  OK,一切搞定后,大家可以测试一下,注销后转向登陆页面,看看是不是sessionid发生变化。

  源码解析:

  注销关键代码:

  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
  ServletException {
        if (!(request instanceof HttpServletRequest)) {
  throw new ServletException("Can only process HttpServletRequest");
        }

        if (!(response instanceof HttpServletResponse)) {
  throw new ServletException("Can only process HttpServletResponse");
        }

        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        if (requiresLogout(httpRequest, httpResponse)) {
  Authentication auth = SecurityContextHolder.getContext().getAuthentication();

  if (logger.isDebugEnabled()) {
      logger.debug("Logging out user '" + auth + "' and redirecting to logout page");
  }

  for (int i = 0; i < handlers.length; i++) {
      handlers[i].logout(httpRequest, httpResponse, auth);
  }

  sendRedirect(httpRequest, httpResponse, logoutSuccessUrl);

  return;
        }

        chain.doFilter(request, response);
    }

  其中requiresLogout判断是否需要注销,只要后缀以/j_acegi_logout结尾的就需要。类似登陆时 requiresAuthentication判断是否需要验证,只有后缀以/j_acegi_security_check结尾的就需要。

LogoutHandler调用注销:

   public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
Assert.notNull(request, "HttpServletRequest required");
if (invalidateHttpSession) {
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
}
}

SecurityContextHolder.clearContext();
}		
 
     

 其中LogoutHandler可以有多个,默认的是消除session的。比如还有利用cookie登陆的,注销时,是不是得消除cookie,new一个新的cookie即可。

  经过上篇博客对session的解析,相信大家很能理解这段话。其中invalidateHttpSession默认是true,HttpSession session = request.getSession(false);获取当前的session,若没有,则返回null。当session!=null时,销毁session—session.invalidate();销毁后,把SecurityContextHolder存放的securitycontext清空。

你可能感兴趣的:(acegi security)