Acegi

2026/4/25 16:53:01

2.2共享组件

让我们先来看一看在Acegi Security中最重要的共享组件。如果组件是框架的核心,框架没有它们将无法工作,那么这样的组件就是“共享”组件。系统其它部分所描述的那些JAVA类型,对于系统来说是很重要的,尽管你不需要直接访问他们。

最基础的对象是SecurityContextHolder。在它里面存储了当前应用程序安全上下文的详细信息,也包含了当前使用应用程序的“个体”的详细信息。默认地,SecurityContextHolder使用一个ThreadLocal来存储这个详细信息,这也就是说这个安全上下文在同一执行线程中对方法总是可用的,尽管安全上下文没有明确地做为参数在这些方法中传递。如果关心在当前“个体”的请求被处理后清除线程,那么在这个方式中使用ThreadLocal是十分安全的。当然,Acegi Security已经自动为你处理好了,所以没有必要担心。

某些应用程序并不十分适合使用ThreadLocal,因为它们使用特殊的多线程方法。例如,Swing客户端可能需要JAVA虚拟机中的所有线程使用同一个安全上下文。为了这种需求,可以使用SecurityContextHolder.MODE_GLOBAL。其它应用程序可能需要通过安全线程采用同一安全标识来使用线程卵(threads spawned)。这可通过使用SecurityContextHolder.MODE_INHERITABLETHREADLOCAL来实现。可以通过改变默认的SecurityContextHolder.MODE_THREADLOCA来切换到这个两种方式之一。方法之一是设置系统属性。也可调用SecurityContextHolder上的一个静态方法。大多数应用程序不需改变默认值,但是如果需要,可参考SecurityContextHolder的JavaDocs以了解更多。

在SecurityContextHolder内部存储了当前与应用程序交互的“个体”的详细信息。Acegi Security使用一个Authentication对象来描述这个信息。你不需要像平常那样建立一个Authentication对象,可以十分方便地请求一个Authentication对象。在应用程序中的任何地方使用如下代码:

Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

if (obj instanceof UserDetails) {

String username = ((UserDetails)obj).getUsername(); } else {

String username = obj.toString(); }

以上代码介绍相关内容和关键对象。首先,会发现在SecurityContextHolder和Authentication对象之间有一个中介对象。SecurityContextHolder.getContext()方法实际返回一个SecurityContext。Acegi Security使用几个不同的SecurityContext实现,例如如果需要存储相对于一个非“特定个体”请求的特定信息。我们的JCaptcha是这样一个很好的例子,它需要知道是否当前的请求来自于一个真实用户。由于相对于这个“个体”的请求可能会被认证通过或不通过,而这个判定并不会做什么,所以我们把Authentication对象存储在SecurityContext中。

另一项需要注意的是从以上代码的Authentication对象中可以得到一个“个体”。这个“个体”也是一个对象。大多数情况下可以将“个体”对象转换成一个UserDetails对象。在Acegi Security中UserDetails是一个核心接口。UserDetails描述了一个“个体”,但是是可扩展且可针对特定应用的。可以把UserDetails想象成是一个位于用户数据库和Acegi Security所需要的SecurityContextHolder之间的适配器。做为用户数据库信息的代表,时常需要把UserDetails转换成应用程序提供的原始对象,以便可以调用特定的商业逻辑方法(如:getEmail(),getEmployeeNumber()等)。

现在你可能想知道,我什么时候要提供一个UserDetails对象呢?我该怎么做?这个问题已经讨论过了,并且不需要写任何JAVA代码,就这些了!这个简短的回答说明了存在一个特别的接口,叫做UserDetailsService。这个接口的唯一方法接受一个字符串型的username参数,并且返回一个UserDetails对象。Acegi Security附带的大多数认证提供者都委派一个UserDetailsService做为认证处理过程的一部分。UserDetailsService用于建立SecurityContextHolder中所存储的Authentication对象。好消息是我们提供了多个UserDetailsService的实现,其中包含一个使用内存映射和一个使用JDBC的实现。大多数使用者更倾向于实现自己的实现,尽管这样的实现常常是简单地建立在一个已经存在的DAO之上的,这个DAO包含了整个应用程序中的雇员,客户,或其它用户。记住一个优势,无论你的UserDetailsService是如何实现的,总是可以通过SecurityContextHolder来得到它,就像上面代码所写的一样。

