《Spring Security3》第六章第四部分翻译(异常处理)(转载)

配置Spring Security的访问拒绝处理

理解和配置异常处理

         Spring Security 使用简单的分发器模式将框架抛出的异常转移到明确的处理行为中,这将会影响用户对安全资源的访问。 Spring Security 过滤器链中最后几个过滤器之一的 o.s.s.web.access.ExceptionTranslationFilter 负责检查在认证和授权过程中(在过滤器链的最后一个过滤器即 FilterSecurityInterceptor 里)抛出的异常并采取适当的行为。

         标准的 ExceptionTranslationFilter 支持分发处理三种常规类型的失败,如下图所示:



 我们能够看到 ExceptionTranslationFilter 处理如下的场景:

抛出 AuthenticationException 异常,用户需要登录(在大多数场景下——取决于 AuthenticationEntryPoint ,我们将会在本章稍后介绍);

抛出 AccessDeniedException ,用户已经尚未登录;

抛出 AccessDeniedException ,用户已经登录,在这种场景下,展现给用户的要么是出错页面,要么是通用的 HTTP 403 响应。

让我们看一下 AccessDeniedHandler 的配置。

配置“Access Denied ”处理

         到此为止,当一个认证过的用户访问受保护的资源时,因为缺少 GrantedAuthority 或其它需要的权限被拒绝的时候,他们看到的是 servlet 容器的默认 HTTP 403 (访问拒绝)页面。这个页面是 o.s.s.web.access.AccessDeniedHandler 默认行为的结果,它被 ExceptionTranslationFilter 所触发以响应框架抛出的一个 AccessDeniedException 异常。

         尽管这个简单的出错页面有效,但是并不具有吸引力和也不对用户友好。最好能够将这个页面与我们站点整体的外观和风格一致,并为用户提供信息告诉他发生了什么。

         基本的处理用户访问拒绝报告的方法是配置自定义的 URLSpring Security 会在请求拒绝时,将用户带到这个 URL 。我们会发现这个功能与初始登录时,用户被定向到 <form-login> 元素声明的 login-page 很类似。

配置“ Access Denied ”的目标地址

         配置用户被定向到的地址是这个练习中最简单的部分。只需在 <http> 声明中,添加一个元素 <access-denied-handler> ,它指明了我们的访问拒绝处理 URL ,如下:

 

Xml代码  收藏代码
  1. < http   auto-config = "true"  ... >   
  2.   < access-denied-handler   error-page = "/accessDenied.do" />   
  3. </ http >   

 注意——还没完事呢,因为我们还没有将这个 URL 与任何的 Spring MVC 应用代码关联起来。我们需要在 LoginLogoutController 添加增强代码以处理这个 URL ,并推送一些有用的信息到 model 中供 view 展现给用户。

添加对 AccessDeniedException 处理的控制器

         我们需要添加一个控制器 action 处理方法以响应刚刚配置的 URL 。另外,我们会从 AccessDeniedException 抽取一些细节信息,这可能在用户看到我们自定义访问拒绝页面时有用。

 

Java代码  收藏代码
  1. @Controller   
  2. public   class  LoginLogoutController  extends  BaseController{  
  3.   // Ch 6 Access Denied   
  4.   @RequestMapping (method=RequestMethod.GET, value= "/accessDenied.do" ).  
  5.   public   void  accessDenied(ModelMap model, HttpServletRequest request) {  
  6.     AccessDeniedException ex = (AccessDeniedException)   
  7.     request.getAttribute(AccessDeniedHandlerImpl   
  8.     .SPRING_SECURITY_ACCESS_DENIED_EXCEPTION_KEY);  
  9.     StringWriter sw = new  StringWriter();  
  10.     model.addAttribute("errorDetails" , ex.getMessage());  
  11.     ex.printStackTrace(new  PrintWriter(sw));  
  12.     model.addAttribute("errorTrace" , sw.toString());  
  13.   }  
  14. }  

 注意的是,需要引用 AccessDeniedHandlerImpl 来获取 request 中指定名字的属性,它被用来临时存储当前 request 范围内的异常。

         遗憾的是, AccessDeniedException 并没有在它的 message 中提供足够的细节信息,而这对系统管理员和用户本身可能会有用。你可能会对使用 Spring SecurityAccessDeniedException 感兴趣或者可能扩展它以提供更多的上下文信息,以得到当授权检查不通过时用户正在试图进行什么操作。

 

