本站首页    管理页面    写新日志    退出


«October 2025»
1234
567891011
12131415161718
19202122232425
262728293031


公告
本博客在此声明所有文章均为转摘,只做资料收集使用。并无其他商业用途。

我的分类(专题)

日志更新

最新评论

留言板

链接

Blog信息
blog名称:
日志总数:210
评论数量:205
留言数量:-19
访问次数:924332
建立时间:2007年5月10日




[acegi权限认证]Acegi框架介绍2
文章收藏,  网上资源,  软件技术,  电脑与网络

李小白 发表于 2007/7/3 18:07:47

重要组件类介绍     每个框架都有一些核心的概念,这些概念被固化为类和接口,成为框架的重要组件类。框架的管理类、操作类都在这些组件类的基础上进行操作。在进入Acegi框架的具体学习前,有必要事先了解一下这些承载Acegi框架重要概念的组件类。     首先,我们要接触是UserDetails接口,它代表一个应用系统的用户,该接口定义了用户安全相关的信息,如用户名/密码,用户是否有效等信息,你可以根据以下接口方法进行相关信息的获取:     String getUsername():获取用户名;      String getPassword():获取密码;      boolean isAccountNonExpired():用户帐号是否过期;      boolean isAccountNonLocked():用户帐号是否锁定;      boolean isCredentialsNonExpired():用户的凭证是否过期;      boolean isEnabled():用户是否处于激活状态。     当以上任何一个判断用户状态的方法都返回false时,用户凭证就被视为无效。     UserDetails还定义了获取用户权限信息的方法:GrantedAuthority[] getAuthorities(),GrantedAuthority代表用户权限信息,它定义了一个获取权限描述信息(以字符串表示,如PRIV_COMMON)的方法:String getAuthority()。 500)this.width=500'>图 3 用户和权限     在未使用Acegi之前,我们可能通过类似User、Customer等领域对象表示用户的概念,并在程序中编写相应的用户认证的逻辑。现在,你要做的一个调整是让原先这些代表用户概念的领域类实现UserDetails接口,这样,Acegi就可以通过UserDetails接口访问到用户的信息了。     UserDetails可能从数据库、LDAP等用户信息资源中返回,这要求有一种机制来完成这项工作,UserDetailsService正是充当这一角色的接口。UserDetailsService接口很简单,仅有一个方法:UserDetails loadUserByUsername(String username) ,这个方法通过用户名获取整个UserDetails对象。 Authentication代表一个和应用程序交互的待认证用户,Acegi从类似于登录页面、Cookie等处获取待认证的用户信息(一般是用户名密码)自动构造Authentication实例。 500)this.width=500'>图 4 Acegi的认证用户     Authentication可以通过Object getPrincipal()获取一个代表用户的对象,这个对象一般可以转换为UserDetails,从中可以取得用户名/密码等信息。在Authentication被AuthenticationManager认证之前,没有任何权限的信息。在通过认证之后,Acegi通过UserDetails将用户对应的权限信息加载到Authentication中。Authentication拥有一个GrantedAuthority[] getAuthorities()方法,通过该方法可以得到用户对应的权限信息。     Authentication和UserDetails很容易被混淆,因为两者都有用户名/密码及权限的信息,接口方法也很类似。其实Authentication是Acegi进行安全访问控制真正使用的用户安全信息的对象,它拥有两个状态:未认证和已认证。UserDetails是代表一个从用户安全信息源(数据库、LDAP服务器、CA中心)返回的真正用户,Acegi需要将未认证的Authentication和代表真实用户的UserDetails进行匹配比较,通过匹配比较(简单的情况下是用户名/密码是否一致)后,Acegi将UserDetails中的其它安全信息(如权限、ACL等)拷贝到Authentication中。这样,Acegi安全控制组件在后续的安全访问控制中只和Authentication进行交互。 由于Acegi对程序资源进行访问安全控制时,一定要事先获取和请求用户对应的Authentication,Acegi框架必须为Authentication提供一个“寓所”,以便在需要时直接从“寓所”把它请出来,作为各种安全管理器决策的依据。     SecurityContextHolder就是Authentication容身的“寓所”,你可以通过SecurityContextHolder.getContext().getAuthenication()代码获取Authentication。细心观察一下这句代码,你会发现在SecurityContextHolder和Authentication之间存在一个getContext()中介,这个方法返回SecurityContext对象。SecurityContext这个半路杀出来的程咬金有什么特殊的用途呢?我们知道Authentication是用户安全相关的信息,请求线程其它信息(如登录验证码等)则放置在SecurityContext中,构成了一个完整的安全信息上下文。SecurityContext接口提供了获取和设置Authentication的方法:  Authentication getAuthentication()  void setAuthentication(Authentication authentication) 500)this.width=500'>图 5 认证用户信息存储器     SecurityContextHolder是Acegi框架级的对象,它在内部通过ThreadLocal为请求线程提供线程绑定的SecurityContext对象。这样,任何参与当前请求线程的Acegi安全管理组件、业务服务对象等都可以直接通过SecurityContextHolder.getContext()获取线程绑定的SecurityContext,避免通过方法入参的方式获取用户相关的SecurityContext。     线程绑定模式对于大多数应用来说是适合的,但是应用本身会创建其它的线程,那么只有主线程可以获得线程绑定SecurityContext,而主线程衍生出的新线程则无法得到线程绑定的SecurityContext。Acegi考虑到了这些不同应用情况,提供了三种绑定SecurityContext的模式:  SecurityContextHolder.MODE_THREADLOCAL:SecurityContext绑定到主线程,这是默认的模式;  SecurityContextHolder.MODE_GLOBAL:SecurityContext绑定到JVM中,所有线程都使用同一个SecurityContext;  SecurityContextHolder.MODE_INHERITABLETHREADLOCAL::SecurityContext绑定到主线程及由主线程衍生的线程中。     你可以通过SecurityContextHolder.setStrategyName(String strategyName)方法指定SecurityContext的绑定模式。 用户认证过程   Acegi支持多种方式的用户认证:如典型的基于数据库的认证、基于LDAP的认证、基于Yale中心认证等方式。不同的认证环境拥有不同的用户认证方式,现在我们先抛开这些具体的细节,考察一下Acegi对受限资源进行访问控制的典型过程:     1.你点击一个链接访问一个网页;     2.浏览器发送一个请求到服务器,服务器判断出你正在访问一个受保护的资源;     3.如果此时你并未通过身份认证,服务器发回一个响应提示你进行认证——这个响应可能是一个HTTP响应代码,抑或重定向到一个指定页面;     4.根据系统使用认证机制的不同,浏览器或者重定向到一个登录页面中,或者由浏览器通过一些其它的方式获取你的身份信息(如通过BASIC认证对话框、一个Cookie或一个X509证书);     5.浏览器再次将用户身份信息发送到服务器上(可能是一个用户登录表单的HTTP POST信息、也可能是包含认证信息的HTTP报文头);     6.服务器判断用户认证信息是否有效,如果无效,一般情况下,浏览器会要求你继续尝试,这意味着返回第3步。如果有效,则到达下一步;     7.服务器重新响应第2步所提交的原始请求,并判断该请求所访问的程序资源是否在你的权限范围内,如果你有权访问,请求将得到正确的执行并返回结果。否则,你将收到一个HTTP 403错误,这意味着你被禁止访问。     在Acegi框架里,你可以找到对应以上大多数步骤的类,其中ExceptionTranslationFilter、AuthenticationEntryPoint、AuthenticationProvider以及Acegi的认证机制是其中的代表者。     ExceptionTranslationFilter是一个Acegi的Servlet过滤器,它负责探测抛出的安全异常。当一个未认证用户访问服务器时,Acegi将引发一个Java异常。Java异常本身对HTTP请求以及如何认证用户是一无所知的,ExceptionTranslationFilter适时登场,对这个异常进行处理,启动用户认证的步骤(第3步)。如果已认证用户越权访问一个资源,Acegi也将引发一个Java异常,ExceptionTranslationFilter则将这个异常转换为HTTP 403响应码(第7步)。可见,Acegi通过异常进行通讯,ExceptionTranslationFilter接收这些异常并作出相应的动作。     当ExceptionTranslationFilter通过Java异常发现用户还未认证时,它到底会将请求重定向哪个页面以要求用户提供认证信息呢?这通过咨询AuthenticationEntryPoint来达到目的——Acegi通过AuthenticationEntryPoint描述登录页面。     当你的浏览器通过HTTP表单或HTTP报文头向服务器提供用户认证信息时,Acegi需要将这些信息收集到Authentication中,Acegi用“认证机制”描述这一过程。此时,这个新生成Authentication只包含用户提供的认证信息,但并未通过认证。AuthenticationProvider负责对Authentication进行认证。AuthenticationProvider究竟如何完成这一过程呢?请回忆一下上节我们所介绍的UserDetails和UserDetailsService,大多数AuthenticationProvider通过UserDetailsService获取和未认证的Authentication对应的UserDetails并进行匹配比较来完成这一任务。当用户认证信息匹配时,Authentication被认为是有效的,AuthenticationProvider进一步将UserDetails中权限、ACL等信息拷贝到Authentication。 当Acegi通过认证机制收集到用户认证信息并填充好Authentication后,Authentication将被保存到SecurityContextHolder中并处理用户的原始请求(第7步)。     你完全可以抛开Acegi的安全机制,编写自己的Servlet过滤器,使用自己的方案构建Authentication对象并将其放置到SecurityContextHolder中。也许你使用了CMA(Container Managed Authentication:容器管理认证),CMA允许你从ThreadLocal或JNDI中获取用户认证信息,这时你只要获取这些信息并将其转换为Authentication就可以了。  


阅读全文(2348) | 回复(0) | 编辑 | 精华
 



发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)



站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.577 second(s), page refreshed 144789447 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号