`
fuwa_jane
  • 浏览: 50010 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Acegi简介

阅读更多
本文载自:http://exvision.iteye.com/blog/29323

Acegi安全系统,是一个用于Spring Framework的安全框架,能够和目前流行的Web容器无缝集成。它使用了Spring的方式提供了安全和认证安全服务,包括使用Bean Context,拦截器和面向接口的编程方式。因此,Acegi安全系统能够轻松地适用于复杂的安全需求。
       安全涉及到两个不同的概念,认证和授权。前者是关于确认用户是否确实是他们所宣称的身份。授权则是关于确认用户是否有允许执行一个特定的操作。
       在Acegi安全系统中,需要被认证的用户,系统或代理称为"Principal"。Acegi安全系统和其他的安全系统不同,它并没有角色和用户组的概念。
Acegi系统设计
  关键组件
      Acegi安全系统包含以下七个关键的功能组件:
         l Authentication对象,包含了Principal,Credential和Principal的授权信息。同时还可以包含关于发起认证请求的客户的其他信息,如IP地址。
        2 ContextHolder对象,使用ThreadLocal储存Authentication对象的地方。
        3 AuthenticationManager,用于认证ContextHolder中的Authentication对象。
        4 AccessDecissionManager,用于授权一个特定的操作。
        5 RunAsManager,当执行特定的操作时,用于选择性地替换Authentication对象。
        6 Secure Object拦截器,用于协调AuthenticationManager,AccessDecissionManager,RunAsManager和特定操作的执行。
        7 ObjectDefinitionSource,包含了特定操作的授权定义。
      这七个关键的功能组件的关系如下图所示(图中灰色部分是关键组件):


  安全管理对象
       Acegi安全系统目前支持两类安全管理对象。
       第一类的安全管理对象管理AOP Alliance的MethodInvocation,开发人员可以用它来保护Spring容器中的业务对象。为了使Spring管理的Bean可以作为MethodInvocation来使用,Bean可以通过ProxyFactoryBean和BeanNameAutoProxyCreator来管理,就像在Spring的事务管理一样使用。
       第二类是FilterInvocation。它用过滤器(Filter)来创建,并简单地包装了HTTP的ServletRequest,ServletResponse和FilterChain。FilterInvocation可以用来保护HTTP资源。通常,开发人员并不需要了解它的工作机制,因为他们只需要将Filter加入web.xml,Acegi安全系统就可以工作了。
  安全配置参数
       每个安全管理对象都可以描述数量不限的各种安全认证请求。例如,MethodInvocation对象可以描述带有任意参数的任意方法的调用,而FilterInvocation可以描述任意的HTTP URL。
       Acegi安全系统需要记录应用于每个认证请求的安全配置参数。例如,对于BankManager.getBalance(int accountNumber)方法和BankManager.approveLoan(int applicationNumber)方法,它们需要的认证请求的安全配置很不相同。
       为了保存不同的认证请求的安全配置,需要使用配置参数。从实现的视角来看,配置参数使用ConfigAttribute接口来表示。Acegi安全系统提供了ConfigAttribute接口的一个实现,SecurityConfig,它把配置参数保存为一个字符串。
       ConfigAttributeDefinition类是ConfigAttribute对象的一个简单的容器,它保存了和特定请求相关的ConfigAttribute的集合。
       当安全拦截器收到一个安全认证请求时,需要决定应用哪一个配置参数。换句话说,它需要找出应用于这个请求的ConfigAttributeDefinition对象。这个查找的过程是由ObjectDefinitionSource接口来处理的。这个接口的主要方法是public ConfigAttributeDefinition getAttributes(Object object),其中Object参数是一个安全管理对象。因为安全管理对象包含有认证请求的详细信息,所以ObjectDefinitionSource接口的实现类可以从中获得所需的详细信息,以查找相关的ConfigAttributeDefiniton对象。
  Acegi如何工作
       为了说明Acegi安全系统如何工作,我们设想一个使用Acegi的例子。通常,一个安全系统需要发挥作用,它必须完成以下的工作:
       l 首先,系统从客户端请求中获得Principal和Credential;
      2 然后系统认证Principal和Credential信息;
      3 如果认证通过,系统取出Principal的授权信息;
      4 接下来,客户端发起操作请求;
      5 系统根据预先配置的参数检查Principal对于该操作的授权;
      6 如果授权检查通过则执行操作,否则拒绝。
      那么,Acegi安全系统是如何完成这些工作的呢?首先,我们来看看Acegi安全系统的认证和授权的相关类图:
 
       图中绿色部分是安全拦截器的抽象基类,它包含有两个管理类,AuthenticationManager和AccessDecisionManager,如图中灰色部分。AuthenticationManager用于认证ContextHolder中的Authentication对象(包含了Principal,Credential和Principal的授权信息);AccessDecissionManager则用于授权一个特定的操作。
      下面来看一个MethodSecurityInterceptor的例子:
      <bean id="bankManagerSecurity" 
                     class="net.sf.acegisecurity.intercept.method.MethodSecurityInterceptor">
             <property name="validateConfigAttributes">
                    <value>true</value>
            </property>
            <property name="authenticationManager">
                   <ref bean="authenticationManager"/>
            </property>
            <property name="accessDecisionManager">
                  <ref bean="accessDecisionManager"/>
            </property>
            <property name="objectDefinitionSource">
                  <value>
                     net.sf.acegisecurity.context.BankManager.delete*=
                             ROLE_SUPERVISOR,RUN_AS_SERVER
                     net.sf.acegisecurity.context.BankManager.getBalance=
                             ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_
                  </value>
            </property>
      </bean> 


      上面的配置文件中,MethodSecurityInterceptor是AbstractSecurityInterceptor的一个实现类。它包含了两个管理器,authenticationManager和accessDecisionManager。这两者的配置如下:
      <bean id="authenticationDao" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
               <property name="dataSource"><ref bean="dataSource"/></property>
      </bean>
      <bean id="daoAuthenticationProvider" 
                     class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
               <property name="authenticationDao"><ref bean="authenticationDao"/></property>
      </bean>
      <bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
               <property name="providers">
                      <list><ref bean="daoAuthenticationProvider"/></list>
               </property>
      </bean>
      <bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>
      <bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
               <property name="allowIfAllAbstainDecisions"><value>false</value></property>
               <property name="decisionVoters">
                      <list><ref bean="roleVoter"/></list>
               </property>
      </bean>


      准备工作做好了,现在我们来看看Acegi安全系统是如何实现认证和授权机制的。以使用HTTP BASIC认证的应用为例子,它包括下面的步骤:
       1. 用户登录系统,Acegi从acegisecurity.ui子系统的安全拦截器(如BasicProcessingFilter)中得到用户的登录信息(包括Principal和Credential)并放入Authentication对象,并保存在ContextHolder对象中;
       2. 安全拦截器将Authentication对象交给AuthenticationManager进行身份认证,如果认证通过,返回带有Principal授权信息的Authentication对象。此时ContextHolder对象的Authentication对象已拥有Principal的详细信息;
       3. 用户登录成功后,继续进行业务操作;
       4. 安全拦截器(bankManagerSecurity)收到客户端操作请求后,将操作请求的数据包装成安全管理对象(FilterInvocation或MethodInvocation对象);
       5. 然后,从配置文件(ObjectDefinitionSource)中读出相关的安全配置参数ConfigAttributeDefinition;
       6. 接着,安全拦截器取出ContextHolder中的Authentication对象,把它传递给AuthenticationManager进行身份认证,并用返回值更新ContextHolder的Authentication对象;
       7. 将Authentication对象,ConfigAttributeDefinition对象和安全管理对象(secure Object)交给AccessDecisionManager,检查Principal的操作授权;
       8. 如果授权检查通过则执行客户端请求的操作,否则拒绝;
  AccessDecisionVoter
       注意上节的accessDecisionManager是一个AffirmativeBased类,它对于用户授权的投票策略是,只要通过其中的一个授权投票检查,即可通过;它的allowIfAllAbstainDecisions属性值是false,意思是如果所有的授权投票是都是弃权,则通不过授权检查。
       Acegi安全系统包括了几个基于投票策略的AccessDecisionManager,上节的RoleVoter就是其中的一个投票策略实现,它是AccessDecisionVoter的一个子类。AccessDecisionVoter的具体实现类通过投票来进行授权决策,AccessDecisionManager则根据投票结果来决定是通过授权检查,还是抛出AccessDeniedException例外。
       AccessDecisionVoter接口共有三个方法:
public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config);
public boolean supports(ConfigAttribute attribute);
public boolean supports(Class clazz);
       其中的vote方法返回int返回值,它们是AccessDecisionVoter的三个静态成员属性:ACCESS_ABSTAIN,,ACCESS_DENIED和ACCESS_GRANTED,它们分别是弃权,否决和赞成。
       Acegi安全系统中,使用投票策略的AccessDecisionManager共有三个具体实现类:AffirmativeBased、ConsensusBased和UnanimousBased。它们的投票策略是,AffirmativeBased类只需有一个投票赞成即可通过;ConsensusBased类需要大多数投票赞成即可通过;而UnanimousBased类需要所有的投票赞成才能通过。
       RoleVoter类是一个Acegi安全系统AccessDecisionVoter接口的实现。如果ConfigAttribute以ROLE_开头,RoleVoter则进行投票。如果GrantedAuthority的getAutority方法的String返回值匹配一个或多个以ROLE_开头的ConfigAttribute,则投票通过,否则不通过。如果没有以ROLE_开头的ConfigAttribute,RoleVoter则弃权。
安全拦截器
  拦截器如何工作
  MethodInvocation拦截器
  FilterInvocation拦截器
认证
  认证请求
  认证管理器
  Authentication Provider
授权
  Access Decision Manager
  Voting Decision Manager
  授权管理推荐
ContextHolder的用户接口
  用户接口目标
  HTTP会话认证
  HTTP Basic认证
1、Log4j的概念
   Log4j中有三个主要的组件,它们分别是Logger、Appender和Layout,Log4j 允许开发人员定义多个Logger,每个Logger拥有自己的名字,Logger之间通过名字来表明隶属关系。有一个Logger称为Root,它永远 存在,且不能通过名字检索或引用,可以通过Logger.getRootLogger()方法获得,其它Logger通过 Logger.getLogger(String name)方法。
   Appender则是用来指明将所有的log信息存放到什么地方,Log4j中支持多种appender,如 console、files、GUI components、NT Event Loggers等,一个Logger可以拥有多个Appender,也就是你既可以将Log信息输出到屏幕,同时存储到一个文件中。
   Layout的作用是控制Log信息的输出方式,也就是格式化输出的信息。
   Log4j中将要输出的Log信息定义了5种级别,依次为DEBUG、INFO、WARN、ERROR和FATAL,当输出时,只有级别高过配置中规定的 级别的信息才能真正的输出,这样就很方便的来配置不同情况下要输出的内容,而不需要更改代码,这点实在是方便啊。

2、Log4j的配置文件
  虽然可以不用配置文件,而在程序中实现配置,但这种方法在如今的系统开发中显然是不可取的,能采用配置文件的地方一定一定要用配置文件。Log4j支持两 种格式的配置文件:XML格式和Java的property格式,本人更喜欢后者,首先看一个简单的例子吧,如下:

 log4j.rootLogger=debug, stdout, R
  log4j.appender.stdout=org.apache.log4j.ConsoleAppender
  log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

  # Pattern to output the caller's file name and line number.
  log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n

  log4j.appender.R=org.apache.log4j.RollingFileAppender
  log4j.appender.R.File=example.log
  log4j.appender.R.MaxFileSize=100KB

  # Keep one backup file
  log4j.appender.R.MaxBackupIndex=1

  log4j.appender.R.layout=org.apache.log4j.PatternLayout
  log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n   


  首先,是设置root,格式为 log4j.rootLogger=[level],appenderName, ...,其中level就是设置需要输出信息的级别,后面是appender的输出的目的地,appenderName就是指定日志信息输出到哪个地方。您可以同时指定多个输出目的地。配置日志信息输出目的地Appender,其语法为
  log4j.appender.appenderName = fully.qualified.name.of.appender.class
  log4j.appender.appenderName.option1 = value1
  ...
  log4j.appender.appenderName.option = valueN
Log4j提供的appender有以下几种:
  org.apache.log4j.ConsoleAppender(控制台)
  org.apache.log4j.FileAppender(文件)
  org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)
  org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生新文件)
  org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)
配置日志信息的格式(布局),其语法为:
  log4j.appender.appenderName.layout = fully.qualified.name.of.layout.class
  log4j.appender.appenderName.layout.option1 = value1
  ....
  log4j.appender.appenderName.layout.option = valueN
Log4j提供的layout有以下几种:
  org.apache.log4j.HTMLLayout(以HTML表格形式布局),
  org.apache.log4j.PatternLayout(可以灵活地指定布局模式),
  org.apache.log4j.SimpleLayout(包含日志信息的级别和信息字符串),
  org.apache.log4j.TTCCLayout(包含日志产生的时间、线程、类别等等信息)

3、Log4j在程序中的使用
  要在自己的类中使用Log4j,首先声明一个静态变量Logger logger=Logger.getLog("classname");在使用之前,用PropertyConfigurator.configure ("配置文件")配置一下,现在就可以使用了,用法如下:logger.debug("debug message")或者logger.info("info message"),看下面一个小例子:

  import com.foo.Bar;
  import org.apache.log4j.Logger;
  import org.apache.log4j.PropertyConfigurator;
  public class MyApp {
    static Logger logger = Logger.getLogger(MyApp.class.getName());
    public static void main(String[] args) {
      // BasicConfigurator replaced with PropertyConfigurator.
      PropertyConfigurator.configure(args[0]);
      logger.info("Entering application.");
      Bar bar = new Bar();
      bar.doIt();
      logger.info("Exiting application.");
    }
  }


[简介]
对于一个典型的Web应用,完善的认证和授权机制是必不可少的,在SpringFramework中,Juergen Hoeller提供的范例JPetStore给了一些这方面的介绍,但还远远不够,Acegi是一个专门为SpringFramework提供安全机制的 项目,全称为Acegi Security System for Spring,当前版本为0.5.1,就其目前提供的功能,应该可以满足绝大多数应用的需求。

本文的主要目的是希望能够说明如何在基于Spring构架的Web应用中使用Acegi,而不是详细介绍其中的每个接口、每个类。注意,即使对已经存在的Spring应用,通过下面介绍的步骤,也可以马上享受到Acegi提供的认证和授权。

[基础工作]
在你的Web应用的lib中添加Acegi下载包中的acegi-security.jar

[web.xml]
实现认证和授权的最常用的方法是通过filter,Acegi亦是如此,通常Acegi需要在web.xml添加以下5个filter:

<filter>
  <filter-name>Acegi Channel Processing Filter</filter-name>
  <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
  <init-param>
    <param-name>targetClass</param-name>
    <param-value>net.sf.acegisecurity.securechannel.ChannelProcessingFilter</param-value>
  </init-param>
</filter>
<filter>
  <filter-name>Acegi Authentication Processing Filter</filter-name>
  <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
  <init-param>
    <param-name>targetClass</param-name>
    <param-value>net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter</param-value>
  </init-param>
</filter>
<filter>
  <filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>
  <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
  <init-param>
    <param-name>targetClass</param-name>
    <param-value>net.sf.acegisecurity.ui.basicauth.BasicProcessingFilter</param-value>
  </init-param>
</filter>
<filter>
  <filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
  <filter-class>net.sf.acegisecurity.ui.AutoIntegrationFilter</filter-class>
</filter>
<filter>
  <filter-name>Acegi HTTP Request Security Filter</filter-name>
  <filter-class>net.sf.acegisecurity.util.FilterToBeanProxy</filter-class>
  <init-param>
    <param-name>targetClass</param-name>
    <param-value>net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter</param-value>
  </init-param>
</filter>


最先引起迷惑的是net.sf.acegisecurity.util.FilterToBeanProxy,Acegi自己的文档上解释是: “What  FilterToBeanProxy does is delegate the Filter's methods through to a bean which is obtained from the
Spring application context. This enables the bean to benefit from the Spring application context lifecycle support and configuration flexibility.”,如希望深究的话,去看看源代码应该不难理解。

再下来就是添加filter-mapping了:
<filter-mapping>
  <filter-name>Acegi Channel Processing Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>Acegi Authentication Processing Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>Acegi HTTP BASIC Authorization Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>Acegi Security System for Spring Auto Integration Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
  <filter-name>Acegi HTTP Request Security Filter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>


这里,需要注意以下两点:
1) 这几个filter的顺序是不能更改的,顺序不对将无法正常工作;
2) 如果你的应用不需要安全传输,如https,则将"Acegi Channel Processing Filter"相关内容注释掉即可;
3) 如果你的应用不需要Spring提供的远程访问机制,如Hessian and Burlap,将"Acegi HTTP BASIC Authorization
Filter"相关内容注释掉即可。

[applicationContext.xml]
接下来就是要添加applicationContext.xml中的内容了,从刚才FilterToBeanFactory的解释可以看出,真正的filter都
在Spring的applicationContext中管理:

1) 首先,你的数据库中必须具有保存用户名和密码的table,Acegi要求table的schema必须如下:

CREATE TABLE users (
    username VARCHAR(50) NOT NULL PRIMARY KEY,
    password VARCHAR(50) NOT NULL,
    enabled BIT NOT NULL
);
CREATE TABLE authorities (
    username VARCHAR(50) NOT NULL,
    authority VARCHAR(50) NOT NULL
);
CREATE UNIQUE INDEX ix_auth_username ON authorities ( username, authority );
ALTER TABLE authorities ADD CONSTRAINT fk_authorities_users foreign key (username) REFERENCES users
(username);


2) 添加访问你的数据库的datasource和Acegi的jdbcDao,如下:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
  <property name="driverClassName"><value>${jdbc.driverClassName}</value></property>
  <property name="url"><value>${jdbc.url}</value></property>
  <property name="username"><value>${jdbc.username}</value></property>
  <property name="password"><value>${jdbc.password}</value></property>
</bean>
<bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl">
  <property name="dataSource"><ref bean="dataSource"/></property>
</bean>


3) 添加DaoAuthenticationProvider:
<bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider">
  <property name="authenticationDao"><ref bean="authenticationDao"/></property>
  <property name="userCache"><ref bean="userCache"/></property>
</bean>

<bean id="userCache" class="net.sf.acegisecurity.providers.dao.cache.EhCacheBasedUserCache">
  <property name="minutesToIdle"><value>5</value></property>
</bean>


如果你需要对密码加密,则在daoAuthenticationProvider中加入:<property name="passwordEncoder"><ref
bean="passwordEncoder"/></property>,Acegi提供了几种加密方法,详细情况可看包
net.sf.acegisecurity.providers.encoding

4) 添加authenticationManager:
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
  <property name="providers">
    <list>
      <ref bean="daoAuthenticationProvider"/>
    </list>
   </property>
</bean>


5) 添加accessDecisionManager:
<bean id="accessDecisionManager" class="net.sf.acegisecurity.vote.AffirmativeBased">
  <property name="allowIfAllAbstainDecisions">
    <value>false</value>
  </property>
  <property name="decisionVoters">
    <list><ref bean="roleVoter"/></list>
  </property>
</bean>
<bean id="roleVoter" class="net.sf.acegisecurity.vote.RoleVoter"/>


6) 添加authenticationProcessingFilterEntryPoint:
<bean id="authenticationProcessingFilterEntryPoint" 
class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
  <property name="loginFormUrl"><value>/acegilogin.jsp</value></property>
  <property name="forceHttps"><value>false</value></property>
</bean>


其中acegilogin.jsp是登陆页面,一个最简单的登录页面如下:
<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core' %>
<%@ page import="net.sf.acegisecurity.ui.AbstractProcessingFilter" %>
<%@ page import="net.sf.acegisecurity.AuthenticationException" %>
<html>
  <head>
    <title>Login</title>
  </head>

  <body>
    <h1>Login</h1>
    <form action="<c:url value='j_acegi_security_check'/>" method="POST">
      <table>
        <tr><td>User:</td><td><input type='text' name='j_username'></td></tr>
        <tr><td>Password:</td><td><input type='password' name='j_password'></td></tr>
        <tr><td colspan='2'><input name="submit" type="submit"></td></tr>
        <tr><td colspan='2'><input name="reset" type="reset"></td></tr>
      </table>
    </form>
  </body>
</html>


7) 添加filterInvocationInterceptor:
<bean id="filterInvocationInterceptor" 
class="net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor">
  <property name="authenticationManager">
    <ref bean="authenticationManager"/>
  </property>
  <property name="accessDecisionManager">
    <ref bean="accessDecisionManager"/>
  </property>
  <property name="objectDefinitionSource">
    <value>
      CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
      \A/sec/administrator.*\Z=ROLE_SUPERVISOR
      \A/sec/user.*\Z=ROLE_TELLER
    </value>
  </property>
</bean>


这里请注意,要objectDefinitionSource中定义哪些页面需要权限访问,需要根据自己的应用需求进行修改,我上面给出
的定义的意思是这样的:
a. CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON意思是在比较请求路径时全部转换为小写
b. \A/sec/administrator.*\Z=ROLE_SUPERVISOR意思是只有权限为ROLE_SUPERVISOR才能访问/sec/administrator*的页面
c. \A/sec/user.*\Z=ROLE_TELLER意思是只有权限为ROLE_TELLER的用户才能访问/sec/user*的页面

8) 添加securityEnforcementFilter:
<bean id="securityEnforcementFilter" class="net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter">
  <property name="filterSecurityInterceptor">
    <ref bean="filterInvocationInterceptor"/>
  </property>
  <property name="authenticationEntryPoint">
    <ref bean="authenticationProcessingFilterEntryPoint"/>
  </property>
</bean>


9) 添加authenticationProcessingFilter:
<bean id="authenticationProcessingFilter" 
class="net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter">
  <property name="authenticationManager">
    <ref bean="authenticationManager"/>
  </property>
  <property name="authenticationFailureUrl">
    <value>/loginerror.jsp</value>
  </property>
  <property name="defaultTargetUrl">
    <value>/</value>
  </property>
  <property name="filterProcessesUrl">
    <value>/j_acegi_security_check</value>
  </property>
</bean>


其中authenticationFailureUrl是认证失败的页面。

10) 如果需要一些页面通过安全通道的话,添加下面的配置:
<bean id="channelProcessingFilter" class="net.sf.acegisecurity.securechannel.ChannelProcessingFilter">
  <property name="channelDecisionManager">
    <ref bean="channelDecisionManager"/>
  </property>
  <property name="filterInvocationDefinitionSource">
    <value>
      CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
      \A/sec/administrator.*\Z=REQUIRES_SECURE_CHANNEL
      \A/acegilogin.jsp.*\Z=REQUIRES_SECURE_CHANNEL
      \A/j_acegi_security_check.*\Z=REQUIRES_SECURE_CHANNEL
      \A.*\Z=REQUIRES_INSECURE_CHANNEL
    </value>
  </property>
</bean>

<bean id="channelDecisionManager" class="net.sf.acegisecurity.securechannel.ChannelDecisionManagerImpl">
  <property name="channelProcessors">
    <list>
      <ref bean="secureChannelProcessor"/>
      <ref bean="insecureChannelProcessor"/>
    </list>
  </property>
</bean>
<bean id="secureChannelProcessor" class="net.sf.acegisecurity.securechannel.SecureChannelProcessor"/>
<bean id="insecureChannelProcessor" class="net.sf.acegisecurity.securechannel.InsecureChannelProcessor"/>


[缺少了什么?]
Acegi目前提供了两种"secure object",分别对页面和方法进行安全认证管理,我这里介绍的只是利用
FilterSecurityInterceptor对访问页面的权限控制,除此之外,Acegi还提供了另外一个Interceptor——
MethodSecurityInterceptor,它结合runAsManager可实现对对象中的方法的权限控制,使用方法可参看Acegi自带的文档
和contact范例。

[最后要说的]
本来以为只是说明如何使用Acegi而已,应该非常简单,但真正写起来才发现想要条理清楚的理顺所有需要的bean还是很
困难的,但愿我没有遗漏太多东西,如果我的文章有什么遗漏或错误的话,还请参看Acegi自带的quick-start范例,但请
注意,这个范例是不能直接拿来用的。
分析和学习Spring中的jpetstore用户管理
  存在用户的系统,必然需要用户的登录和认证,今天就通过分析Spring中自带的jpetstore的例子来学习一下如何实现在Spring构架的系统中用户登录。
1、首先从注册用户开始,先看看jpetstore-servlet.xml中关于注册用户的bean定义,从定义命名中就可以看出下面这段就是注册用户的:
<bean name="/shop/newAccount.do" class="org.springframework.samples.jpetstore.web.spring.AccountFormController">
    <property name="petStore"><ref bean="petStore"/></property>
    <property name="validator"><ref bean="accountValidator"/></property>
    <property name="successView"><value>index</value></property>
  </bean>


1). formView呢?从AccountFormController的构造函数中得到,原来为EditAccountForm; 
2). EditoAccountForm.jsp中显得非常乱,其实没有多少难理解的地方,最主要的是这个form既是添加新用户的,又是编辑用户信息的,所以显得有点乱糟糟的。
2、添加好了新用户,接下来看看如何登录,在jpetstore-servlet中发现这两个相关bean定义,如下:
<bean name="/shop/signon.do" class="org.springframework.samples.jpetstore.web.spring.SignonController">
    <property name="petStore"><ref bean="petStore"/></property>
  </bean>
  <bean name="/shop/signonForm.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
    <property name="viewName"><value>SignonForm</value></property>
  </bean>


1). 第二个bean是在运行时用户输入用户名和密码的form,叫做SignonForm,对于这个 ParameterizableViewController,用文档里的话说这是最简单的Controller,其作用就是在运行中指向 Controller而不是直接指向jsp文件,仅此而已。
2). SignonForm.jsp,里面就是一个简单的form,其action就是第一个bean,即/shop/signon.do,最需要注意的是 signonForwardAction,其主要作用是forward到需要输入用户名和密码的那个页面上去,这个变量哪里来的呢?看看下面:
 <bean id="secureHandlerMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="interceptors">
      <list>
        <ref bean="signonInterceptor"/>
      </list>
    </property>
    <property name="urlMap">
      <map>
        <entry key="/shop/editAccount.do"><ref local="secure_editAccount"/></entry>
        <entry key="/shop/listOrders.do"><ref local="secure_listOrders"/></entry>
        <entry key="/shop/newOrder.do"><ref local="secure_newOrder"/></entry>
        <entry key="/shop/viewOrder.do"><ref local="secure_viewOrder"/></entry>
      </map>
    </property>
  </bean>


原来,上面的signonInterceptor实现了preHandle,因此在请求上面的map页面时,首先要经过这个Interceptor,看看 SignonInterceptor的源码,原来在其中为signon.jsp赋予一个signonForwardAction对象,呵呵,总算明白了。
3). 接下来去学习一下SignonController,其主体部分中可以看出,首先取出用户输入的username和password,然后到数据库中验证 有没有这个用户,如果没有这个用户,返回各错误页面;如果成功,首先生成一个UserSession对象,在request的session加入这个 userSession,注意这部分代码中给出了PagedListHolder分页的简单使用方法,关于分页显示,以后再学习吧。
3、登录成功后,就可以根据不同的用户设施不同的行为了,取得用户信息,无非就是从session取出userSession即可。
分享到:
评论

相关推荐

    spring Acegi

    Spring安全系统:Acegi Security Acegi简介! Acegi安全系统,是一个用于Spring Framework的安全框架,能够和目前流行的Web容器无缝集成。它使用了Spring的方式提供了安全和认证安全服务,包括使用Bean Context,...

    acegi安全框架简介

    Acegi安全系统,是一个用于Spring Framework的安全框架,能够和目前流行的Web容器无缝集成。它使用了Spring的方式提供了安全和认证安全服务,包括使用Bean Context,拦截器和面向接口的编程方式。因此,Acegi安全...

    Acegi安全框架简介及实用扩展

    Acegi安全框架简介及实用扩展,spring acegi 权限管理

    Acegi_使用.doc

    Acegi简介 3 Acegi系统设计 3 关键组件 3 安全管理对象 4 安全配置参数 5 Resuest Contexts 5 Contexts 5 Secure Contexts 6 Custom Contexts 6 Context Storage 7 Acegi如何工作 7 认证授权流程 9 授权机制 12 ...

    敏捷Acegi、CAS构建安全的Java系统

    资源名称:敏捷Acegi、CAS 构建安全的Java系统 内容简介:本书是关于Acegi、CAS的权威教程,是Java/Java EE安全性开发者的必备参考书。无论是Java EE安全性编程模型的背景和基础知识,还是Acegi、CAS本身,还是...

    struts + spring + hibernate + velocity + ajax + jotm + acegi

    简介: struts + spring + hibernate + velocity + ajax + jotm + acegi ================================================================================================ 本资料共包含以下附件: 1161...

    java文集

    映射标记 Java的“静态库链接” 姚博文 集成ACEGI 进行权限控制 SWT可交互式Browser控件 JDK配置(注意) RIA简介(第一部分) 在 Eclipse 中嵌入 NASA World Wind Java SDK, 用3DES加密解密 ...

    Spring技术内幕:深入解析Spring架构与设计原理

    资源简介×××总共两个zip文件;7zip压缩 ×××Spring 技术内幕.zip.001 ×××Spring 技术内幕.zip.002 本书是spring领域的问鼎之作,由业界拥有10余年开发经验的资深java专家亲自执笔!java开发者社区和...

    《精通Spring2.X企业应用开发详解》20-23

    图书简介 本书分为6大部分,其中第一部分为Spring概述性知识;第二部分讲解了Spring框架核心技术的内容;第三部分涵盖了在Spring中使用各种数据访问技术的内容;第四部分讲解业务层各种技术的知识;第五部分是...

    《精通Spring2.X企业应用开发详解》16-19章

    图书简介 本书分为6大部分,其中第一部分为Spring概述性知识;第二部分讲解了Spring框架核心技术的内容;第三部分涵盖了在Spring中使用各种数据访问技术的内容;第四部分讲解业务层各种技术的知识;第五部分是...

    《精通Spring2.X企业应用开发详解》随书源码1-15章

    图书简介 本书分为6大部分,其中第一部分为Spring概述性知识;第二部分讲解了Spring框架核心技术的内容;第三部分涵盖了在Spring中使用各种数据访问技术的内容;第四部分讲解业务层各种技术的知识;第五部分是...

    Grails 中文参考手册

    1. 简介 2. 起步 2.1 下载并安装Grails 2.2 创建一个Grails应用 2.3 Hello World示例 2.4 使用IDE 2.5 规约配置 2.6 运行Grails应用 2.7 测试Grails应用 2.8 部署Grails应用 2.9 所支持的Java EE容器 2.10 创建工件 ...

    DWR中文文档.pdf

    39 4.6.2 HibernateBeanConverter 39 4.6.3 Session管理 39 4.7 DWR与WebWork 40 4.7.1 配置dwr.xml 40 4.7.2 在JSP中导入脚本 40 4.7.3 高级 41 4.8 DWR与Acegi 42 4.8.1 问题提出...

    Spring技术内幕

    内容简介:, 本书是Spring领域的问鼎之作,由业界拥有10余年开发经验的资深Java专家亲自执笔!Java开发者社区和Spring开发者社区一致强烈推荐。, 国内第一本基于Spring3.0的著作,从源代码的角度对Spring的内核和...

    JAVA上百实例源码以及开源项目

    简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往...

    JAVA上百实例源码以及开源项目源代码

    简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!...

Global site tag (gtag.js) - Google Analytics