除了“个体”,Authentication提供的另一个重要方法是getAuthorities()。这个方法提供了一个GrantedAuthority对象的数组。GrantedAuthority没什么奇怪的,它是一个被分配给“个体”的权限。这些权限使用“角色roles”这个字义,例如ROLE_ADMINISTRATOR或ROLE_HR_SUPERVISOR。这些角色为稍后的WEB授权,方法授权和域对象授权而配置。Acegi Security的其它部分有解释这些权限的能力,并且根据权限来呈现。你将常常从UserDetailsService中返回GrantedAuthority对象数组。

通常GrantedAuthority对象数组是应用程序范围的授权。而不是为某个给定的域对象而存在的。因此你很可能不会将一个GrantedAuthority对象授权给编号为54的雇员,如果有上千个这样的权限,那么在运行时很快就会内存溢出的(或者至少,会使应用程序花费很长时间来认证一个用户)。当然,Acegi Security很明确地被设计成可以控制这个通用的需求,但你为了达到这个目的最好使用项目的域对象安全能力来代替。

最后,有时需要在HTTP请求之间存储SecurityContext。有时“个体”将在每个请求上重新认证,尽管大多数时候它将被存储起来。在HTTP请求之间存储一个SecurityContext对象是由HttpSessionContextIntegerationFilter负责的。由这个类的名字可知,HttpSession被用来存储这些信息。你将不会为了安全目的而直接与HttpSession交互。简直没有理由会这样做,通常由SecurityContextHolder代替。

让我们重新回顾一下,Acegi Security由以下主要部分组成:

? SecurityContextHolder,提供到SecurityContext的任何类型的访问。 ? SecurityContext,存储了Authentication和特殊请求的安全信息。

? HttpSessionContextIntegrationFilter,在WEB请求之间用HttpSession存储

SecurityContext。

? ? ? ?

Authentication,在一个Acegi Security的特定行为中描述一个“个体”。 GrantedAuthority,用来映射分配给一个“个体”的应用程序级的权限。

UserDetails,提供必要的信息来从应用程序的DAO中建立一个Authentication对象。 UserDetailsService,通过传递一个username字符串(或标识ID)来创建一个UserDetails。

现在你已经对这个经常使用的组件有了一定的了解,接下来让我们详细了解一下认证的处理过程。

2.3认证

参考指南的开始部分提到过,Acegi Security可以参与多种不同的认证环境。当然我们推荐用户使用Acegi Security进行认证,且不要与已存在的容器管理的认证进行集成,尽管支持这样做;可使用自己自定义的认证系统进行集成。首先让我们浏览一下整个Acegi Security自己所管理的WEB安全的情景,它说明了最复杂同时也是最通用的情形。

考虑一个典型的WEB应用的认证过程: 1. 访问首页,并点击一个链接。

2. 一个请求被发送到服务器,并且服务器决定是否访问的是一个受保护的资源。

3. 如果当前没有被认证,服务器返回一个响应指示必须认证。这个响应可能是一个HTTP

响应代码,或重定向到一个特定的网页。 4. 依靠认证机制,浏览器可能重定向到一个特定的网页以便填写表单信息,或浏览器将总

是回复一个标识(如:一个BASIC认证对话框,一个cookie,一个X509证书等)。 5. 浏览器返回一个响应给服务器。这个响应可能是一个包含了表单内容的HTTP POST,或

一个包含了认证信息的HTTP头。

6. 接下来服务器将决定当前的凭证是否有效。有效,所请求的内容将显示;否则,通常来

说浏览器将会再询问一次(返回第二步)。 7. 原始请求引起的认证过程将被重试。要求拥有足够的权限以访问受保护的资源。如果拥

有足够的权限,请求将会成功。否则,将会得到一个HTTP的403错误代码,这意味着“被禁止”。

Acegi Security拥有明确的类负责上面描述的大多数步骤。其中主要的参与者(按上面使用的顺序)是ExceptionTranslationFilter,AuthenticationEntryPoint,authentication mechanism,AuthenticationProvider。

