Spring Security 3.0须要Java 5.0运行时环境或更高版本。因为Spring Security的目标是以独立的方式运行,因此没有必要将任何特殊的配置文件放入Java运行时环境中。特别是,不须要配置特殊的Java身份验证和受权服务(JAAS)策略文件,也不须要将Spring Security放在公共的类路径位置。html
一样,若是您使用的是EJB容器或Servlet容器,就不须要在任何地方放置任何特殊的配置文件,也不须要在服务器类加载器中包含Spring Security。全部必需的文件都将包含在您的应用程序中。web
这种设计提供了最大的部署时间灵活性,由于您能够简单地将您的目标工件(不管是JAR、WAR仍是EAR)从一个系统复制到另外一个系统,它将当即工做。spring
在Spring Security 3.0中,spring-security-core jar的内容被剥离到最低限度。它再也不包含任何与网络应用安全、LDAP或命名空间配置相关的代码。咱们将在这里看一看核心模块中的一些Java类型。它们表明框架的构建块,因此若是您须要简单的名称空间配置,那么理解它们是什么很重要,即便您实际上不须要直接与它们交互。数据库
最基本的对象是SecurityContextHolder(安全上下文持有者)。咱们在这里存储应用程序当前安全上下文的详细信息,包括当前使用该应用程序的主体的详细信息。默认状况下,SecurityContextHolder使用ThreadLocal来存储这些细节,这意味着安全上下文始终对同一执行线程中的方法可用,即便安全上下文没有做为参数显式传递给这些方法。这种状况下使用ThreadLocal是很是安全的,只要记得在处理完当前主体的请求之后,把这个线程清除就好了。固然,Spring Security自动帮你管理这一切了, 你就不用担忧什么了。小程序
有些程序并不适合使用ThreadLocal,由于它们处理线程的特殊方法。好比Swing客户端也许但愿Java Virtual Machine里全部的线程 都使用同一个安全环境。SecurityContextHolder能够在启动时配置策略,以指定您但愿如何存储上下文。对于独立的应用程序,您可使用SecurityContextHolderSecurityContextHolder能够在启动时配置策略,以指定您但愿如何存储上下文。对于独立的应用程序,您可使用SecurityContextHolder.MODE_GLOBAL策略。其余程序可能也想由安全线程产生的线程也承担一样的安全标识。这是经过使用SecurityContextHolder.MODE_INHERITABLETHREADLOCAL实现。第一个是设置系统属性,第二个是调用SecurityContextHolder的静态方法。大多数应用程序不须要修改默认值,可是若是你想要修改,能够看一下SecurityContextHolder的JavaDocs中的详细信息了解更多。数组
在SecurityContextHolder中,咱们存储当前与应用程序交互的主体的详细信息。Spring Security使用一个身份验证对象来表示这些信息。您一般不须要本身建立身份验证对象,可是用户查询身份验证对象是很常见的。您能够从应用程序中的任何位置使用如下代码块来获取当前通过身份验证的用户的名称,例如:浏览器
调用getContext()返回的对象是SecurityContext接口的一个实例。这是保存在线程本地存储中的对象。正如咱们将在下面看到的,Spring Security中的大多数身份验证机制都返回一个UserDetails实例做为主体。缓存
从上面的代码片断中须要注意的另外一点是,您能够从身份验证对象中获取一个主体。主体只是一个客体。大多数状况下,这能够转换成一个UserDetails对象。UserDetails是Spring安全的核心接口。它表明一个主体,可是以一种可扩展的和特定于应用程序的方式。将UserDetails视为您本身的用户数据库和SecurityContextHolder内部的Spring Security须要之间的适配器。做为来自您本身的用户数据库的表示,您常常会将UserDetails转换为您的应用程序提供的原始对象,所以您能够调用特定于业务的方法(如getEmail(),getEmployeeNumber(),等等)。安全
如今你可能想知道,我何时提供一个用户详细信息对象?我怎么作呢?我想你说这个东西是声明式的,我不须要写任何代码——什么给出了?服务器
简而言之,有一个叫作UserDetailsService(用户详细服务)的特殊接口。此接口上的惟一方法接受基于字符串的用户名参数并返回UserDetails(用户详细信息):
这是在Spring Security中为用户加载信息的最多见的方法,当须要关于用户的信息时,您会在整个框架中看到它的使用。
在成功的身份验证中,UserDetails(用户详细信息)用于构建存储在SecurityContextHolder中的Authentication(身份验证对象)(下面将详细介绍)。好消息是咱们提供了大量的用户细节服务实现,包括一个使用内存映射(InMemoryDaoImpl)的实现和一个使用JDBC (JdbcDaoImpl)的实现。然而,大多数用户倾向于编写本身的代码,他们的实现一般只是简单地位于表明他们的雇员、客户或应用程序的其余用户的现有数据访问对象(DAO)之上。请记住,不管您的UserDetailsService返回什么,均可以使用上面的代码片断从安全上下文持有者得到。
关于UserDetailsService常常会有一些混淆。它纯粹是用户数据的DAO,除了向框架内的其余组件提供数据以外,不执行其余功能。特别是,它不会对用户进行身份验证,这是由AuthenticationManager完成的。在许多状况下,若是须要自定义身份验证过程,直接实现AuthenticationProvider更有意义。
除了主体,身份验证提供的另外一个重要方法是getAuthorities()。这个方法提供了一个受权对象的数组。绝不奇怪,受权是授予委托人的权力。这种权限一般是“角色”,例如ROLE_ADMINISTRATOR或ROLE _ HR _ SUPERVISOR。这些角色稍后将针对web受权、方法受权和域对象受权进行配置。Spring Security的其余部分可以解释这些权限,并指望它们存在。受权对象一般由UserDetailsService加载。
一般授予的权限对象是应用程序范围的权限。它们并不特定于给定的域对象。所以,您不太可能拥有受权来表示对雇员对象编号54的权限,由于若是有成千上万个这样的权限,您将很快耗尽内存(或者至少致使应用程序花很长时间来验证用户)。固然,Spring Security是专门为处理这种常见需求而设计的,可是您可使用项目的域对象安全功能来实现这一目的。
简单回顾一下,目前为止咱们看到的Spring Security的主要构建模块是:
SecurityContextHolder,提供对SecurityContext的访问。
SecurityContext,用于保存Authentication和可能的特定于请求的安全信息。
Authentication,以Spring安全特定的方式表明主体。
GrantedAuthority,以反映授予主体的应用程序范围的权限。
UserDetails,提供必要的信息,以便从应用程序的DAOs或其余安全数据源构建身份验证对象。
UserDetailsService,当传入基于字符串的用户名(或证书标识等)时建立UserDetails。
如今您已经了解了这些重复使用的组件,让咱们更仔细地看看身份验证的过程。
Spring Security能够参与许多不一样的身份验证环境。虽然咱们建议人们使用Spring Security进行身份验证,而不要与现有的容器管理身份验证集成,可是它仍然受到支持,就像与您本身的专有身份验证系统集成同样。
让咱们考虑一个你们都熟悉的标准身份验证场景。
一、提示用户输入用户名和密码进行登陆。
二、系统(成功)验证用户名的密码是否正确。
三、获取该用户的上下文信息(他们的角色列表等等)。
四、为用户创建安全上下文。
五、用户继续执行一些操做,这些操做可能受到访问控制机制的保护,该机制根据当前的安全上下文信息检查操做所需的权限。
前三项构成了身份验证过程,所以咱们将看看这些是如何在Spring Security中发生的。
一、用户名和密码被获取并组合到一个UsernamePasswordAuthenticationToken的实例中(这是咱们前面看到的身份验证接口的一个实例)。
二、令牌被传递给AuthenticationManager的一个实例进行验证。
三、AuthenticationManager在身份验证成功时返回彻底填充的Authentication。
四、经过调用securitycontextholder . GetContext()来创建安全上下文。设置身份验证(…),传入返回的身份验证对象。
从这一点上来看,用户被认为是被验证的。让咱们看看一些代码做为一个例子:
这里,咱们编写了一个小程序,要求用户输入用户名和密码,并执行上面的序列。咱们在这里实现的身份验证管理器将验证用户名和密码相同的任何用户。它为每一个用户分配一个角色。上面的输出将相似于:
请注意,你一般不须要写任何这样的代码。这个过程一般会发生在内部,以一个web认证过滤器为例,咱们刚刚在这里的代码显示,在Spring Security中到底是什么构成了验证的问题,有一个相对简单的答案。用户验证时,SecurityContextHolder包含一个彻底填充的Authentication对象的用户进行身份验证。
默认状况下,使用StrictHttpFirewall。该实现拒绝看似恶意的请求。若是它对你的需求来讲太严格,那么你能够定制什么类型的请求被拒绝。然而,重要的是你要知道这可能会使你的应用程序受到攻击。例如,若是您但愿利用Spring MVC的矩阵变量,能够在XML中使用如下配置:
一样的事情也能够经过Java配置来实现,方法是公开一个StrictHttpFirewall bean。
事实上,Spring Security并不介意如何将身份验证对象(Authentication)放入SecurityContextHolder中。惟一关键的要求是SecurityContextHolder包含一个身份验证(Authentication),该身份验证在抽象安全接口(AbstractSecurityInterceptor)(咱们将在后面详细讨论)须要受权用户操做以前表明一个主体。
您能够(许多用户也能够)编写本身的过滤器或MVC控制器,以提供与不基于Spring安全的身份验证系统的互操做性。例如,您可能正在使用容器管理的身份验证,这使得当前用户能够从线程本地或JNDI位置访问。或者,你可能在一家拥有传统专有认证系统的公司工做,这是一个你几乎没法控制的公司“标准”。在这种状况下,很容易让Spring Security工做,而且仍然提供受权功能。您须要作的只是编写一个过滤器(或等效工具),从一个位置读取第三方用户信息,构建一个Spring安全特定的身份验证对象(Authentication),并将其放入安全上下文持有者(SecurityContextHolder)。在这种状况下,您还须要考虑一般由内置身份验证基础结构自动处理的事情。例如,在向客户端脚注写入响应以前,您可能须要先建立一个HTTP会话来缓存请求之间的上下文:一旦提交了响应,就不可能建立会话。
若是您想知道AuthenticationManager是如何在实际示例中实现的,咱们将在核心服务一章( core services chapter)中讨论这一点。
如今让咱们探讨一下在web应用程序中使用Spring Security的状况(没有启用web.xml安全性)。如何对用户进行身份验证并创建安全上下文?
考虑一个典型的web应用程序的身份验证过程:
一、你访问主页,点击一个连接。
二、一个请求到达服务器,服务器决定您已经请求了一个受保护的资源。
三、因为您目前没有经过身份验证,服务器会发回一个响应,指示您必须经过身份验证。该响应或者是一个HTTP响应代码,或者是一个到特定网页的重定向。
四、根据身份验证机制,您的浏览器要么重定向到特定的网页以便您填写表单,要么浏览器以某种方式检索您的身份(经过基自己份验证对话框、cookie、X.509证书等)。)。
五、浏览器将向服务器发回响应。这要么是一个包含您填写的表单内容的HTTP POST,要么是一个包含您的身份验证详细信息的HTTP标头。
六、接下来,服务器将决定呈现的凭证是否有效。若是它们是有效的,下一步就会发生。若是无效,一般你的浏览器会被要求再试一次(因此你回到上面的第二步)。
七、将重试您为致使身份验证过程而提出的原始请求。但愿你已经经过了足够的受权来访问受保护的资源。若是您有足够的访问权限,请求将会成功。不然,您将收到一个返回的HTTP错误代码403,这意味着“禁止”。
Spring Security有不一样的类来负责上面描述的大部分步骤。主要参与者(按使用顺序)是异常转换过滤器(ExceptionTranslationFilter),一个AuthenticationEntryPoint和一个“身份验证机制(authentication mechanism)”,负责调用咱们在上一节中看到的AuthenticationManager。
ExceptionTranslationFilter是一个Spring安全筛选器,负责检测引起的任何Spring安全异常。这种异常一般会被抽象安全接口(AbstractSecurityInterceptor)抛出,它是受权服务的主要提供者。咱们将在下一节讨论抽象安全接口,可是如今咱们只须要知道它产生了Java异常,而且对HTTP或者如何验证主体一无所知。相反,ExceptionTranslationFilter提供此服务,具体负责返回错误代码403(若是主体已通过身份验证,所以缺乏足够的访问权限,如上面的步骤七),或者启动AuthenticationEntryPoint(若是主体还没有经过身份验证,所以咱们须要开始步骤三)。
AuthenticationEntryPoint负责上述列表中的第三步。能够想象,每一个web应用程序都有一个默认的身份验证策略(能够像Spring Security中的其余任何东西同样进行配置,可是如今让咱们保持简单)。每一个主要的身份验证系统都有本身的AuthenticationEntryPoint实现,它一般执行步骤3中描述的操做之一。
一旦您的浏览器提交了您的身份验证凭据(或者做为一个HTTP表单帖子,或者做为一个HTTP头),服务器上就须要有一些东西来“收集”这些身份验证的详细信息。到如今为止,咱们已经在上面列表的第六步了。在Spring Security中,咱们为从用户代理(一般是web浏览器)收集身份验证详细信息的功能起了一个特殊的名字,将其称为“身份验证机制(authentication mechanism)”。例如基于表单的登陆和基自己份验证。一旦从用户代理收集了身份验证详细信息,就会构建一个身份验证(Authentication)“请求”对象,而后呈现给身份验证管理器(AuthenticationManager)。
在身份验证机制收到彻底填充的身份验证(Authentication)对象后,它将认为请求有效,将身份验证(Authentication)放入SecurityContextHolder中,并重试原始请求(上面的第七步)。另外一方面,若是AuthenticationManager拒绝了请求,身份验证机制将要求用户代理重试(上面的第二步)。
根据应用程序的类型,可能须要一个策略来存储用户操做之间的安全上下文。在典型的web应用程序中,用户登陆一次,随后由他们的会话Id标识。服务器缓存持续会话的主体信息。在Spring Security中,在请求之间存储SecurityContext的责任属于SecurityContextPersistenceFilter,默认状况下,它将上下文存储为HTTP请求之间的HTTP会话属性。它将每一个请求的上下文还原到SecurityContextHolder,而且在请求完成时清除SecurityContextHolder。出于安全目的,您不该该直接与HttpSession交互。这样作是没有任何理由的——老是使用SecurityContextHolder。
许多其余类型的应用程序(例如,无状态的RESTful web服务)不使用HTTP会话,而且会在每次请求时从新进行身份验证。可是,链中包含securitycontextPersistenceFilter仍然很重要,以确保每次请求后都清除了SecurityContextHolder。
在单个会话中接收并发请求的应用程序中,同一安全上下文实例将在线程之间共享。即便正在使用线程本地,它也是从每一个线程的HttpSession中检索的同一个实例。若是您但愿临时更改线程运行的上下文,这是有意义的。若是您只使用securitycontextholder . GetContext(),并对返回的上下文对象调用设置身份验证(anAuthentication),则身份验证对象将在共享同一个SecurityContext实例的全部并发线程中更改。您能够自定义securitycontextPersistenceFilter的行为,为每一个请求建立一个全新的SecurityContext,防止一个线程中的更改影响另外一个线程。或者,您能够在临时更改上下文的位置建立一个新实例。方法securitycontextholder . createemptycontext()老是返回一个新的上下文实例。
在Spring Security中,负责作出访问控制决策的主要接口是访问决策管理器(AccessDecisionManager)。它有一个decide方法,它须要一个Authentication对象请求访问、一个"secure object"(安全对象)(见下文)和安全元数据属性的列表适用的对象(例如授予访问所需的角色列表)。
若是你熟悉AOP,你会意识到有不一样类型的建议可用:以前,以后,抛出和周围。循环建议很是有用,由于advisorSpring Security为方法调用和web请求提供了一个全面的建议。咱们使用Spring的标准AOP支持实现了方法调用的循环建议,并使用标准过滤器实现了web请求的循环建议。能够选择是否继续方法调用、是否修改响应以及是否抛出异常。
对于那些不熟悉AOP的人来讲,须要理解的关键一点是,Spring安全性能够帮助您保护方法调用和web请求。多数人对保护他们服务层上的方法调用感兴趣。这是由于服务层是当前一代Java EE应用程序中大多数业务逻辑所在的地方。若是您只须要保护服务层中的方法调用,Spring的标准AOP就足够了。若是您须要直接保护域对象,您可能会发现AspectJ是值得考虑的。
您能够选择使用AspectJ或Spring AOP来执行方法受权,也能够选择使用过滤器来执行web请求受权。你能够同时使用零、1、二或三种方法。主流的使用模式是执行一些web请求受权,再加上服务层上的一些Spring AOP方法调用受权。
那么什么是“安全对象”?Spring Security使用该术语来指代任何能够应用安全性(例如受权决策)的对象。最多见的例子是方法调用和web请求。
每一个受支持的安全对象类型都有本身的拦截器类,它是抽象安全拦截器(AbstractSecurityInterceptor)的子类。重要的是,在调用抽象安全拦截器(AbstractSecurityInterceptor)时,若是主体已通过身份验证,安全上下文持有者(SecurityContextHolder)将包含有效的身份验证(Authentication)。
抽象安全拦截器(AbstractSecurityInterceptor)为处理安全对象请求提供了一致的工做流,一般:
一、查找与当前请求相关联的“配置属性”。
二、将安全对象、当前身份验证和配置属性提交给访问决策管理器(AccessDecisionManager)进行受权决策。
三、有可能在调用的过程当中,对Authentication进行修改。
四、容许安全对象调用继续进行(假设授予了访问权限)。
五、调用返回后,调用AfterInvocationManager(若是已配置)。若是调用引起了异常,将不会调用AfterInvocationManager。
一个"配置属性"能够看作是一个字符串,它对于AbstractSecurityInterceptor使用的类是有特殊含义的。它们由框架中的接口ConfigAttribute表示。它们多是简单的角色名,也可能有更复杂的含义,这取决于AccessDecisionManager实现的复杂程度。AbstractSecurityInterceptor配置有一个安全数据源(SecurityMetadataSource),用于查找安全对象的属性。一般这种配置对用户是隐藏的。配置属性将做为安全方法上的注释或安全网址上的访问属性输入。例如,当咱们在名称空间介绍中看到相似< intercept-url pattern='/secure/**' access='ROLE_A,ROLE_B'/>的内容时,这意味着配置属性ROLE_A和ROLE_B适用于与给定模式匹配的web请求。实际上,使用默认的访问决策管理器(AccessDecisionManager)配置,这意味着任何拥有与这两个属性之一匹配的受权(GrantedAuthority)的人都将被容许访问。严格地说,它们只是属性,解释依赖于AccessDecisionManager的实现。前缀ROLE_的使用是一个标记,表示这些属性是角色,应该由Spring Security的RoleVoter使用。只有在使用基于投票者的访问决策管理器(AccessDecisionManager)时,这才是相关的。咱们将在受权一章中看到如何实现AccessDecisionManager。
假设AccessDecisionManager决定容许执行这个请求,AbstractSecurityInterceptor会正常执行这个请求。话虽如此,在极少数状况下,用户可能但愿用不一样的身份验证来替换安全上下文(SecurityContext)中的身份验证(Authentication),该身份验证由调用运行管理器(RunAsManager)的访问决策管理器(AccessDecisionManager)来处理。
在至关不常见的状况下,例如服务层方法须要调用远程系统并显示不一样的标识时,这可能颇有用。 因为Spring Security会自动将安全身份从一台服务器传播到另外一台服务器(假设您使用的是正确配置的RMI或HttpInvoker远程协议客户端),所以这颇有用。
在安全对象调用继续进行以后,而后返回-这可能意味着方法调用完成或过滤器链继续进行-AbstractSecurityInterceptor得到了处理调用的最后机会。在此阶段,AbstractSecurityInterceptor对可能修改返回对象感兴趣。 咱们可能但愿发生这种状况,由于没法在安全对象调用的“途中”作出受权决定。因为高度可插拔,AbstractSecurityInterceptor会将控制权传递给AfterInvocationManager,以根据须要实际修改对象。 此类甚至能够彻底替换对象,或者引起异常,也能够按照其选择的任何方式对其进行更改。调用后检查仅在调用成功的状况下执行。 若是发生异常,将跳过其余检查。图9.1“安全拦截器和“安全对象”模型”中显示了AbstractSecurityInterceptor及其相关对象。
只有考虑一种全新的拦截和受权请求方式的开发人员才须要直接使用安全对象。例如,能够构建一个新的安全对象来保护对消息传递系统的调用。任何须要安全性而且提供拦截调用方式的东西(好比关于建议语义的AOP)都可以被作成一个安全的对象。尽管如此,大多数Spring应用程序将简单地使用当前支持的三种安全对象类型(AOP联盟方法定位、AspectJ链接点和web请求过滤器调用),而且彻底透明。
那么什么是“安全对象”?Spring Security使用该术语来指代任何能够应用安全性(例如受权决策)的对象。最多见的例子是方法调用和web请求。
每一个受支持的安全对象类型都有本身的拦截器类,它是抽象安全拦截器(AbstractSecurityInterceptor)的子类。重要的是,在调用抽象安全拦截器(AbstractSecurityInterceptor)时,若是主体已通过身份验证,安全上下文持有者(SecurityContextHolder)将包含有效的身份验证(Authentication)。
抽象安全拦截器(AbstractSecurityInterceptor)为处理安全对象请求提供了一致的工做流,一般:
一、查找与当前请求相关联的“配置属性”。
二、将安全对象、当前身份验证和配置属性提交给访问决策管理器(AccessDecisionManager)进行受权决策。
三、有可能在调用的过程当中,对Authentication进行修改。
四、容许安全对象调用继续进行(假设授予了访问权限)。
五、调用返回后,调用AfterInvocationManager(若是已配置)。若是调用引起了异常,将不会调用AfterInvocationManager。
一个"配置属性"能够看作是一个字符串,它对于AbstractSecurityInterceptor使用的类是有特殊含义的。它们由框架中的接口ConfigAttribute表示。它们多是简单的角色名,也可能有更复杂的含义,这取决于AccessDecisionManager实现的复杂程度。AbstractSecurityInterceptor配置有一个安全数据源(SecurityMetadataSource),用于查找安全对象的属性。一般这种配置对用户是隐藏的。配置属性将做为安全方法上的注释或安全网址上的访问属性输入。例如,当咱们在名称空间介绍中看到相似< intercept-url pattern='/secure/**' access='ROLE_A,ROLE_B'/>的内容时,这意味着配置属性ROLE_A和ROLE_B适用于与给定模式匹配的web请求。实际上,使用默认的访问决策管理器(AccessDecisionManager)配置,这意味着任何拥有与这两个属性之一匹配的受权(GrantedAuthority)的人都将被容许访问。严格地说,它们只是属性,解释依赖于AccessDecisionManager的实现。前缀ROLE_的使用是一个标记,表示这些属性是角色,应该由Spring Security的RoleVoter使用。只有在使用基于投票者的访问决策管理器(AccessDecisionManager)时,这才是相关的。咱们将在受权一章中看到如何实现AccessDecisionManager。
假设AccessDecisionManager决定容许执行这个请求,AbstractSecurityInterceptor会正常执行这个请求。话虽如此,在极少数状况下,用户可能但愿用不一样的身份验证来替换安全上下文(SecurityContext)中的身份验证(Authentication),该身份验证由调用运行管理器(RunAsManager)的访问决策管理器(AccessDecisionManager)来处理。
在至关不常见的状况下,例如服务层方法须要调用远程系统并显示不一样的标识时,这可能颇有用。 因为Spring Security会自动将安全身份从一台服务器传播到另外一台服务器(假设您使用的是正确配置的RMI或HttpInvoker远程协议客户端),所以这颇有用。
在安全对象调用继续进行以后,而后返回-这可能意味着方法调用完成或过滤器链继续进行-AbstractSecurityInterceptor得到了处理调用的最后机会。在此阶段,AbstractSecurityInterceptor对可能修改返回对象感兴趣。 咱们可能但愿发生这种状况,由于没法在安全对象调用的“途中”作出受权决定。因为高度可插拔,AbstractSecurityInterceptor会将控制权传递给AfterInvocationManager,以根据须要实际修改对象。 此类甚至能够彻底替换对象,或者引起异常,也能够按照其选择的任何方式对其进行更改。调用后检查仅在调用成功的状况下执行。 若是发生异常,将跳过其余检查。图9.1“安全拦截器和“安全对象”模型”中显示了AbstractSecurityInterceptor及其相关对象。
只有考虑一种全新的拦截和受权请求方式的开发人员才须要直接使用安全对象。例如,能够构建一个新的安全对象来保护对消息传递系统的调用。任何须要安全性而且提供拦截调用方式的东西(好比关于建议语义的AOP)都可以被作成一个安全的对象。尽管如此,大多数Spring应用程序将简单地使用当前支持的三种安全对象类型(AOP联盟方法定位、AspectJ链接点和web请求过滤器调用),而且彻底透明。
Spring Security支持最终用户可能看到的异常消息的本地化。若是您的应用程序是为说英语的用户设计的,您不须要作任何事情,由于默认状况下全部的安全消息都是英语的。若是您须要支持其余语言环境,您须要知道的一切都包含在本节中。
全部异常消息均可以本地化,包括与身份验证失败和访问被拒绝(受权失败)相关的消息。针对开发人员或系统部署人员的异常和日志消息(包括不正确的属性、违反接口约定、使用不正确的构造函数、启动时间验证、调试级日志记录)没有本地化,而是在Spring Security的代码中用英语硬编码。
在spring-security-core-xx.jar中,您会找到一个org.springframework.security包,该包又包含一个messages.properties文件,以及一些常见语言的本地化版本。这应该由您的应用程序上下文来引用,由于Spring Security 类实现了Spring的MessageSourceAware 接口,并指望消息解析器在应用程序上下文启动时被依赖注入。一般,您须要作的只是在应用程序上下文中注册一个bean来引用消息。下面是一个例子:
messages.properties是根据标准资源包命名的,表明Spring Security消息支持的默认语言。这个默认文件是英文的。
若是您但愿自定义messages.properties文件,或者支持其余语言,您应该复制该文件,对其进行相应的重命名,并在上面的bean定义中注册它。
这个文件中没有大量的消息键,因此本地化不该该被认为是一个主要的举措。若是您确实执行了此文件的本地化,请考虑经过记录JIRA任务并附加适当命名的本地化版本的messages.properties来与社区共享您的工做。
spring安全依赖于Spring的本地化支持,以便实际查找适当的消息。为了实现这一点,您必须确保来自传入请求的区域设置存储在Spring的org . Spring framework . context . i18n . localeContextholder中。Spring MVC的DispatcherServlet会自动为您的应用程序执行此操做,可是因为Spring Security的过滤器是在此以前调用的,所以在调用过滤器以前,须要将LocaleContextHolder设置为包含正确的区域。您能够本身在一个过滤器中完成这项工做(这个过滤器必须在Spring Security过滤器以前)。有关在Spring中使用本地化的更多详细信息,请参考Spring框架文档。“contacts人”示例应用程序被设置为使用本地化消息。