??xml version="1.0" encoding="utf-8" standalone="yes"?>
开放,灉|的架构?br />1. Z标准Q易于理解的设计
2. ZWebLogic Server应用的端对端的安全(从主机到览器)
3. 能与已存在的安全规则(Scheme)q行集成Q从而有利于保护企业投资?br />4. 安全的工具集成到一个灵z,l一架构的系l以便于在企业q行安全理
5. 通过公司的业务规则和安全policies的对应,能方便实现根据业务需求客户化应用安全
6. 易于Security Policy的更新?br />7. 易于客户化安全解x案的变化?br />8. 因ؓh模块化的架构Q因此安全架构能Ҏ不同公司的特D需求不断变?br />9. 能够配置多个Security Provider
10. 安全实现l节和应用基架构分离Q安全更易于部|Ԍ理Q维护和Ҏ需求变?br />11. 当前的WebLogic Security providers提供了和应用无关的可行的安全规则。(SchemeQ?br />12. 使用WebLogic custom security providerq行客户化工?br />13. 通过理控制台进行统一的安全规?Rule),Security Policy和Security Provider的统一理
14. Ҏ新的J2EE安全技术的支持Q包括JAAS(Java Authentication and Authorization Service),JSSE(java Secure Sockets Extensions),and JCE(java Cryptography Extensions)
易于使用Q?/b>Ҏl用戯言Q只需要登陆一ơ,p讉K所有资源(SSOQ,Q限制在WebLogic DomainQ?br />可管理:提供WebLogic security Provider,当前的Provider支持所有需要的安全功能QSecurity Data存放在WebLogic Server提供的LDAP Server?br />客户? WebLogic Security API,JAAS,JSSE custom security provider through SSPIs(WebLogic Server Security Service Provider Interfaces) |
WebLogic Server 6.x | WebLogic Server70 |
安全的API | 非常多的已存在API不推荐用,BEA使用ZJ2EE规范的标准接口实现应? |
JAAS认证 | JAAS认证增强已提供对于IIOP和t3客户端访问的LoginModules |
审计 | 无需实现WebLogic.security.Audit接口已在你的应用中加入审计功能,WebLogic Auditing provider已提供? |
定义weblogic.xml和weblogic-ejb-jar.xml和weblogic-ra.xml中的安全需? | 增强可以通过理控制台定? |
pȝ密码 | 没有指定的系l̎? |
ACL | ACL已经不推荐用,q由security policy代替 |
用户和组 | 仍然存在Qƈ通过security policyweblogic resouce赋予user,group或security role |
6.x安全Realm | 不推荐用,但仍存在Realm Adapter当你q行安全的{换时 |
支持多个Security Provider | |
SSL | 支持JSSE标准和TLS v1(Transport Layer Security)协议 |
支持J2EE JKS keystores |
Authentication(认证)
通过使用username/passwordl合来判断用h否是一个系l的合法用户Q主要回{?Who Are You?"的问题?br />
Principal认证通过后赋予用hl的w䆾QIdentityQSubject JAAS 要求通过subjectQContainer知道客户信息Q包括pricipals |
·Relationships Among Users, Groups, Principals and Subjects |
2. JAAS
JAAS实现了java版本的PAM模块Q允许应用和后层采用的认证技术,同时允许再不更改应用的情况下采用更新的或者变化了的安全认证技术?br />WebLogic sever使用JAAS在胖客户端认证和内部认证,因此Q只有客户化Authentication Provider的开发者和q程胖客L需要直接用JAAS, Thin 客户端和在container内的胖客L(EJB throgh servelt)不需要直接用JAAS.
·JAAS LoginModules
认证用户Q发布Subject.不用于perimeter authentication
·JAAS Control Flags
Multiple Authentication provider configured
REQUIRED : 必须成功Q如果失败,authenticationl箋其他的LoginModule(当前)
REQUISITE:必须成功Q成功l,不成功,返回应用?br />SUFFICIENTQ不需要成功,如果成功Q返回应用,如果p|QlLoginModule List
OPTIONAL:允许成功或失败,但必通过一个LoginModule
·CallBackHandlers
CallbackHandler 是ؓ参数或复杂对象传入Ҏ中的一U高度灵zȝ规范。包括NameCallback:return username
PasswordCallback:return password
TextInputCallback: return 用户在Login form中输入的数据?br />Security service不同的Callback传入CallbackHandler要求获取不同cd的信息,CallbackHandler的实现决定如何根据不同的Callback获取和显C?/p>
·Mutual Authentication
客户端和服务端都需要相互认证,WebLogic Server支持2-way SSL
·Identity Assertion Providers and LoginModules
当和LoginModules一起用时QIdentity Assertion provider支持Sigle-sign-on,LoginModule包含Q?br />
用户?口o认证:SSL,HTTPS CA(Certification Authentication):当SSL或HTTPS客户h发vӞWebLogic Server回应客户一个数字认证(digital certificationQ,客户证实q个数字认证从而徏立SSL联结Q数字认证是׃证机构CA发放?br />Perimeter Authentication 主要用于应用服务器外的远E用L认证q程 q程用户指定assert identity和相应得材料来完成?br />Authentication agent能采用各U格式,VPN,Firewall,企业U认证服务?br />Authentication agent处理认证q程同时Dartifact和token产生。Identity assertion的概联weblogic server能用perimeter authentication schemes提供的认证机Ӟ比如Checkpoint's OPSEC,the emerging Security Assertion Markup Language(SAML), enhancement of Common Secure Interoperability(CSI)v2完成功能?/td> |
WebLogic resource:包含
理资源
应用资源
COM资源
EIS资源
EJB
JDBC
JMS
JNDI
Server资源
URL资源
Web Service资源
·Security Policy
代替ACL,主要回答的问题是QWho have access to WebLogic resource?
当你weblogic resource和用Pl,security role相关联时QSecurity Policy产生?br />Security Policy存储在Authorization Provider的数据库中,当前的WebLogic Authorization provider存在LDAP Server?br />BEA推荐在security role上徏立security policy.
·ContextHandlers
从resource container中获取context和有关container的信息,为security provider做出讉K或权限mapping军_的提供信息?br />
·Adjudication
解决了当多个Authorization Provider提供授权时生的冲突问题。Adjudication Server权衡多个Access Decision的结果,q且军_最lpermit或者deny的结果。当唯一的Authorization providerq回l果为ABSTAINӞAdjudication provider军_怎样处理?/p>
·SSL
当前WebLogic Server支持1-way方式的SSL认证Q用管理控制台Q能够配|?-way的SSL.
需要配|privite key,包括public key的数字证?digital certificate)Q和臛_׃个CA认证的数字证?digital certificate),有可能需要安装root trusted CA's digital certificate.
取数字证书,自己生成public key,private key和认证签名请?CSR)(包含public key),同时CSR发到认证机构已得到签名的证书?br />Public key存放在WebLogic domain目录下的文gpȝ?br />Private key和通过认证的证书能存放在文件系l或通过WebLogic keystore provider提供的keystore中?/p>
SSL提供
1Q?应用间沟通的机制便于认证双方的n?br />2Q?应用间交换数据的加密?/p>
Server authentication:WebLogic Server使用l过CA{的数字证书,向客戯证。当客户不需要向Server证明自己的数字证书时Q这U联接的方式?-way SSL认证?br />Client Identity Verification:可选的Q客户必dWebLogic Server出示数字证书,WebLogic Server证实数字证书由CA发放同时建立SSL联结Q这U方式叫2-way SSL认证?br />Confidentiality所有客Lh和Server的相应在|络上的传输都加密?br />数据完整?客户端和服务端传输的数据受保护?/p>
SSL Tunneling
SSL是在ZIP协议上Tuneled.意味着每个SSLU录被封装同时有使它在其他协议上发送的header来包装?/p>
One-way/Two-way SSL认证
在One-way情况下,客户端通过两种方式查数字认?br />1Q?查数字认证在它的可信任认证机构中(CA)
2Q?查认证中的主机名和Server一致?br />
Exportable SSL支持512位证书和40-?0-位数据加密(标准支持Q?br />Domestic SSL支持768位和 1024位证书和128位数据加?Ask BEA Sales) |
当定义一个用hQWebLogic 对用L密码q行加密Q同时当WebLogic接收到客戯求时Q客Lh的密码被hash加密,同时和以存在的加密密码比较以判断是否W合?/p>·l?br />l是用户的逻辑l合。在一个Security Realm中,所有的用户和组必须唯一?
·Security Role
动态赋予用户和l,Ҏ用户名,l的成员或一天中的某个时间?
能在一个WebLogic server的域中,针对单个应用定义资源?/p>
在weblogic 6.x中,security role只能赋予web application ?EJB, ?70版本中,用户的security role能扩展到所有的WebLogic资源?/p>·Security Policy
Policy是WebLogic资源和用Pl,和Security Role的关联。用以保护WebLogic资源不收不被授权的用戯问。它代替?.x中用的ACL
·Security Provider
对应用提供安全服务的模块Q用以保护WebLogic资源Q客戯够直接用WebLogic Server直接提供的security provider,也能购买W三方的产品q行集成Q或者开发自qsecurity provider.
Security Provider数据?br />Security Provider数据库包含用Pl,role和policy,以及有些安全提供者用的密码。比如Authentication provider要求用户和组的信息。Authorization provider要求安全policy斚w的信息,Role Mapping Provider要求安全Role斚w的信息,Credential Mapping provider要求resource Adapter用于联结后台的EISpȝ的密码信息。这些信息都存放在数据库中?/p>
Security provider的数据库在递一ơ用security provider时候被初始化,所做的工作?br />当WebLogic实例重v?
当一个security provider的Mbean被调用?/p>
当你在一个security realm中配|了多个security provider,那么q些security provider是用同一个security provider数据库。当你在不同的security realm中配|两个security provider或两个相同的security provider,他们用不同的provider database.,在一个时间只有一个security Realm处在Ȁzȝ态?br />
·Embedded LDAP Server
Embedded LDAP Server被当前的WebLogic security provider使用作ؓ数据库存储用Pl,role和policy. 是一个完整的LDAP Server,支持的操作有Q?br />在LDAP Server中访问和修改
使用LDAP browser导入或导出安全的数据
被WebLogic security providerd讉K?br />WebLogic Server不支持在Embedded LDAP Server中加入属?Attribute)
WebLogic Security Provider | Embedded LDAP Server Usage |
Authentication | Stores user and group information. |
Identity Assertion | Stores user and group information. |
Authorization | Stores security roles and security policies. |
Adjudication | None. |
Role Mapping | Supports dynamic role associations by obtaining a computed set of roles granted to a requestor for a given WebLogic resource. |
Auditing | None. |
Credential Mapping | Stores Username-Password credential mapping information. |
·Security Provider的类?br />Authentication Provider
主要用于:
用户?密码的认?br />直接和WebLogic ServerZ证书的认?br />通过外部的web serverZHTTP证书的认证代?/p>
Identity Assertion Provider主要用于处理Zperimeter的认证和多个安全另牌(token)cd和协议?/p>
在安全域中必至有一个Authentication provider,同时你可以配|多个Authentication Provider,意味着你有多个LoginModules,每个处理不同的认证。管理员配置不同的provider以便于当用户登陆pȝ时多个LoginModules怎样被调用?br />Identity Assertion Provider
使用客户提供的可能存在于h外的Token识别客户的n份?br />
WebLogic Security Service Architecture(架构)
Security Framwork
security framework提供的应用API被security和应用开发者定义安全服务用,同时做ؓweblogic Container(Web和EJB),资源 Container和安全提供者间的中间层?/p>
下面详细描述各层间的交互
当用户通过username/passwdl和登陆pȝӞWebLogic建立信Q同时对于每个JAASh回送包含principal的subject?/p>
通过认证后,一个authentication context建立?/p>
·Identity Assertion Process
主要用于perimeter authenticationq程Q当使用perimeter authenticationӞ外部pȝ传入tokenlIdentity Assertion Provider.如果通过QIdentity Assertion providertoken对应到相应的username,q将回送username到weblogic server,然后由WebLogic Serverusername送回到JAAS的CallbackHandlerq传递到每个配置的Authentication Provider的LoginModule模块Q最后LoginModule能生包含正principal的Subject.
·Principal Validation Process
WebLogicsubject传递给principal validation Provider,后者将对principalq行{q过WebLogic Server把他回送客L应用。以后principal validation provider用来证明经q签名的subject中的principal没有被别人改q?/p>
Authorization process
Authenorization process最初由用户或系l要求用WebLogic Server资源时触发。Resource Container处理被请求的资源?Resource Container调用WebLogic Security Framwork同时传递给它相应的hsubject和请求resource的信息。WebLogic framework调用配置的role mapping provider,同时传递的信息转换成相应的格式Q由Role Mapping provider回送role的列表给WebLogic security framework, Authorization provider军_subject是否有访问相兌源的权限Q如果配有多个Authorization provider,WebLogic security framework军_M有冲H的讉K判断传递给Adjudication Provider,最后由Adjudication Provider军_最l的讉K许可?
·Role Mapping Process
WebLogic security framework调用每个role mapping provider以得到请求的role listQ如果security policy指定h赋予相应的role,rolep加入到subject可用的role list中,同时role list q回lWebLogic security framwork做ؓ下一步访问控制的判断?br />
·Auditing Process
Authentication Provider除了提供认证服务外,需要发送audit事gQ初始化AuditEvent对象Q包含audit的eventcd和audit的别),Authentication Provider随后调用Audit Provider,同时传递AuditEvent对象Q当AuditEvent和Auditing Provider配置的需要Audit的信息相同时Q将被记录到文gpȝQ数据库或其他存储介质中?br />
·Credential Mapping Process
最初由应用lgQ包括jsp,ejb,resource adapterQ访问EISpȝQ包括Oracle,SQL Server或其他)调用 WebLogic security framework时引发。应用组件传递subject(who),weblogic resource(what)和需要的credential。WebLogic security framework请求传递给credential mapping provider,credential mapping provider处理hQƈ数据库中的credential回送weblogic security framework,最后将credentialq回l组件层Q组件层使用credential以访问EISpȝ?br />
·weblogic security provider
~省自带的security provider,如果不能满你的需求,可以自己开发客户化的security provider.
?从weblogic.security.spi包中实现正确的SSPIs(security service provider interface)以生成security provider.
?建立Mbean的定义文ӞMDFQ?使用Weblogic MbeanMaker工具生成Mbeancd?br />
weblogic authentication provider
代替?.xFile realm的功能,支持用户?密码认证Q利用embedded LDAP Server存储用户和组的信息?/p>
支持LDAP Authentication讉K外部的LDAP 存储QOpen LDAP,Netscape iPlanet,Microsoft Active Directory,Novell NDSQ?/p>
WebLogic Identity Assertion Provider
支持X.509认证和CSIv2(CORBA Common Secure Interoperability version 2)w䆾认证?br />WebLogic Identity Assertion provider验证token 的类型,然后X.509数字认证和x.501的单一的名字和WebLogic 的用户名相对应。同h定一信Q的客户principal列表便于CSIv2的n份确认。统配符*用于指定所有的信Q的principal.如果客户没有列入Cȝprincipal中,CSIv2 Identity Assertion失败?br />支持的tokencd?br />
?AU_TYPE -- WebLogic authenticationdUserWebLogic principal validation provider
WebLogic authorization provider
WebLogic adjudication provider
WebLogic role mapping provider
·WebLogic auditing provider
WebLogic credential mapping provider
以上provider功能在前面已l做了基本介l。在此省略?br />
·Weblogic keystore provider
使用sun公司sdk提供的keystore实现Q利用标准的JKS keystorecdQ将keystore做ؓ文gQ每台机一个)来保存。有两种keystore 文g
?一个文件保存CA认证(CA certificates)
?另一个文件保存server的private key
·WebLogic realm adapter provider
主要用来提供?.x安全域的兼容。Realm Adapter提供
Authentication(include Identity Assertion Provider)
Authorization
Auditing
Adjudication
仅仅用于升且不使用?br />
作者简?/span> | |
聂健是(dev2dev ID: ericnieQ?Horizon Software Ltd. 技术顾?/td> |
旉Q?005-04-20 作者:马晓?/a> 览ơ数Q? 152611 本文关键字: |
|
1 J2EE Security ?LDAP Security
2 JAAS和WebLogic Security Framework
3 了解WebLogic LDAP Authentication Provider
4 定制自己的Custom LDAP Authentication Provider
5 部v中的注意事项
6 l束?/a>
7 参考资?/a>
从WebLogic Server 7.0开始,WebLogic Server的安全机制有了全面的改变Q实C一个更加规范的ZJAAS的Security FrameworkQ以及提供了一pd设计良好的Security Service Provider Interface。这h们可以根据自q具体需求,通过Custom Security Authentication Provider来实现安全上的定制功能?/p>
本文以WebLogicQWebLogic Server 8.1Q?Security?LDAP为基Q介lCustom LDAP Authentication Provider如何l我们带来更多的灉|性,和系l安全设计上更多的空_以及讨论如何实现一个Custom LDAP Authentication Provider和部|过E中的一些良好经验?/p>
׃本文涉及到的范围太广Q不可能一一详细讨论Qؓ了没有相关基础的读者也能够阅读理解本文Q因此我在文章前半部分Q试N过最z扼要的描述Q来使大家对于J2EE SecurityQWebLogic Security Framework以及LDAP {有一个初步的清晰认识Q进而可以开发出自己的LDAP Authentication Provider。因此很多地方做了比较有限的描述或者介l,更多详细的内容可以参考文后附带的参考资料或者文中给出的链接?a id="1" name="1">
1 J2EE Security ?LDAP Security
Sun J2EE推出以来Q其安全部分的规范就一直倍受x。我们最常见到安全规范的两个斚w分别是Servlet Security ?EJB Security。目前绝大多数的Servlet容器QJ2EE容器都能很好的支持这些安全规范?/p>
WebLogic Server作ؓ业界领先的J2EE服务器对J2EE Security的支持是非常优秀的。我们这里将l合WebLogic Security和用越来越q泛的LDAP做一个简要的介绍Q这些是设计开发Custom LDAP Authentication Provider的技术基?/p>
1.1 Authentication 和Authorization
q里需要大家先明确安全上的两个重要名词Q一个是认证QAuthenticationQ,一个是授权QAuthorizationQ。认证是回答q个人是谁的问题Q即完成用户名和密码的匹配校验;授权是回{这个h能做什么的问题。我们讨论的J2EE Security包括Declarative Authorization和Programmatic AuthorizationQ即一个是通过web.xmlQejb-jar.xml{部|描q符中的安全声明通过容器提供的服务来完成权限控制的;一个是通过HttpServletRequest.isUserInRole()和EJBContext.isCallerInRole()q样的编E接口在应用中自己完成权限控制的?/p>
1.2 资源QResourceQ和Security Role
资源原本只包?Web Resource和EJB ResourceQ但在WebLogic Security中扩展到几乎M一个WebLogic Platform中的资源Q具体可以参?a target="_blank">http://e-docs.bea.com/wls/docs81/secwlres/types.html#1213777。授权就是针对资源的讉K控制?/p>
J2EE Security是基于Security Role的。我们可以将一l资源与一个Security Roleq行兌来达到控制的目的——只有拥有该Role权限的用h能够讉Kq些资源。简单的_我们可以通过l用户分配不同的Security Role来完成权限的控制。复杂的情况下包括用?用户l,以及Principal和Role的映关pȝ{。下面是一个声明性安全在web applicationQwar包中WEB-INF/web.xmlQ中的示例:
<web-app> <security-constraint> <web-resource-collection> <web-resource-name>Success</web-resource-name> <url-pattern>/welcome.jsp</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> </web-resource-collection> <auth-constraint> <role-name>webuser</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>default</realm-name> </login-config> <security-role> <role-name>webuser</role-name> </security-role> </web-app> |
只有拥有角色webuser的用h能够讉Kwelcome.jsp面Q否则容器会q回401无权讉K的错误。更多信息请参?a target="_blank">http://e-docs.bea.com/wls/docs81/security/index.html?/p>
同时我们需要在weblogic.xmlQwar包中WEB-INF/weblogic.xmlQ中对security role和principalq行映射关系的配|:
<weblogic-web-app> <security-role-assignment> <role-name>PayrollAdmin</role-name> <principal-name>Tanya</principal-name> </security-role-assignment> </weblogic-web-app> |
q样拥有Principal “Tanya”的用户QPrincipal封装到Subject中,用户和Subject兌Q将会拥有PayrollAdmin的权限?/p>
注意Q一般情况下Z化设计,本文中将假设security rolexprincipal nameQ如果不配置security-role-assignmentQWebLogic会默认做此假设)。即上例中Principal-name也ؓPayrollAdmin?/i>
1.3 LDAP Security
LDAP是轻量目录服务QLightweight Directory Access ProtocolQ。越来越多的应用开始采用LDAP作ؓ后端用户存储。在安全上,LDAP Security是基于ACLQAccess Control ListQ的Q它通过l一个用L分配LDAP 操作资源Q比如对一个子树的查询Q修改等Q来最l完成权限的控制。因此在LDAP中,授权工作是以用户lؓ单位q行的。一个用L一般来说是拥有如下一l属性的LDAP EntryQ?/p>
?-3-1
其中objectclass可以为groupOfUniqueNames或者groupOfNamesQ它们对应的l成员属性分别是uniquemember和member。如果是动态组Qobjectclass为groupOfURLs。动态组一般应用在成员可以通过某种业务逻辑q算来决定的情况下。比如,l理为ZHANGSAN的全部员工。下面是一个典型的动态组QmemberURL属性定义了哪些entry属于该组Q?/p>
?-3-2
从图1-3-1中我们可以看出,用户WANTXIAOMINGQZHANGSANQLISI属于lHR Managers。这U组和成员的关系是通过属性uniquemember来决定的。同时LADP Group 支持嵌套Q即一个组可以是另外一个组的成员,比如我们Accounting Managersl分配给HR Managersl作为其成员Q?/p>
?-3-3
q样表CAccounting Managers中的成员Q同时也是组HR Managers的成员。通过q种层关系可以使权限分配变的更加灵zR?/p>
下面是一些名词的解释Q希望大家对LDAP有更好的理解Q?br /> a) Objectclass —?LDAP对象c,抽象上的概念cM与一般我们理解的class。根据不同的objectclassQ我们可以判断这个entry是否属于某一个类型。比如我们需要找出LDAP中的全部用户Q?objectclass=person)再比如我们需要查询全部的LDAPl:(objectclass=groupOfUniqueNames)
b) Entry —?entry可以被称为条目,或者节点,是LDAP中一个基本的存储单元Q可以被看作是一个DN和一l属性的集合?属性可以定义ؓ多值或者单倹{?br />
c) DN —?Distinguished NameQLDAP中entry的唯一辨别名,一般有如下的Ş式:uid=ZHANGSAN, ou=staff, ou=people, o=examples。LDAP中的entry只有DN是由LDAP Server来保证唯一的?/p>
d) LDAP Search filter ——用filter对LDAPq行搜烦?Filter一般由 (attribute=value) q样的单元组成,比如Q?&(uid=ZHANGSAN)(objectclass=person)) 表示搜烦用户中,uid为ZHANGSAN的LDAP EntryQ再比如Q?&(|(uid= ZHANGSAN)(uid=LISI))(objectclass=person))Q表C搜索uid为ZHANGSAN, 或者LISI的用P也可以?来表CZQ意一个| 比如(uid=ZHANG*SAN)Q搜索uidg ZHANG开头SANl尾的Entry。更q一步,Ҏ不同的LDAP属性匹配规则,可以有如下的FilterQ?(&Qcreatetimestamp>=20050301000000Q?createtimestamp<=20050302000000))Q表C搜索创建时间在20050301000000?0050302000000之间的entry?br /> Filter??amp;?表示“与”;?”表C“非”;“|”表C“或”。根据不同的匚w规则Q我们可以用?”,“~=”,?gt;=”以及?lt;=”,更多关于LDAP Filter读者可以参考LDAP相关协议Q?a target="_blank">http://www.ietf.org/rfc/rfc2254.txt?/p>
e) Base DN —?执行LDAP Search时一般要指定basednQ由于LDAP是树状数据结构,指定basedn后,搜烦从BaseDN开始,我们可以指定Search Scope为:只搜索basednQbaseQ,basedn直接下Qone levelQ,和basedn全部下Qsub tree levelQ?/p>
下面是一个典型的LDAP Treel构Q右侧显CEntry uid=ZHANGSAN, ou=staff, ou=people, o=examples的属性,该entry代表了一个名字叫张三的用P
2 JAAS和WebLogic Security Framework
现在来多的h开始了解JAASQ用JAAS。WebLogic Security Framework是ZJAAS的。因此我们需要对此有一个非常准的理解才能够设计开发Custom Authentication Provider?/p>
下面我们从几个名词入手,了解JAAS?WebLogic Security Framework的关键之处:
2.1 PrincipalQSubject和LoginModule
a) Principal
当用h功验证后Q系l将会生成与该用户关联的各种Principal。我们这里将Principalq行化的设计Q认Z个Principal是用户d帐号和它所属于的组QLDAP GroupQ。这样当用户d成功后,我们会在LDAP中执行搜索,扑և用户属于哪些l,q将q些l的名字Q或者其标识作ؓPrincipalq回。这P当用户在LDAP中属于某一个组Qƈ且这个组的名字对应到 web.xml Q或者ejb-jar.xmlQ中的Security roleQ那么这个用户就可以看作拥有讉Kq个Security Role定义的资源的权限?br /> 在WebLogic Security Framework中,q个LDAP Group的名字(PrincipalQ和Security Role的映关p,可以通过一?Role Mapping Provider来实现动态的匚wQ即用户的动态权限控制。比如在q行时根据某一个业务逻辑来决定用h否拥有某一个权限。关于Role Mapping ProviderQ读者可以参考下面链接的内容Q?a target="_blank">http://e-docs.bea.com/wls/docs81/dvspisec/rm.html#1145542?/p>
b) Subject
JAAS规定由Subject装用户以及用户认证信息Q其中包括Principals。下面是WebLogic Security Framework中Subject的组成图C:
?-1-1
q样当用戯图访问一个受限的J2EE资源Ӟ比如一个web URLQ或者一?EJB MethodQ可以在web.xml或者ejb-jar.xml中定义,由Security Role控制Q,WebLogic Security Framework会通过 Authorization Provider查用户当前的Subject中是否包含有是否可以讉K受限资源的Principals。由于Principals和J2EE Security Role在weblogic.xml中定义一个映关p(或者通过其他业务逻辑来确定这U关p)Q因此通过q样的关p,可以最l知道用h否有某一个J2EE Resource的访问权限?/p>
c) LoginModule
JAAS LoginModule是一个Authentication Provider必须的组成部分。LoginModule是认证的核心引擎Q它负责对用戯n份进行验证,同时返回与用户兌的PrincipalsQ用L录帐P以及LDAP GroupsQ,然后攑օSubject中,供后l的讉K控制使用?br /> 我们在LoginModules中完成LDAP的相兌证,查询操作Q将用户在LDAP中所属于的组搜烦出来Q作证后的结果封装到Subject中返回?/p>
2.2 WebLogic Authentication认证q程
下面我们了解一下WebLogic的认证过E。以下图片来?a target="_blank">http://e-docs.bea.com/wls/docs81/dvspisec/atn.html 我将其中主要部分q行说明?/p>
?-2-1
Security Framework在WebLogic Server启动时初始化Authentication ProviderQ?Q。当有认证请求进入时QSecurity Framework首先通过AuthenticationProvider.getLoginModuleConfiguration()来获取一个AppConfigurationEntry对象。通过AppConfigurationEntryQ详?a target="_blank">http://java.sun.com/security/jaas/apidoc/javax/security/auth/login/AppConfigurationEntry.html Q可以初始化一个LoginModule。初始化LoginModule的方法ؓQpublic void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)Q可以看到里面有Subject, CallbackHandler{等重要参数?br /> 被实例化的JAAS LoginModule完成用L一pd验证d。验证完成后Q在Q?aQ中principals被Principal Validation Provider{Q在Q?6bQ中存放C用户兌的Subject里面。Security Framework最后将拿着该用LSubjectd成其他权限控制等d?a id="3" name="3">
3 了解WebLogic LDAP Authentication Provider
现在我们有信心了解一下WebLogic LDAP Authentication Provider的工作原理了。这里将以WebLogic提供的iPlanet Authentication Provider的配|ؓ例进行说明。在q里也需要明说明一下,Z方便q行描述Q我们将实际属于LoginModule的行Z一q归l到Provider中。没有单独将两个的行为分开Q目的是ZH出整个完整的过E?/p>
3.1 iPlanet Authentication Provider配置
?-1-1
从上囑֏以看出我们需要指定LDAP服务器的地址Q端口,q接LDAP使用的PrincipalQ不同于前面讨论的PrincipalQ这个Principal实际是一个连接LDAP的用P也就是一个LDAP 中用户Entry?DNQ它必须要有相关的LDAP 搜烦{权限)和CredentialQ一般来说就是口令)?br /> 再看下面关于Users的配|:
?-1-2
3.1.1 User Object Class —?前面已经对objectclassq行q说明,指明LDAP Entry属于哪一c?br />3.1.2 User Name Attribute —?用户d帐号在LDAP Entry中的属性,一般ؓUID或者cn
3.1.3 User Base DN —?所有的用户会攄到这个子树下面,因此在Provider中对用户q行的搜索将会从q个basedn开?br />3.1.4 User Search Scope —?指定搜烦范围为Basedn的直接一U或者全部下U?br />3.1.5 User From Name Filter —?使用q个filter可以搜烦出用户信息。其?u会被用戯入的d帐号替换Q从而查询中LDAP中的用户信息
?-1-3
3.1.6 Group Base DN —?从该Base DN开始搜索用L
3.1.7 Group From Name Filter —?%g会被组的名字替换,通过该filter可以搜烦出符合条件的LDAP Group
3.1.8 Static group name attribute —?l名字的属性,属性cn对应的值就是组的名?/p>
?-1-4
3.1.9 Static Member DN Attribute —?静态成员属性,通过该属性可以判断一个Entry是否属于一个组
3.1.10 Static Group DNs From Member DN Filter —?通过该filter可以扑և用户属于哪些l?br />3.1.11 Dynamic Group —?动态组是在q行时根据某U业务逻辑Q来军_成员隶属关系的LDAP Group
3.2 iPlanet Authentication Provider的工作原?/b>
从上面配|的介绍中可以看出,后端存储为LDAP的情况下Q在Console中我们需要配|的参数已经清楚的表明它所要完成工作的内容?br /> 首先Q它使用配置的User BaseDN和FilterQ来Ҏ用户输入的登录帐可行搜索,扑և存放在LDAP中的用户Entry。如果找C个用P那么Provider׃用该用户的DN和用戯入的口oQ进行验证。验证可以用LDAP Bind和LDAP CompareQ这需要根据不同LDAP的特Ҏq行选择?br />
A. LDAP Bind —?当前的LDAP Connectionl定C个用戯n份上。这样后l的使用该Connection的LDAP Operation都将以该w䆾q行。LDAP Bind需要两个重要参敎ͼ一个是用户Entry的DNQ一个是该用L口o?/i>
B. LDAP Compare —?LDAP Compare是一个ؓ兼容X.500的古老操作,它用于检查一个属性值是否包含在指定Entry中的属性里。这h们可以在知道用户password存放在哪个属性的前提下,对该属性进行compare。如果成功,表明口o正确。如果属性gؓ散列后的口oQ绝大多数情况)Q有的LDAP Server支持q样的验证,有的不支持,比如iPlanet LDAP Server 5?/i>
验证成功后,Provider用Console中关于Groups和Memberships中的配置Q查扄户属于哪些LDAP GroupQ而且׃q些l本w可能会有一些嵌套,因此对于搜烦到的l还需要进行查询。即使用filterQ?(&Quniquemember=uid=ZHANGSAN,ou=staff,ou=people,o=examplesQ?objectclass=groupOfUniqueNames))从Group Base DN开始搜索,返回用h属的W一层次GroupQ然后对于这些返回的lDNQ仍焉要用上面的Filterq行搜烦Quniquemember值替换ؓl的DNQ,扑և嵌套关系Q直到查询完成没有组嵌套为止Q此处需要防止陷入嵌套的循环中,比如Group A 包含了Group BQ?Group B又包含了Group AQ有的LDAP Server可以自动出Q有的需要我们程序来判断Q?br />
然后用L录的帐号Q用h属组的名字(属性CN的值或其他Q,攑օSubject中。最后调用Principal Validator ProviderQ对Subject中的principalsq行{Q来表明该Subject是这个Provider生成的。这样防止其他攻击者伪造Subject以及Principalq行ƺ骗。此处也可以解释Z在不同的WLS Domain间不能够传递SubjectQ我们可以通过讄域信L完成q种Subject的传递。设|域信Q使用的Credential是{用的Key?br />
?-1-5表明了如何设|WebLogic Domain CredentialQ默认情况下WebLogic Server会在启动的时候随即生成一个CredentialsQ在WLS6.1Ӟq个值就是system用户的口令)Q?/p>
可以惌如果我们实现自己的Principal Validator ProviderQ让它去一个集中的验证服务器中对Subjectq行{Q或者验证SubjectQ这样就可以实现域信任,q而完成ApplicationQEJB TierQ层的SSO?/p>
通过以上的讨论,我们对于实现自己的LDAP Authentication Provider是不是又增加了一份信心?
4 定制自己的Custom LDAP Authentication Provider
Z要定制自qAuthentication Provider? ׃WebLogic Server已经提供了很多默认的Authentication Provider在一般情况下我们实没有必要实现自己的Provider。但是面Ҏ些针对安全方面的复杂需求时QWebLogic Server提供的Provider很有可能不满些需求,此时需要我们定制自qProvider?/p>
在这一章的开头部分中我需要简要讨论关于WebLogic MBean TypesQ以及WebLogic Console扩展{内容,目的在于让读者了解到我们通过WebLogic Console可以完成对Custom Security Provider的配|和部vQ我以WebLogic 提供的Sample Security Provider为示例进行说明。详l的信息可以参考以下的一些资源:
http://e-docs.bea.com/wls/docs81/dvspisec/atn.html#1106272
http://e-docs.bea.com/wls/docs81/dvspisec/atn.html#1106241
上面两个链接描述了如何创建MBean Types以及在控制台上配|Custom Authentication Provider.下面q个链接中专门介l了WebLogic Console的扩展:
读者可以从http://dev2dev.bea.com/codelibrary/code/security_prov81.jsp下蝲WLS提供的Sample Security Provider?/p>
4.1 MBean Types和WebLogic Console
一般情况下Qh们可能更习惯通过WebLogic Console对Security Providerq行配置。这里我简要描q这个过E,以及可以到达的一个效果。限于篇q就不详l讨Z?/p>
从weblogic.management.security.authentication.Authenticator扩展MBean Types?MBean Types是MBeanQhttp://java.sun.com/products/JavaManagement/wp/Q的工厂Q我们扩展SampleSecurityProviders81 包中的SimpleSampleAuthenticator.xmlQMBean Definition FileQ,增加一个我们自定义的参数LDAP Server IPQ?/p>
<MBeanAttribute Name = "LDAPServerIP" Type = "java.lang.String" Writeable = "true" Default = ""127.0.0.1"" /> |
q样在Provider中我们将通过MbeanMaker(WLS提供)生成的SimpleSampleAuthenticatorMBean中取到这个属性:SimpleSampleAuthenticatorMBean.getLDAPServerIP()。MBean在初始化Provider的时候作为参C入。这h们就可以通过MBean中的参数控制Provider的行为?/p>
当然q个参数是可以在WebLogic Console中设|的Q通过对MBean Types的扩展,在WebLogic Console上看到的画面如下Q?/p>
?-1-1
q样我们可以通过Console修改配置参数Q修改的Security Provider参数保存在config.xml中,默认的值将保存在MBean Jar File中)?/p>
4.2 Z定制LDAP Authentication Provider
当我们面临越来越复杂的安全方面的业务需求时Q或者面临较高的性能要求Q需要根据目标LDAP做针Ҏ的优化Ӟ或者需要将我们已有的认证,或授权模块集成到WebLogicq_ӞWebLogic提供的现成的Provider往往不能满我们的需求?/p>
4.2.1 复杂的业务需?br /> 当系l要求用户不仅仅输入用户名(j_usernameQ,口oQj_passwordQ,q需要输入其他信息,比如d的地点,pȝ的名字,用户的类型等{。如果是采用ZJ2EE Form的验证方式, d信息需要提交到j_security_checkQServlet规范定义由容器负责实现的ServletQ,D我们没法处理更多的信息?/p>
q个时候,如果能够实现我们自己?Authentication ProviderQ那么我们就可以通过TextInputCallback来获取登录表单中更多的信息了Q进而通过q些信息在Provider中完成符合我们需要的处理?/p>
比如搜狐的登录页面上需要选择用户的类型:
?-2-1
4.2.2 性能需求或者调?/b>
有时Q有的用户会比较困惑ZWebLogic LDAP Security Provider在压力测试中的表C很理惻I用户需要较长时间的{待Q才能够d到系l中。由于这些Provider?WebLogic产品的一部分Q因此缺乏对不同目标LDAP Server的有针对性的优化。这样就使得我们无法充分发挥具体LDAP Server的性能调优?/p>
比如Q有的LDAP Server支持动态组QLDAP Dynamic GroupQ成员关pLq行时根据ldap serverQbasednQfilter{动态决定的Q,可以使用如下的Filter查询用户属于哪些动态组Q?/p>
(uniquemember=uid=MAXQ,ou=staff,ou=people,o=examples)
有的LDAP Server虽然支持动态组Q但是支持的有限Q不能用上面的Filter获取用户属于哪些动态组。在WebLogic iPlanet Authentication Provider的实CQ它先是搜烦出全部的动态组Q然后再遍历q些动态组Q依ơ去LDAP中检查用h否属于一个组Q很明显Q这栯然最大程度的满了不同LDAP Server的要求(从品的角度讲可能是必须的)Q但是与LDAP交互的次数大增,q发用户量一大性能下降的比较明显?/p>
此时Q如果系l中的LDAP支持上面的Filter或者有更好的搜索方式,那么完全可以通过定制Provider完成Ҏ能的优化?/p>
4.2.3 已有权限控制的集?/b>
如果pȝ中已l存在了现成的满需求的认证模块Qƈ且已l很好的工作Q在pȝ转向J2EE架构Qƈ使用WebLogic Server做J2EE容器Ӟ我们可能会更愿意直接在Provider中加入这个认证模块?/p>
lgQ我只是列D了一些可以驱动我们开发自己Provider的需求,怿在读者实际工作中可能会面临更复杂的情况,开发自qProvider是一个非常好的选择?/p>
4.3 LDAP Authentication Provider实现
本文之前Z表述的方便没有单独提到LoginModuleQ认为LoginModule的行为就是LDAP Authentication Provider的行为。到了目前的具体实现阶段Q我们必d开Authentication Provider和JAAS LoginModule。最l部|到WebLogic上的实际只是LDAP AuthenticationProvider Implements?/p>
WebLogic SecurityFramework通过Authentication Provider获取具体的JAAS LoginModule。通过LoginModule完成最l登录的工作。因此我们必d实现一个AuthenticationProvider?/p>
我们一般通过weblogic.security.spi.AuthenticationProvider 来实现自qAuthenticationProvider。这里介l其中的几个重要ҎQ?/p>
a) public void initialize(ProviderMBean mbean, SecurityServices services)
初始化一个Provider。通过参数MBean我们可以获取到在WebLogic Console中配|的各项参数。进而初始化我们的ProviderQ然后通过Provider传递到LoginModule中?/p>
b) public void shutdown()
释放一些与ProviderQLoginModule{相关的资源?/p>
c) public AppConfigurationEntry getLoginModuleConfiguration()
q个Ҏ非常重要Q通过该方法,WebLogic Security Framework可以获取用于初始化LoginModule的AppConfigurationEntry。AppConfigurationEntry中存放了LoginModule的类名等信息Q比如用如下代码返回一个AppConfigurationEntry:
return new AppConfigurationEntry( "examples.security.providers.authentication.SampleLoginModuleImpl", controlFlag, options); |
其中LoginModule Name?/p>
?examples.security.providers.authentication.SampleLoginModuleImpl"Q我们通过它就可以实例化一个LoginModuleq过LoginModule.initialize()Ҏq行初始化?/p>
d) public AppConfigurationEntry getAssertionModuleConfiguration()
该方法将q回一个与Identity Assertion Provider兌的LoginModule。这个Assertion LoginModuleQ将只会验证用户是否存在Q以及如果存在返回用LPrincipals?该方法也比较重要Q需要正实玎ͼ比如我们使用CLIENT-CERTq种WEB认证方式Q该Ҏ׃被调用?/p>
Provider的实现比较简单,读者可以在http://dev2dev.bea.com/codelibrary/code/security_prov81.jsp下蝲WebLogic提供的SamplesQ查看SampleAuthenticationProviderImpl的代码?/p>
4.4 LDAP LoginModule 逻辑程
实现了Provider后,必须拥有我们自己的LDAP LoginModule。下面是一个简单的用于演示的验证逻辑程图。实际的一个LoginModule׃不同的业务需求,情况可能会复杂得多。这里只是描qC最核心最基本的逻辑Q读者能有一个清晰的思\。后面我以q个程Zq行实现?/p>
4.5 LoginModule代码CZ和讲?br /> q里我将使用Netscape LDAP SDK for java作ؓ开发工具实现LDAP相关的操作,读者可以到http://docs.sun.com/db/doc/816-6402-10 下蝲开发手册,?a target="_blank">http://www.mozilla.org/directory/ 下蝲SDK 包。一般来说还可以通过JNDI来操作LDAPQ我个h认ؓSun LDAP JNDI Provider中关于Connection Pool的实现非怼U。但不管使用哪种SDKQ对LDAP的编E原理上基本都是相同的(因ؓZ同样的LDAP协议Q,不同的可能仅仅是接口Q类的名字而已?/p>
4.5.1 初始化Connection Pool
Z有效使用宝贵Qƈ且有限的LDAPq接Q必M用连接池。下面的代码初始化了一个LDAPq接池:
/** * */ static ConnectionPool pool; /** * * LDAPException */ public LdapClient() throws LDAPException { pool= new ConnectionPool( 1, 150, "127.0.0.1", 389, "cn=Directory Manager", "88888888"); } |
Sun JNDI LDAP Service ProviderQJDK1.4Q中可以通过在环境变量中讄具体的参数来启用q接池,辑ֈ复用q接的目的。具体可以参考链接:http://java.sun.com/products/jndi/tutorial/ldap/connect/index.htmlQ下面是CZ代码Q?br />
Hashtable env= new Hashtable();
?br />env.put("com.sun.jndi.ldap.connect.pool", "true");
DirContext ctx= new InitialDirContext( env);
4.5.2 Ҏ用户输入的登录帐P搜烦用户Entry
下面q个Ҏ实现了从LDAP中搜索用户Entry DN的最单的q程。实际上我们可以在其中实现很多定制的功能。比如允许用户用多于一个的帐号dQ只要这些帐可够通过LDAP Searche最l返回一个唯一的用户DN卛_?/p>
* * LDAPException */ public String getUserDN( String uid) throws LDAPException{ LDAPConnection conn= pool.getConnection(); try { String[] attrs= new String[] {}; LDAPSearchResults sr= conn.search("o=examples", 2, "(uid="+ uid +")", attrs, false); if ( sr.hasMoreElements()) { LDAPEntry entry= sr.next(); return entry.getDN(); } throw new LDAPException("No Such Object:"+ uid, LDAPException.NO_SUCH_OBJECT); }catch ( LDAPException ex) { throw ex; }finally { try { if (conn!= null) pool.close(conn); }catch ( Exception ex) {} } } |
首先需要从池中获取一个LDAPq接Q然后用LDAPConnection.searchҎq行搜烦。我q里以一个典型的LDAP Search接口Zq行说明Q其他API比如JNDI{,Z同样的LDAP协议Q接口中同样参数的含义都是相同的?/p>
public LDAPSearchResults search(java.lang.String base, int scope, java.lang.String filter, java.lang.String[] attrs, boolean attrsOnly) |
1) Base: 表明从该Basedn开始搜索,可以通过MBean获取
2) Scope: 搜烦的范_
a) LDAPv2.SCOPE_BASEQ?只搜索basedn指定的entry
b) LDAPv2.SCOPE_ONE, 在basedn的下一Uentry中搜索,不包括basedn
c) LDAPv3.SCOPE_SUBQ在basedn的全部下Uentry中搜索,包括basedn
3) FilterQ过虑条件。比如uid=ZHANGSANQ搜索UID为ZHANGSAN的用P再比如uid=ZHANG*Q搜?ZHANG开头的帐号Q或者uid=Z*SQ搜索以Z开头Sl尾的帐受前面已l介l过q里׃多说了?/p>
4) attrsQ返回该attrs数组中指定的属性,比如new String[]{“uid”}Q只q回属性uidQ其他属性将会不在结果中q回?一般来说我们会要求开发h员只需要的属性返回,q样避免q回无用的属性,降低|络和Server{方面的资源开销Q而且如果存在一个有较大属性集合的EntryQƈ且你q不使用到这个较大的属性集合。D个实际例子来_比如你的pȝ中拥有很多成员数目超q?万或者更多的LDAP GroupsQƈ且你希望通过LDAP Search扑և某一个用户属于的lCNQ那么搜索结果只q回l的CN已经可以满你的要求了,q时没有必要将全部member属性也q回了。这在后面我会有代码来说明?/p>
q里q有一点很重要的细节,怿对读者会有帮助。比如,你希望搜索到modifytimestamp{Operational Attributes。这些属性(LDAP Server自己负责l护的,用户无法修改的)必须要在参数attrs中指定,LDAP Server才会q回l客L。如果用户希望返回全部User Attributes的同Ӟq回指定?Operational Attributes那该怎么办?不在attrs列表中的属性将不会被返回,一旦我指定了attrsQ是否需要将全部的属性都列在attrs参数中?实际上此时只需要传?new String[]{ ?? “createtimestamp”}q样的参数即可;?”号即代表了全部的User Attributes。在Sun JNDI LDAP Service Provider中也是这P管NSun关于JNDI的文档也找不到这L说明。LDAP协议Ҏ的说明在 http://www.ietf.org/rfc/rfc2251.txt W?8c?/p>
5) attrsOnlyQ只q回属性名Uͼ不包含倹{我们一般设|ؓfalse?/p>
我们下面看一下Sun JNDI中关于LDAP Search的接口:
public NamingEnumeration search(String name,
String filter,
SearchControls cons)
throws NamingException
name参数是上面的basednQSearchControls中封装更多的讄Q比如:SearchControls. setSearchScope(int scope)其中的scope对应上面?)Q?SearchControls.setReturningAttributes(String[] attrs)Q设|指定返回的属性,对应上面?)?/p>
其他的参数还包括Size LimitQ即限制搜烦l果的数目(LDAPq回的Entry一般情况下是没有排序的Q除非用一些Sort ControlQ,当你的搜索可能会q回成千上万的EntryӞ限制搜烦的数目是非常明智也是必须的。关于这些,读者可以参考API文档或者LDAP协议?/p>
4.5.3 Ҏ用户的Entry DNQ和用户输入的口令完成n份验?br /> 下面的方法实C到LDAP的n份验证。LDAP中的用户实际上就是一个LDAP EntryQ一ơ验证实际是Connection与这个Entryq行l定Q因此验证时我们需要两个必ȝ参数Q一个是Entry的DNQ一个是口o。LDAP的n份验证方式有多种Q包括SASL以及Z证书的验证等Q我们这里只介绍Simple Authentication。关于SASL更多信息读者可以参考:http://www.ietf.org/rfc/rfc2222.txt?/p>
/** * * dn * pwd * * LDAPException */ public boolean authentication( String dn, String pwd) throws LDAPException { LDAPConnection conn= pool.getConnection(); try { conn.authenticate( dn, pwd); return true; }catch ( LDAPException ex) { if ( ex.getLDAPResultCode()== LDAPException.INVALID_CREDENTIALS) { return false; // 用户口o错误 } if ( ex.getLDAPResultCode()== LDAPException.NO_SUCH_OBJECT) { return false; // 用户不存?} throw ex; }finally { try { if ( conn!= null) pool.close(conn); }catch ( Exception ex) { } } } |
我们q里使用 LDAP Bind操作完成对用Lw䆾验证。本文前面曾提到也可以用LDAP CompareQ通过比较口o属性(userpasswordQ中的值来完成验证。我们需要根据不同的LDAP Server选择合适的验证Ҏ?/p>
比如iPlanet LDAP Server 5Q只能通过Bind完成认证Q而Oracle Internet Directory可以通过LDAP Compare完成验证Q而且q支持口令策略?/p>
如果我们使用了连接池Q连接池中的q接一般都是用权限较大的用户初始化的Q这栯些连接才可以完成对LDAP的搜索操作;而当通过q些q接Ҏ通用戯行n份验证时Q如果通过验证Q连接的w䆾被改变为普通的用户Q或UCؓ与普通用Lw䆾兌Q。普通用户很可能没有除了bind以外的Q何权限,所以在q接被放入池中前Q我们必要恢复q接的n份?/p>
q样我们必须执行两次LDAP BindQ一ơ用于对普通用户验证n份;一ơ用于恢复连接的较大权限的用戯n份。我们看到这h率是比较低的Q可能你在LDAP Server端统计有2万次bindhQ实际上只有1万hơ登录?/p>
对于特定的LDAP ServerQ比?Oracle Internet DirectoryQ可以通过LDAP Compare对用戯n份进行验证,q且不会改变q接兌的用戯n份。这h在用池的情况下只需要一ơLDAP Compare卛_。效率有很大提高。如果不通过定制LDAP Authentication ProviderQ这L调优是没法实现的?/p>
Netscape LDAP SDK的ConnectionPool的实CQ在q接攑օ池中前会查连接的w䆾Q如果n份被改变Q那么会重新q行bind。所以我们没有必要在代码中再做bind?/p>
4.5.4 Ҏ用户的DN搜烦用户属于的组列表
有了上面的基后,q个Ҏ很Ҏ理解了。下面我们来看看如何q回用户所属的l?/p>
/** * * groupbasedn * memberDn * * LDAPException */ public List getGroupMembership( String groupbasedn, String memberDn) throws LDAPException { LDAPConnection conn= pool.getConnection(); try { LDAPSearchResults sr= conn.search( groupbasedn, 2, "(uniquemember="+ memberDn +")", new String[] {"cn"}, false); List groups= new java.util.ArrayList(); while ( sr.hasMoreElements()) { LDAPEntry entry= sr.next(); LDAPAttribute attr= entry.getAttribute("cn"); if ( attr!= null) { String[] values= attr.getStringValueArray(); if ( values!= null && values.length>0) groups.add( values[0]); } } return groups; }catch ( LDAPException ex) { throw ex; }finally { try { if ( conn!= null) pool.close(conn); }catch ( Exception ex) { } } } |
成员和组的membership主要是通过uniquemember或?member属性来定义的。成员不仅仅可以使用用户Q也可以是组Q因为组可以嵌套?br />
a) 上面的方法中只实C一个层ơ的搜烦Q即用户——组的搜索,而组间的嵌套搜烦没有实现。读者可以根据系l内的具体情况,在此处也可以做一些优化?/p>
b) l成员的数量可能比较大,Z避免不必要的开销Q我们指定只q回l的cn属性?/p>
c) 动态组的优化。在WebLogic默认的实CQProviderQ实际ؓLoginModuleQ会不断的拿动态组中定义的URL中的filter和用LDN去LDAP做搜索,来看用户是否属于该组。本文前面也讨论了,q样效率很低Q完全可以放在Provider本地实现URL和Entry的匹配?/p>
4.5.5 LoginModule中的login()Ҏ实现
一切准备就l后Q我们就可以完成LoginModule.login()q个最核心的方法了。下面我Ҏ代码中的注释逐条说明?/p>
// A boolean loginSucceeded; // B List principals= new java.util.ArrayList(); /** * * * LoginException */ public boolean login() throws LoginException { // C Callback[] callbacks= new Callback[] { new NameCallback("username: "), new PasswordCallback("password: ",false)}; try { callbackHandler.handle( callbacks); }catch (IOException e) { throw new LoginException(e.toString()); }catch (UnsupportedCallbackException e) { throw new LoginException(e.toString() + " " +e.getCallback().toString()); } // String userName = ((NameCallback)callbacks[0]).getName(); if ( userName== null || userName.length()== 0) { throw new LoginException("User login name is empty!"); } // PasswordCallback passwordCallback= (PasswordCallback)callbacks[1]; char[] password = passwordCallback.getPassword(); passwordCallback.clearPassword(); if ( password== null || password.length== 0) { throw new LoginException("User password is empty!"); } try { // D String dn= this.getUserDN( userName); if ( dn== null) { throw new LoginException("User "+ userName +" doesn't exist."); } // E boolean authResult= this.authentication( dn, String.valueOf( password)); if ( authResult== false) { throw new FailedLoginException("User login failed."); } // F principals.add( new WLSUserImpl( userName)); // G List groups= this.getGroupMembership( "ou=groups,o=examples", dn); for ( int i=0, n=groups.size(); i<n; i++) { String cn= String.valueOf(groups.get(i)); // H principals.add( new WLSGroupImpl(cn)); } }catch ( LDAPException ex) { java.io.StringWriter sw = new java.io.StringWriter(); ex.printStackTrace(new java.io.PrintWriter(sw)); sw.flush(); throw new LoginException( sw.toString()); } return loginSucceeded= true; } |
a) 用于保存验证l果Q在后箋ҎQcommit{)中?br />
b) 用于保存和用户关联的PrincipalQ在后箋ҎQcommit{)中?br />
c) 在JAAS中通过CallbackHandler来完成用户和底层安全认证pȝ间信息的交换Q这里我们通过CallbackHandler获取用户输入的登录帐号和口o。CallbackHandler在初始化LoginModule时由WebLogic Security Framework传入。读者可能会问,我是否可以在此要求WebLogic Security Framework传入我自己实现的CallbackHandlerQ进而获取更多的信息Q支持更多的CallbackQ很遗憾Q不可以。只有在一U情况下Q本文前面也提到Q有一个变通,是在Web应用中,通过Form Basedq种认证方式q行用户w䆾验证Ӟ可以获取更多的登录表单中提交的cgi变量?/p>
下面的代码将演示q种技术:
Callback[] callbacks= new Callback[] { new NameCallback("username: "), new PasswordCallback("password: ",false), new TextInputCallback("my_hidden_field")}; try { callbackHandler.handle( callbacks); }catch (IOException e) { throw new LoginException(e.toString()); }catch (UnsupportedCallbackException e) { throw new LoginException(e.toString() + " " +e.getCallback().toString()); } String value= ((TextInputCallback)callbacks[2]).getText(); |
q样我们通过((TextInputCallback)callbacks[2]).getText()来获取表单中更多的信息。其中TextInputCallback的Prompt必须要和表单中对应域的名字一_否则取不C息。如果有多个域,则需要传入多个TextInputCallback?/p>
同时如果d表单中没有这些对应TextInputCallback的域Q或者用JNDI方式验证Q那么会抛出UnsupportedCallbackException?/p>
下面是一个符合Servlet安全规范的登录表单,其中域my_hidden_field的值将通过CallbackHandler传递到的TextInputCallback中:
<html> <form method=”POST?action=”j_security_check?gt; <input type=”text?name=”j_username?gt; <input type=”password?name=”j_password?gt; <input type=”hidden?name=”my_hidden_field”value=”Hello Callback!?gt; </form> </html> |
d) 生成一个用于存放Principal的集合对?br /> e) 通过d帐号获取LDAP中的Entry DN
f) 通过DN和用户口令进行n份验?br /> g) 通过验证的用户名加入到Principal列表中,q些以后都将代表用户的一定权?br /> h) 查找用户属于哪些l?br /> i) 这些组的名字加入到Principal列表?/p>
4.5.6 LoginModule中的commit()和abort()Ҏ实现
完成了以上的验证后,我们需要通过LoginModule.commit()Ҏ提交验证l果Q或者abort()Ҏ取消验证l果?/p>
// A private Subject subject; /** * * * LoginException */ public boolean commit() throws LoginException { if (loginSucceeded) { // B subject.getPrincipals().addAll(principals); return true; }else { return false; } } /** * * * LoginException */ public boolean abort() throws LoginException { // C subject.getPrincipals().removeAll(principals); return true; } |
我这里仍焉过代码中的注释q行相应的说明:
a) JAAS SubjectQ在LoginModule初始化时Q由WebLogic Security Framework负责传入Q用L权限信息QPrincipals{)都将装到该Subject中。同时Principal Validator会对Subject中的Principalsq行{Q防止被黑客U改?/p>
b) 用户认证成功的情况下Q将用户兌的Principals加入到Subject中。这L户在q行后箋的访问时QWebLogic Security Framework会检查与用户兌的Subject中是否有可以讉K受限资源的Principal?/p>
c) 用户dp|的情况下Q有可能是其他的LoginModuleD的整体登录失败,具体参考JAAS Control FlagQ,我们在commit中添加的Principals必须从Subject中删除?/p>
通过上面的描q和讨论Q相信读者已l对如何实现一个LDAP AuthenticationProvider/LoginModule有了比较清楚的了解。限于篇q省略了很多l节Q对此有需要的读者可以根据文中给出的相关链接做进一步的了解Q或者与我交。从q里我们也可以看到核心的逻辑q是比较单的。其中将LDAP Group作ؓ用户的PrincipalQ是J2EE Security与LDAP Securityl合的非帔R要的一步。通过q种l合Q我们可以将LDAP作ؓ后端Q设计出ZJ2EEQJAAS的用戯n份验证,权限理{系l?a id="5" name="5">
5 部v中的注意事项
开发完成LDAP Authentication Provider后,需要将通过WebLogic MBean Maker生成的MBean Jar File攑ֈ/server/lib/mbeantypes目录下。由于WebLogic Server在启动时会加载这些ProviderQ因此在一个分布式的环境中QWebLogic Domain内的全部WLServerQ包括Managed ServerQ均需要部|该Jar包?/p>
同时׃使用了Provider MBeanQ因此,当你删除了MBean Types中定义的Qƈ且通过修改保存在config.xmlQWebLogic Domain配置文gQ中的属性时Q重新部|的Jar包会DWebLogic Server无法正常启动Q因为它没有办法按照config.xml中配|的属性初始化MBean。此旉要手工修改config.xmlQ删除相关的属性即可?/p>
<examples.security.providers.authentication.simple.SimpleSampleAuthenticator
ControlFlag="OPTIONAL"
Name="Security:Name=myrealmSimpleSampleAuthenticator"
UserBaseDN="ou=people, o=examples" Realm="Security:Name=myrealm"/>
比如UserBaseDN已经不需要通过MBean来管理,q且在MBean Types中已l删除,那么直接删除q里的UserBaseDN="ou=people, o=examples" 可以了?a id="6" name="6">
6 l束?/b>
本文所讨论的内Ҏ些过于广泛,从我个h角度Ԍ写v来也比较困难Q很多技术问题没有进行深入的讨论。其实只是希望通过本文Q能够帮助读者对WebLogic SecurityQJ2EE SecurityQLDAP Security以及JAAS有一个初步的认识Q能够给希望实现LDAP Authentication ProviderQ或者被WebLogic LDAP Authentication Provider困惑的读者一些启C。只要能够对读者有所帮助Q本文的目的q辑ֈ了?/p>
限于幅Q本文很多地方的表述可能q不清晰Q也可能会有一些错误,如果在阅读过E中产生M疑问或者有M看法都可以通过E-mail来与我交,我也非常希望能和大家交流?a id="7" name="7">
7 参考资?/b>
a) http://e-docs.bea.com/wls/docs81/secwlres/types.html#1213777 关于WebLogic Resource的更多说?br />b) http://e-docs.bea.com/wls/docs81/security/index.html 关于WebLogic Security的全部内?br />c) http://e-docs.bea.com/wls/docs81/dvspisec/rm.html#1145542 关于Role Mapping Provider的更多内?br />d) http://dev2dev.bea.com.cn/techdoc/2005012102.html 关于WebLogic Console的扩?br />e) http://dev2dev.bea.com/codelibrary/code/security_prov81.jsp Custom Seuciryt Provider的Samples
f) http://java.sun.com/products/JavaManagement/wp/ 更多关于Sun JMX
g) http://java.sun.com/products/jndi/tutorial/ldap/connect/index.html 关于如何使用Sun JNDI LDAP Service Provider中提供的q接?br />h) http://www.ietf.org/rfc/rfc2254.txt 更多关于LDAP Filter
i) http://www.ietf.org/rfc/rfc2251.txt LDAP V3协议
j) http://www.ietf.org/rfc/rfc2222.txt 更多关于SASL
下面来看一个例子,在该例子中,我们要完成的工作是利用URLClassLoader加蝲jarq运行其中的cȝ某个Ҏ?/p>
首先我们定义一个接口,使所有承它的类都必d现actionҎQ如下:
完成后将其打包ؓtestInterface.jar文g?/p>
接下来新Z工程Qؓ了编译通过Q引入之前打好的testInterface.jar包。ƈ创徏TestActionc,使它实现ActionInterface接口。如下:
完成后将其打包ؓtest.jarQ放在c盘根目录下。下面要做的是利用URLClassLoader加蝲q运行TestAction的actionҎQƈ返回的值打印在控制C?/p>
新徏一工程Q引入testInterface.jar包。ƈ创徏一可执行类QmainҎQ,在其中加入如下代码:
在上面的例子中,首先利用URLClassLoader加蝲了C:\test.jar包,其中的com.mxjava.TestActionc蝲入内存,其强制转型为testInterface包中的ActionInterfacecdQ最后调用其actionҎQƈ打印到控制台中?/p>
执行E序后,在控制台上如期打印出我们惌的内宏V但是,事情q没有那么简单,当我们将该代码移动web应用中时Q就会抛出异常。原来,Java为我们提供了三种可选择的ClassLoaderQ?br />1. pȝcd载器或叫作应用类加蝲?(system classloader or application classloader)
2. 当前cd载器
3. 当前U程cd载器
在上例中我们使用javac命o来运行该E序Q这时候用的是系l类加蝲?(system classloader)。这个类加蝲器处?-classpath下的cd载工作,可以通过ClassLoader.getSystemClassLoader()Ҏ调用?ClassLoader 下所有的 getSystemXXX()的静态方法都是通过q个Ҏ定义的。在代码中,应该量地调用q个ҎQ以其它的类加蝲器作Z理。否则代码将只能工作在简单的命o行应用中。当在web应用中时Q服务器也是利用ClassLoader来加载class的,׃ClassLoader的不同,所以在强制转型时JVM认定不是同一cd。(在JAVA中,一个类用其完全匚wcd(fully qualified class name)作ؓ标识Q这里指的完全匹配类名包括包名和cd。但在JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识。因此,如果一个名为Pg的包中,有一个名为Cl的类Q被cd载器KlassLoader的一个实例kl1加蝲QCl的实例,即C1.class在JVM中表CZؓ(Cl, Pg, kl1)。这意味着两个cd载器的实?Cl, Pg, kl1) ?(Cl, Pg, kl2)是不同的Q被它们所加蝲的类也因此完全不同,互不兼容的。)Z能够使程序正运行,我们首要解决的问题就是,如何URLClassLoader加蝲的类Q同当前ClassLoader保持在同一cd载器中。解x法很单,利用java提供的第三种ClassLoader—当前线E类加蝲器即可。jdk api文档׃发现QURLClassLoader提供了三U构造方式:
接下来要做的是Q在构造URLClassLoaderӞ当前线E类加蝲器置入即可。如下:
ȝQ?br /> Java是利用ClassLoader来加载类到内存的QClassLoader本n是用java语言写的Q所以我们可以扩展自qClassLoader。利用URLClassLoader可以加蝲指定jar包中的类到内存。在命行上利用URLClassLoader加蝲jarӞ是用系l类加蝲器来加蝲class的,所以在web环境下,׃出错。这是因为JVM中一个类用其全名和一个加载类ClassLoader的实例作为唯一标识的。我们只要利用URLClassLoader的第二种构造方法ƈ传入当前U程cd载器卛_解决?br />
参考:
http://www.tkk7.com/sharajava/archive/2006/07/25/59946.html
http://kb.csdn.net/java/Articles/200510/a1843d60-05b1-456f-9f72-811cb45ea4ae.html
Oracle在执行一个SQL之前,首先要分析一下语句的执行计划,然后再按执行计划L行。分析语句的执行计划的工作是׃化器(Optimizer)来完成的。不同的情况,一条SQL可能有多U执行计?但在某一时点,一定只有一U执行计划是最优的,p旉是最的。相信你一定会用Pl/sql Developer、Toad{工具去看一个语句的执行计划,不过你可能对Rule、Choose、First rows、All rowsq几Ҏ疑问,因ؓ我当初也是这L,那时我也疑惑Z么选了以上的不同的?执行计划变?
1、优化器的优化方?
Oracle的优化器共有两种的优化方?卛_于规则的优化方式(Rule-Based Optimization,UCؓRBO)和基于代L优化方式(Cost-Based Optimization,UCؓCBO)?
A、RBO方式Q优化器在分析SQL语句?所遵@的是Oracle内部预定的一些规则。比如我们常见的,当一个where子句中的一列有索引时去走烦引?
B、CBO方式Q依词义可知,它是看语句的代h(Cost)?q里的代价主要指Cpu和内存。优化器在判断是否用q种方式?主要参照的是表及索引的统计信息。统计信息给的大?、有行、每行的长度{信息。这些统计信息v初在库内是没有的,是你在做analyze后才出现?很多的时侯过期统计信息会令优化器做出一个错误的执行计划,因些我们应及时更新这些信息。在Oracle8及以后的版本,Oracle列推荐用CBO的方式?
我们要明?不一定走索引是优的 ,比如一个表只有两行数据,一ơIO可以完成全表的?而此时走索引时则需要两ơIO,q时对这个表做全表扫?full table scan)是最好的?
2、优化器的优化模?Optermizer Mode)
优化模式包括Rule,Choose,First rows,All rowsq四U方?也就是我们以上所提及的。如下我解释一下:
Rule:不用多说,卌Z规则的方式?
Choolse:q是我们应观注的,默认的情况下Oracle用的便是q种方式。指的是当一个表或或索引有统计信?则走CBO的方?如果表或索引没统计信?表又不是特别的小,而且相应的列有烦引时,那么p索引,走RBO的方式?
First Rows:它与Choose方式是类似的,所不同的是当一个表有统计信息时,它将是以最快的方式q回查询的最先的几行,从M上减了响应旉?
All Rows:也就是我们所说的Cost的方?当一个表有统计信息时,它将以最快的方式q回表的所有的?从M上提高查询的吞吐量。没有统计信息则走基于规则的方式?
3、如何设定选用哪种优化模式
a、InstanceU别
我们可以通过在init<SID>.ora文g中设定OPTIMIZER_MODE=RULE、OPTIMIZER_MODE=CHOOSE、OPTIMIZER_MODE=FIRST_ROWS、OPTIMIZER_MODE=ALL_ROWS去选用3所提的四种方式,如果你没讑֮OPTIMIZER_MODE参数则默认用的是Chooseq种方式?
B、SessionsU别
通过SQL> ALTER SESSION SET OPTIMIZER_MODE=<Mode>;来设定?
C、语句?
q些需要用到Hint,比如:
SQL> SELECT /*+ RULE */ a.userid,
2 b.name,
3 b.depart_name
4 FROM tf_f_yhda a,
5 tf_f_depart b
6 WHERE a.userid=b.userid;
4、ؓ什么有时一个表的某个字D|明有索引,当观察一些语的执行计划确不走索引呢?如何解决?Q?
A、不走烦引大体有以下几个原因
♀你在InstanceU别所用的是all_rows的方?
♀你的表的l计信息(最可能的原?
♀你的表很?上文提到q的,Oracle的优化器认ؓ不值得走烦引?
B、解x?
♀可以修改init<SID>.ora中的OPTIMIZER_MODEq个参数,把它改ؓRule或Choose,重v数据库。也可以使用4中所提的Hint.
♀删除l计信息
SQL>analyze table table_name delete statistics;
♀表小不走索引是对?不用调的?
5、其它相?
A、如何看一个表或烦引是否是l计信息
SQL>SELECT * FROM user_tables
2 WHERE table_name=<table_name>
3 AND num_rows is not null;
SQL>SELECT * FROM user_indexes
2 WHERE table_name=<table_name>
3 AND num_rows is not null;
b、如果我们先用CBO的方?我们应及时去更新表和索引的统计信?以免生Ş不切合实的执行计划?
SQL> ANALYZE TABLE table_name COMPUTE STATISTICS;
SQL> ANALYZE INDEX index_name ESTIMATE STATISTICS;
具体的ANALYZE语句请参照Oracle8i/9i 的refrence文档?
ha是一个接口实现类Q在该场景下Q对应的接口实现cMؓQ?br />org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
SimpleControllerHandlerAdaptercM对应的实C码ؓQ?/p>
调用的是对应的Controller接口中方法,当前Controller对应的接口实现类为我们配|的自定义控制类Q一般承于org.springframework.web.servlet.mvc.SimpleFormController;一层一层再跟踪发现Q?br />SimpleFormControllerl层于同包AbstractFormControllerc,?br />AbstractFormControllerl承于同包AbstractControllerc,对应?br />handleRequest(request,response)在AbstractControllercM实现Q最l调用代码如下:
handleRequestҎZ个抽象方法,在AbstractFormControllercM实现Q终于找到原因了Q呵?br />
原因实际很简单,因为我在要提交的表单中没有采用postҎQ呵?br />而isFormSubmission(request)是Ҏ此项判断Q所以其实际执行的代码ؓQ?br />return showNewForm(request, response);
而我在对应的配置属性中没有配置对应属?formView|因ؓ我本来就不是要展C个新表单?br />故最后返回的ModelAndView为空?br />
问题都解决了Q只是没惛_Ҏ交表单这么严|其他web框架是没有这U限Ӟ不过也没多大关系Q在实际开发中我们大都是采用post方式提交表单的?br />
学习心得Q?br />Spring提供三种创徏cd例方?
a、通过构造函敎ͼ讉K属性可以是L
b、通过对应cȝ静态工厂方法,注意不能是私有的
c、通过工厂cȝ实例工厂ҎQ是非静态的Ҏ
Q、bean节点相关主要属性:
id/name 实例?别名
class 必须、类全名
singleton 是否为单实例Q默认ؓtrue
init-method 初始化方?br /> depends-on 指定依赖Bean,实现在被依赖Bean实例创徏前,对依赖的一个或多个Bean的实例化,
init-method在对应Bean实例已经创徏后调?br /> destroy-method 释放回调ҎQ常用于资源释放
dependency-check 依赖?br /> parent 指定父Bean实例Q减因l承关系的重复配|?/p>
说明除配|init-method,destory以外Q可以在对应Bean中实现InitializingBean,DisposableBean两个接口Ҏ
Spring容器不负责管理非单实例的Bean
配置bean事项Q?br />1、注意在通过构造器参数匚wӞ必须指定参数的序P同时明确说明cdQ?br /> <constructor-arg index="0"><value>128</value></constructor-arg>
<constructor-arg index="1"><value>teststring</value></constructor-arg>
最好说明相兛_数类型类型?
<constructor-arg index="0" type="int"><value>128</value></constructor-arg>
<constructor-arg index="1" type="java.lang.String"><value>teststring</value></constructor-arg>
可以使用化配|?br /> <constructor-arg index="0" type="int" value="128"/>
<constructor-arg index="1" type="java.lang.String" value="testString"/>
2、属性ؓI?br /> <property name="pro1><null/></property>
3、空?
<property name="pro1><value></value></property>
二、常用elements
bean | ref | idref | value | null | list | set | map | props
说明Q?br /> bean 创徏一个新的bean实例
ref 引用已经创徏的bean实例
value 单数据类?br /> null I指?br /> list 创徏java.util.ArrayList对象实例
set 创徏java.util.LinkedHashSet对象实例
map 创徏java.util.LinkedHashMap对象实例
props 创徏java.util.Properties实例
list,set,map可以多层嵌套配置
遗留问题Q?br />idref 配置没有起作用,cMvalue配置Q测试输Zؓ字符串对象,是否配置不正?
上述配置范围基本覆盖了我们开发时的bean使用情况Q详见配|可以参考dtd
http://www.springframework.org/dtd/spring-beans.dtd
ApplicationContext l承于BeanFactory相关接口Q针对企业应用的,占有内存较多
BeanFactory 提供配置框架和基本功能,适用于对内存有限制的相关应用
功能Q?br />1、提供消息访问,ApplicationContext 本nl承于MessageSource接口Q?br /> ApplicationContext 加蝲时查扑֯应的MessageSource Bean, bean id 必须为messageSource
Spring框架提供两个MessageResource实现Q?br /> org.springframework.context.support.ResourceBundleMessageSource
org.springframework.context.support.StaticMessageSource
2、事件传?br />3、用资?br />
目的Q?/strong>
a、b׃要说了,那时候的代码l构真是天马行空Q我当时初学Q维护公怸个项目代码,1个jsp实现一个模块所有功能,我花了好长时间才 L代码?br /> 时代L向前发展的,慢慢的系l结构层ơ上是越来越清晰Q开发效率也来高Q维护也来容易(Z一定的培训成本Q?br />
在实际项目中ZE_性以及团队开发技能我一直没考虑采用Spring框架Q最q有旉p划学习Spring框架Qؓ以后的项目开发做相关的技术储备?/p>
回顾Q?/strong>
开源框架在以前的项目中用过不少Q?struts,webwork,hibernate,前两者属于web框架Q后者属于ORM框架Q这些框架基本都是侧重于应用的某个层面,不能UC为J2EE全面的框Ӟ往往是需要和其他框架相结合,我开发的目采用q如下组合,有的Ҏ没有框Ӟ只是自己做了设计装
a、servlet+jdbc,
b、servlet+jsp+javabean+jdbc,
c、struts+BD+DAO ,
d、webwork+ejb+hibernate
使用体会Q?/strong>
相对而言Z设计理念来讲Q个人更喜欢webwork+hibernate框架l合?/font>
常有论同{开发层面框架的优缺点,我所属品的另外一个项目团队曾lؓ目后箋开?应该采用strutsq是webwork争论的不可开交, 其实个h认ؓstruts,webwork都是非常好的web框架Q都有自w的优缺点:
struts开创web MVC框架之先治I2003Q?004q开发的目基本都是采用struts框架Q当时招聘h的时候常问会不会strutsQ会基本招了 )Q实际MVC设计理念很早提ZQ在j2SE中有很多使用之处Q但当时没有一个web框架开发中很好的诏彻该设计理念Q直到struts 出现Q可能有Q只是没有apache更引人注意)?br />
struts优点使用用户多,相关技术文档比较全面,开发遇到的问题相关案例也比较多、比较容易解冻I框架更加E_(q一炚w帔R要)?br />
webwork相对于struts来讲Q的有不少优异之处Q(也是情理之中的事Q后发布的框架如果再没有优点别h也不会用)
个h认ؓ在开发上主要有以下几点:
1、页面数据封装成值对象功能比struts强大Qwebwork采用ognlcd转化?br /> struts只能对简单类型的数据对象以及文g对象装成值对? 而webwork装的值对象基本没有限Ӟ值对象属性还可以是List,Mapq些对象Q这个特性在我们开发一些批量数据、复杂数据处理时非常方便Q,减少很多代码量,代码非常整洁?br />
2、拦截器功能
拦截器是webwork的一个亮点,实际上也是业界比较流行的AOP的一个体玎ͼ在实际开发中你可以配|默认的拦截器, 也可以ؓ单独的模块指定特定的拦截器,q且可自定义拦截器,action执行前后拦截都可以。?br />
3、单元测试比较方?br /> 最早用struts框架开发测试时Q相关的单元试基本是不好做的,无法qweb环境Q测试都是只做集成测试、系l测试?br /> 使用webwork可以单对action相关属性赋|可以相关的单元测试,当然前提是在对应action中没有引用web环境相关的对象。?br /> 其实webwork框架核心q是xwork框架Q最早框架用在C/Sl构下,webwork只是xwork的一个在web环境的实玎ͼ只是ActionContext 上下文发生了变化Q所以说action能够做到qweb环境也是情理之中的?/p>
4、配|文?br />webwork配置文g可以采用引用、承其他配|文件方式,在团队开发一般都是分模块开发,q样比较方便Q配|管理更ҎQ不会冲H?br />
5、模板技术集?br /> 我在实际应用目中是采用velocity模板做视囑ֱ玎ͼ因ؓ在对应版本的webwork框架中和velociy集成的相当好Q比较方便, 比直接写jsp代码更整z、同时利用velocity模板Ҏ结合每个action的配|文Ӟ可实现比较通用的页面查询、录入等视图的展现?br /> 而struts是没有相x杉K成,不过struts的tag相对而言比webwork的tag好用Qwebwork如果视图是jspcdQ相关的tag真的比较ȝ, 虽然tag 库很丰富Q这也是我ؓ什么用velocity做视囄原因 。?br />
6?框架的效验功?br /> 老实_两者框架的效验功能都比较麻烦,相对而言webwork更加ȝ点,配置较多Q验证接口实现太ȝQ我实际目使用中还是 自定义了相兛_台验证接口, 要验证的相关action只要实现相关接口卛_Q相x截器负责拦截验证Q 大部分的效验根据配|数据以及html对象自定义属性通过javascript通用效验Q实际上现在ZXmlHttp的ajax技术应用成熟的? 后台验证接口的用途会逐渐淡化?
说明上述比较版本?struts 1.0 /webwork 2.1.6Q后lstruts框架扩展很多功能Q不是很了解Q可能和上诉描述不一定很d?br />
现在两者已l合qӞ希望能结合两者的优势Q发展出更好web框架?br />
7、关于Hibernateq是DAO模式Q个人徏议采用hibernate+DAO盔R合的模式Qhibernate占主导地位?br /> 虽然DAO模式通过自动生成代码效率不会低,但如果需求变更就比较ȝQ维护修改代码较多,试工作量也较大Q 但Hibernate不是万能的,在一些必要的应用q是采用DAO模式Q特别是性能相关的部分?
废话一大堆Q也把我的工作回顾了一遍,呵呵Q这两天单了解Spring框架Q个人感觉Spring更像一个全面的J2EE框架解决Ҏ, 希望能够有时间系l的学习一把,大家有兴的请多多交?我会我的学习心得和大家分n?br />
]]>