编写 Access Denied 页面

         控制器写好后,接下来是访问拒绝页面。

 

Html代码  收藏代码
  1. < %@ page  language = "java"   contentType = "text/html; charset=ISO-8859-1"   
  2.   pageEncoding = "ISO-8859-1" % >   
  3. < jsp:include   page = "common/header.jsp" >   
  4.   < jsp:param   name = "pageTitle"   value = "Access Denied" />   
  5. </ jsp:include >   
  6. < h1 > Access Denied </ h1 >   
  7. < p >   
  8.   Access to the specified resource has been denied for   
  9.   the following reason: < strong > ${errorDetails} </ strong > .  
  10. </ p >   
  11. < em > Error Details (for Support Purposes only): </ em > < br   />   
  12. < blockquote >   
  13.   < pre > ${errorTrace} </ pre >   
  14. </ blockquote >   
  15. < jsp:include   page = "common/footer.jsp" />   

          你可以看到我们使用了在控制器设置的模型属性 errorDetailserrorTrace 。尽管不是很漂亮,但是这个页面完成了它的任务即用通用的站点导航,将用户带到了站点的其它区域并给他们提供了导致出错的提示信息。

什么会触发AccessDeniedException

         当设计异常处理时,进行一些分析并理解目标异常的原理很重要。对于 Spring Security 的用户来说,通常很迷惑的一件事就是 AccessDeniedException (默认会导致 HTTP 403 页面)和 AuthenticationException (一般当用户根本没有登录时抛出)。以下的指南可能会帮助你分清框架在什么时间抛出每种类型的异常:

异常类型

谁抛出以及原因

AuthenticationException

AuthenticationProvider ,当提供的凭证不合法或用户失效、过期;

DaoAuthenticationProvider ,当访问 DAO 数据存储时出错;

RememberMeServices ,当 remember me cookie 被篡改;

各种特定的认证类( CASNTLM 等)在用户特定的场景下。

AccessDeniedException

AccessDecisionManager ,当配置的 Voter 投票拒绝访问——注意这可能在任何投票场景下

         要记住的是,我们前面提到的 ExceptionTranslationFilter 是区分这两种类型异常的关键点,因为这关系到应用用户的请求和响应流程。

【注意过滤器链中在 ExceptionTranslationFilter 之前的那些过滤器。 ExceptionTranslationFilter 只会处理和响应过滤器链中在此之后的过滤器所抛出的异常。用户可能会感到迷惑,尤其是将自定义过滤器进行了不正确排序的时候,不明白为什么期望的行为与应用实际的异常处理不一致——在很多场景下,过滤器的顺序是原因所在。】

         尽管内置的处理流程在大多数情况下是可预测且满足需要的,但有时候你会需要自定义异常处理,尤其是在引入基类异常的自定义子类时,这需要过滤器链的特殊处理。

AuthenticationEntryPoint 的重要性

         AuthenticationEntryPoint (在 ExceptionTranslationFilter 我们看到它是工作流程中的一个辅助类)在处理未认证用户请求中很重要。当 ExceptionTranslationFilter 确定用户需要认证时,它请求 AuthenticationEntryPoint 以了解下一步要做什么。在基于 form 的认证中, o.s.s.web.authentication.LoginUrlAuthenticationEntryPoint 负责将用户定向到登录 form

         我们将会在后面的章节中看到 AuthenticationEntryPoint 被用在各种认证机制中,从而实现更个性化的行为——例如,在中心认证服务( CAS )单点登录中, AuthenticationEntryPoint 要确保用户被定向到 CAS 门户进行认证。

         在很多环境下,当实现 Spring Security 与第三方认证系统(独立于 web 应用)集成时,你需要实现自己的 AuthenticationEntryPoint

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值