有些应用程序由于使用线程的方式而并不是完全适用ThreadLocal。例如,Swing客户端可能需要一个Java Virtual Machine中的所有线程都使用同样的安全上下文(security context)。在这种情况下你要使用
SecurityContextHolder.MODE_GLOBAL模式。另外一些应用程序可能需要安全线程产生的线程拥有同样的安全标识符(security identity)。这可以通过
SecurityContextHolder.MODE_INHERITABLETHREADLOCAL来实现。你可以通过两种方法来修改默认的
SecurityContextHolder.MODE_THREADLOCAL。第一种是设臵一个系统属性。或者,调用SecurityContextHolder的一个静态方法。大部分的应用程序不需要修改默认值,不过如果你需要,那么请查看SecurityContextHolder的JavaDocs获取更多信息。
我们在SecurityContextHolder中存储当前和应用程序交互的principal的详细信息。Acegi Security使用一个Au真的不掉线
吗??、????????????
thentication对象来代表这个信息。尽管你通常不需要自行创建一个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实现,以备我们需要存储一些和principal无关的特殊信息。一个很好的例子就是我们的Jcaptcha集成,它需要知道一个需求是否是由人发起的。这样的判断和principal是否通过认证完全没有关系,因此我们将它保存在SecurityContext中。
从上述的代码片段可以看出的另一个问题是你可以从一个Authentication对象中获取一个principal。Principal只是一个对象。通
常可以把它cast为一个UserDetails对象。UserDetails在Acegi Security中是一个核心接口,它以一种扩展以及应用相关的方式来展现一个principal。可以把UserDetails看作是你的用户数据库和Acegi Security在
SecurityContextHolder所需要的东西之间的一个适配器(adapter)。作为你自己用户数据库的一个展现,你可能经常要把它cast到你应用程序提供的原始对象,这样你就可以调用业务相关的方法(例如 getEmail(), getEmployeeNumber())。
现在你可能已经开始疑惑,那我什么时候提供UserDetails对象呢?我要如何提供呢?
我想你告诉过我这个东西是声明式的,我不需要写任何Java代码-那怎么做到呢?对此的简短回答就是有一个叫做
UserDetailsService的特殊接口。这个接口只有一个方法,接受一个Sring类型的参数并返回
一个UserDetails。Acegi Security提供的大多数认证提供器将部分认证过程委派给
UserDetailsService。UserDetailsService用来构建保存在SecurityContextHolder中的Authentication对象。好消息是我们提供若干个UserDetailsService的实现,包括一个使用in-memory map和另一个使用JDBC的。
大多数用户还是倾向于写自己的实现,这样的实现经常就是简单的构建于已有的Data Access Object (DAO)上,这些DAO展现了他们的雇员、客户、或者其他企业应用程序中的用户。要记得这样做的好处,不论你的
UserDetailsService返回什么,它总是可以从SecurityContextHolder中获取,象上面的代码显示的那样。
除了principal,Authentication提供的另一个重要方法就是getAuthorities()。这个方法返回一个GrantedAuthority对象数组。GrantedAuthority,毫无疑问,就是授予