ExceptionTranslationFilter是一个Acegi Security过滤器,它负责检测被抛出的Acegi Security异常。这些异常通常被一个AbstractSecurityInterceptor抛出,它是主要的认证服务提供者。我们将在下一节讨论AbstractSecurityInterceptor,但是现在我们必须知道它产生了JAVA异常且不知道关于HTTP或如何去认证一个“个体”的内容。除了ExceptionTranslationFilter所提供的服务,还要具体指定负责返回错误代码403(如果“个体”已认证,只是缺少必要的权限。上面第七步),或创建一个AuthenticationEntryPoint(如果“个体”还没认证,将返回第三步)。

AuthenticationEntryPoint负责上面列表中的第三步。可以想象一下,每个WEB应用

程序都会有一个默认的认证策略(当然,跟Acegi Security中其它配置相似,但现在让我们先来点简单的)。大部分的认证系统都会有自已的AuthenticationEntryPoint实现,它在第三步中起作用。在浏览器决定提交认证证书(HTTP表单或HTTP头)之后,在服务器上需要收集认证信息。现在我们到了第六步。在Acegi Security中对于从客户端(浏览器)收集认证信息的功能有一个特别的名字,叫做“authentication mechanism”。当认证信息收集好后,一个“Authentication request”对象被创建并且发送给一个AuthenticationProvider。

Acegi Security认证处理的最后一步是AuthenticationProvider。十分简单,它负责获取一个Authentication请求对象并决定是否有效。AuthenticationProvider要么抛出一个异常,要么返回一个完整的Authentication对象。还记得我们的益友,UserDetails和UserDetailsService吗?如果忘了,再回头看看吧。大多数AuthenticationProviders都会要求一个UserDetailsService提供一个UserDetails对象。就像前面说过的,大多数应用程序都会提供自己的UserDetailsService,尽管有些会使用由Acegi Security提供的JDBC或in-memory实现。UserDetails对象的结果和其独有的GrantedAuthority[]s包含在UserDetails对象中,将被用来构建完整的Authentication对象。

当authentication mechanism收到返回的完整Authentication对象之后,它将认证请求是有效的,把Authentication放入SecurityContextHolder,且触发原始请求重试操作(第七步)。另一方面,如果AuthenticationProvider拒绝请求,authentication mechanism会要求客户端重试(第二步)。

这里描述的是典型的认证流程,值得高兴的是Acegi Security不介意如果将一个Authentication放入SecurityContextHolder中。最重要的需要仅仅是SecurityContextHolder包含一个Authentication,这个Authentication代表了在AbstractSecurityInterceptor需要认证一个请求之前的一个“个体”。

你可以(并且大多数用户都这样做)自定义过滤器或MVC控制器以提供和不基于Acegi Security的认证系统之间的交互。例如,可以使用容器管理的认证,使当前用户在ThreadLocal或JNDI位置可见。或者,可能工作于企业的一个遗留特有的认证系统上,这个系统是建立在企业标准之上的,而你仅有很小的控制能力。在这种情况下,可以很容易地应用Acegi Security来工作,且仍然可以提供认证的能力。你所需要做的仅是自定义一个从某位置读取第三方用户信息的过滤器(或等价的)创建一个Acegi Security规定的Authentication对象,并且放入SecurityContextHolder中。做起来十分简单,并且是一个安全支持的集成方法。

2.4安全对象

如果你熟悉AOP,那么可能知道有几种不同的advice类型:before,after,throws和around。Around advice是非常有用的,因为这个advisor可以选择是否在方法之前处理,是否修改响应,是否抛出异常。Acegi Security提供了一个around advice用于方法之前,同样有WEB请求的。我们使用AOP Alliance实现了一个用于方法之前的around advice,和使用标准过滤器实现的一个用于WEB请求的around advice。


Acegi.doc 将本文的Word文档下载到电脑
搜索更多关于: Acegi 的文档
相关推荐
相关阅读
× 游客快捷下载通道(下载后可以自由复制和排版)

下载本文档需要支付 10

支付方式:

开通VIP包月会员 特价:29元/月

注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信:xuecool-com QQ:370150219