抽象
本文根據(jù)自定義類別將Java EE Security與Apache Shiro和Spring Security進(jìn)行了比較。它針對希望獲得一個(gè)大致概念的讀者,該選擇哪種框架來保護(hù)其應(yīng)用程序。因此,本篇文章將不深入。為了提供一些上下文,我們將簡要介紹測試環(huán)境。然后進(jìn)行實(shí)際比較。自定義類別為文檔,易用性,社區(qū)支持和差異化功能。結(jié)論中總結(jié)了我們的發(fā)現(xiàn)。
Java EE應(yīng)用程序通常包含多個(gè)組件。甲容器保持這些部件。Java EE的安全性模型指定容器必須提供或支持某些安全性功能。您可以通過兩種方式實(shí)現(xiàn)這些功能:聲明式和編程式。
聲明性的:開發(fā)人員在部署描述符和/或代碼中使用注釋指定安全要求。關(guān)于注釋的最酷的事情是,您可以將它們放在類和/或方法上,而不用編寫冗長的XML代碼。
程序化的:提供基于安全上下文做出與安全相關(guān)的決策的能力。如果注釋和部署描述符的表達(dá)能力不夠,“ Java EE教程,第7版”文檔建議使用此方法。一個(gè)示例是使資源僅在一天的特定時(shí)間訪問。
兩種方法都基于Java身份驗(yàn)證和授權(quán)服務(wù)(JAAS) API。
的兩個(gè)主要特征(“ shiro” = jap?!?castle”)是簡單性和容器獨(dú)立性。它的核心功能是身份驗(yàn)證,授權(quán),加密和會(huì)話管理。
身份驗(yàn)證設(shè)計(jì)簡單而直觀。該過程是基于主題的,由開發(fā)人員僅使用幾個(gè)方法調(diào)用來執(zhí)行。豐富的異常層次結(jié)構(gòu)有助于錯(cuò)誤診斷。記住,我本身就包含功能??刹灏蜠AO可以用于實(shí)現(xiàn)領(lǐng)域,并且可以將一個(gè)主題登錄到多個(gè)領(lǐng)域,同時(shí)保持其統(tǒng)一視圖。
授權(quán)也是基于主題的。訪問權(quán)限由主題角色和權(quán)限確定。要立即開始實(shí)施權(quán)限,可以使用Shiro的自制通配符權(quán)限語法。為了改善用戶體驗(yàn)和性能,支持不同的緩存解決方案。
密碼學(xué)功能以簡單性為中心。Shiro的主要目標(biāo)是使Java密碼學(xué)擴(kuò)展易于使用。由于Shiro的API是接口驅(qū)動(dòng)和基于POJO的,因此可以使用任何JavaBeans兼容格式輕松配置加密組件。
即使對于非基于Web的應(yīng)用程序,也可以使用Shiro進(jìn)行會(huì)話管理。由于會(huì)話對象也是POJO的對象,因此可以將它們持久保存在任何類型的存儲(chǔ)中。一些更流行的緩存解決方案也可以在這里使用。
此外,Shiro還提供特定于Web的功能。通過通過web.xml為您的應(yīng)用程序啟用Shiro,您可以保護(hù)任何URL,還可以為每個(gè)URL指定過濾器鏈。
與前兩個(gè)框架一樣,Spring Security的功能圍繞身份驗(yàn)證和授權(quán)。它可以與無Spring的應(yīng)用程序以及基于Spring的應(yīng)用程序一起使用。這主要是因?yàn)榕cApache Shiro一樣,Spring Security與容器無關(guān)。
Spring Security的創(chuàng)建始于2003年下半年,當(dāng)時(shí)是一個(gè)名為“ Spring Acegi Security System”的項(xiàng)目,當(dāng)時(shí)是一個(gè)簡單的實(shí)現(xiàn),最初并未發(fā)布。隨著越來越多的Spring社區(qū)成員要求提供安全功能,他們獲得了上述項(xiàng)目。2004年初,大約有20個(gè)人在使用該項(xiàng)目。越來越多的人加入,最終在2004年3月創(chuàng)建了SourceForge項(xiàng)目。2006年5月,Acegi成為Spring的正式子項(xiàng)目,在2007年,它成為Spring Portfolio的一部分,并更名為“ Spring Security”。
該框架是一個(gè)簡單的測試Web的應(yīng)用程序組成的的REST API和一個(gè)index.html(也:登錄/注銷/的error.html)在開發(fā)Eclipse的霓虹燈對Java EE與WildFly 10.1.0.Final作為應(yīng)用服務(wù)器和PostgreSQL 9.6的持久性。
Java EE安全性文檔絕對是最基礎(chǔ)的文檔,因?yàn)樗粌H說明了如何使用安全性功能,而且還花了一些時(shí)間(而且篇幅較長,篇幅較長)來解釋基本的應(yīng)用程序安全性概念。大多數(shù)其他框架都遵循文檔中列出的安全模型,因此即使您不打算實(shí)際使用API,也值得一讀,特別是對于初學(xué)者。但是,如果您想快速入門,則可能需要尋找更簡潔的方法。
Spring Security的文檔非常全面。如果您想了解更多信息,可以快速入門,并繼續(xù)閱讀。除了一些基本的應(yīng)用程序安全性術(shù)語外,它還涵蓋了Spring Security可以做的所有事情?;蛘咧辽倌赡軙?huì)喜歡它,因?yàn)楫?dāng)您閱讀某個(gè)組件時(shí),可能會(huì)提到五個(gè)(或大約)新的相關(guān)組件。因此,這可能會(huì)讓您感到不知所措。
與其他兩個(gè)相比,Apache Shiro的文檔介于兩者之間。它確實(shí)解釋了一些基本術(shù)語和定義,以及Shiro本身的工作方式或可以用它完成的大部分工作。但是,請注意它被稱為“大多數(shù)”,而不是“全部”,因?yàn)槟赡軙?huì)遇到一些空的“ TODO”部分。
對于使用聲明式樣式的非?;镜呐渲?,這三者都同樣容易,其中Shiro處于領(lǐng)先地位,而Java EE Security則處于落后地位,而Spring Security處于中間位置。
Shiro的聲明式配置風(fēng)格真正令人感到滿意的是它的光滑度(甚至 看起來不錯(cuò))和簡單。您將配置寫入一個(gè)簡單的INI文件中。XML僅用于啟用Shiro本身。
# login / logout configuration | authc = shiro standard FormAuthenticationFilter
authc.loginUrl = /login.html # specifying which URL to redirect to, when Shiro attempts to authenticate a user via authc
authc.successUrl = /index.html # the redirect-URL after a successful login
logout.redirectUrl = /logout.html # the redirect-URL after a successful logout
jan = passwort, employer # format: username = password[, role1[, role2[, roleN]]]
ajn = passwort
# define permissions for roles
employer = * # granted all permissions
employee = shop:browse:* # granted permission to browse the shop and do any related action
/login.html = authc # this step is necessary to register /login.html as the loginUrl of the authc filter
/index.html = authc # catch requests to /index.html and let the authc filter process them
/logout = logout # catch requests to /logout and let the logout filter process them
# REST urls | noSessionCreation is used to avoid creation of sessions | authcBasic = shiro's standard BasicHttpAuthenticationFilter
/rest/shop/browse/** = noSessionCreation, authcBasic, perms["shop:browse:*"] # the perms filter additionally checks the subject for the specified permissions
/rest/shop/add = noSessionCreation, authcBasic, roles[employer] # the roles filter checks the subject for the specified roles
/rest/shop/delete/* = noSessionCreation, authcBasic, roles[employer]
相比之下,通過web.xml配置Java EE Security有點(diǎn)累。但是,最大的缺點(diǎn)是僅憑web.xml不能滿足要求。您還必須配置您的應(yīng)用程序服務(wù)器。當(dāng)嘗試實(shí)現(xiàn)更高級的功能(例如JDBC領(lǐng)域)時(shí),這可能會(huì)令人感到沮喪。
請注意,除了/index.html外,沒有其他受保護(hù)的URL。REST URL使用注解進(jìn)行保護(hù),在這種情況下,這樣做較為容易。幾乎快要看到胖的<security-constraint>元素了嗎?與shiro.ini相比,您比實(shí)際規(guī)則更忙于編寫元素名稱。對于小型應(yīng)用程序,這似乎并不重要,因?yàn)槟梢灾付ǘ鄠€(gè)<url-pattern>。但是想象一下,編寫具有更多角色和規(guī)則來實(shí)施和保護(hù)URL的代碼。
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
<display-name>PetShop</display-name>
<welcome-file>index.html</welcome-file>
<servlet-name>Logout</servlet-name>
<servlet-class>src.servlet.Logout</servlet-class>
<servlet-name>Logout</servlet-name>
<url-pattern>/logout</url-pattern>
<param-name>resteasy.role.based.security</param-name> <!-- turn on JAX-RS Annotations -->
<param-value>true</param-value>
<login-config> <!-- configure authentication -->
<auth-method>FORM</auth-method> <!-- form-based authentication chosen -->
<realm-name>secureDomain</realm-name> <!-- name of your security realm on the application server -->
<form-login-config> <!-- specify the login and error page -->
<form-login-page>/login.html</form-login-page>
<form-error-page>/error.html</form-error-page>
<security-constraint> <!-- here you can make a set of URL's only accessible to certain user roles -->
<web-resource-collection> <!-- you can also specify wich HTTP methods have to be protected -->
<web-resource-name>Some name</web-resource-name>
<url-pattern>/index.html</url-pattern> <!-- the URL pattern to be protected -->
<auth-constraint> <!-- the set of roles which are granted access to the URL's specified in <web-resource-collection> -->
<role-name>employer</role-name>
<role-name>employee</role-name>
<security-role> <!-- the security roles used by the application -->
<role-name>employer</role-name>
<role-name>employee</role-name>
Spring Security的基本配置非常簡單。它甚至可能比Shiro的要容易一些。它將創(chuàng)建一個(gè)登錄頁面(如果您沒有登錄頁面),并添加針對CSRF和會(huì)話固定的保護(hù)。不過,自動(dòng)保護(hù)最適合JSP。對于HTML,變通辦法將是必需的。
要實(shí)現(xiàn)自定義組件,您將必須學(xué)習(xí)XML中的bean定義以及Spring的注入。這可能會(huì)導(dǎo)致大量的bean聲明,從而使.xml難以閱讀。另外,使用批注還需要進(jìn)一步的Spring或AspectJ依賴性。
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!-- use the <http> element to configure a filter chain -->
<http pattern="/rest/**" create-session="never"> <!-- apply chain on a specific URL using 'pattern' | control session creation using 'create-session' -->
<intercept-url pattern="/**" access="hasRole('EMPLOYER')" /> <!-- access to every URL following /rest/ is restricted to the 'EMPLOYER' role -->
<http-basic /> <!-- turn on HTTP Basic Authentication -->
<http> <!-- a <http> element without a pattern attribute is applied to all incoming requests that are not caught by other <http> elements before it -->
<intercept-url pattern="/login.jsp" access="hasRole('ANONYMOUS')" /> <!-- grant everyone access to /login.html -->
<intercept-url pattern="/index.jsp" access="hasRole('EMPLOYEE') or hasRole('EMPLOYER')" /> <!-- restrict access to index.jsp to subjects in the 'EMPLOYEE' or 'EMPLOYER' role -->
<form-login login-page="/login.jsp" default-target-url="/index.jsp"
always-use-default-target="true" /> <!-- turn on form authentication, set default success url, tell spring to always use that url -->
<logout /> <!-- turn on logout -->
<remember-me /> <!-- turn on remember me -->
<csrf disabled="true" /> <!-- turn on csrf protection -->
<authentication-manager> <!-- turn on authentication services -->
<authentication-provider> <!-- compares the supplied username/password combination with the ones stored in <user-service> -->
<user-service> <!-- store username/password pairs in-memory -->
<user name="jan" password="passwort" authorities="ROLE_EMPLOYER" />
<user name="naj" password="passwort" authorities="ROLE_EMPLOYEE" />
這里沒有太多要說的,因?yàn)榕c其他兩個(gè)相比,Spring Security具有龐大的社區(qū)。關(guān)于Spring Security的Stack Overflow(SO)有很多問題和答案,因此最有可能至少找到一些問題的提示。此外,不再支持官方論壇,它們僅在閱讀模式下可用。支持已移至SO。在那里,國防部監(jiān)視某些標(biāo)簽。
對Shiro的支持相當(dāng)“不錯(cuò)”。有一個(gè)官方用戶論壇,活動(dòng)活躍。在其他資源上尋求幫助不會(huì)產(chǎn)生更多的結(jié)果。您可能會(huì)看到相同的人(例如原始開發(fā)人員Lez Hazelwood)在受歡迎的網(wǎng)站(例如SO)上回答問題,這不一定是不好的。解決意外問題可能需要一些時(shí)間。
關(guān)于Java EE安全性支持的最糟糕的事情是,您還必須依賴于所使用容器的社區(qū)。因此,解決問題所需的支持,精力和時(shí)間會(huì)有所不同。
但是,這三個(gè)都在積極發(fā)展中。盡管Java EE Security通過Soteria API(Java EE 8)獲得了新功能,但Spring Security和Shiro仍在不斷改進(jìn)。
Shiro的簡單性和靈活性令人贊嘆。INI配置進(jìn)一步強(qiáng)調(diào)了這一點(diǎn)。Shiro還建議盡可能獨(dú)立于其他技術(shù)。它還需要很少的依賴關(guān)系,使其輕量級。非Web應(yīng)用程序(例如CLI客戶端或移動(dòng)應(yīng)用程序)的會(huì)話管理和通配符許可語法也很重要。
Spring Security的自動(dòng)保護(hù)機(jī)制使它在Web應(yīng)用程序的上下文中具有最初的優(yōu)勢。總的來說,可以說該框架在網(wǎng)絡(luò)方面是相對全面的。但是,這是以犧牲自己的體重為代價(jià)的,并且在某些情況下必須綁定到Spring技術(shù)。與Shiro的通配符權(quán)限語法相反,Spring Security中的權(quán)限可以基于Spring EL來實(shí)現(xiàn)。
此處缺少Java EE安全性。換句話說,它確實(shí)不提供任何出色的功能,僅滿足應(yīng)用程序安全性的最基本需求。
如果您的應(yīng)用程序非常小,用戶和角色沒有太多,并且不需要使用任何過于高級的功能,請隨時(shí)使用Java EE Security。為此,它提供了堅(jiān)實(shí)的基礎(chǔ)。但是,Java EE安全性的可能性很快就被耗盡了。例如,您只能為整個(gè)應(yīng)用程序指定一種身份驗(yàn)證機(jī)制。另外,如果應(yīng)用程序需要可移植,則一定要使用其他兩個(gè)框架之一。
現(xiàn)在,如果需要一個(gè)很大程度上獨(dú)立的,輕量級的和可擴(kuò)展的安全解決方案,那么Apache Shiro是必經(jīng)之路。但是,不利的一面是可能需要花費(fèi)一些時(shí)間才能解決問題。一個(gè)人可能還必須自己實(shí)現(xiàn)一些功能。Shiro的設(shè)計(jì)(基于接口的驅(qū)動(dòng)和基于POJO的)促進(jìn)了這一點(diǎn)。
最后,如果該應(yīng)用程序已經(jīng)基于Spring,那么不妨繼續(xù)使用Spring Security,在這種情況下沒有任何實(shí)際的缺點(diǎn)(除了Spring Security難以實(shí)現(xiàn))。對于沒有彈簧的應(yīng)用程序,這是不同的,即使以前從未使用過Spring,也是如此。首先,更難實(shí)現(xiàn)高級功能,除非包含Spring本身或AspectJ,否則不能使用注釋。另外,如果需要Spring OAuth2,則必須使用spring-mvc而不是Jersey或RESTeasy來創(chuàng)建REST資源。
至此,我們的比較結(jié)束了。再次提醒我們有關(guān)觀測的相對性。自己嘗試框架,并使用最適合您需求的框架。
==============================================================
相對于Apache Shiro,Spring Security提供了更多的諸如LDAP、OAuth2.0、ACL、Kerberos、SAML、SSO、OpenID等諸多的安全認(rèn)證、鑒權(quán)協(xié)議,可以按需引用。對認(rèn)證/鑒權(quán)更加靈活,粒度更細(xì)。可以結(jié)合你自己的業(yè)務(wù)場景進(jìn)行更加合理的定制化開發(fā)。在最新的Spring Security 5.x中更是提供了響應(yīng)式應(yīng)用(reactive application)提供了安全控制支持。從語言上來講,支持使用kotlin、groovy進(jìn)行開發(fā)。Spring Security因?yàn)槭抢昧薙pring IOC 和AOP的特性而無法脫離Spring獨(dú)立存在。
而Apache Shiro可以獨(dú)立存在。但是Java Web領(lǐng)域Spring可以說是事實(shí)上的J2EE規(guī)范。使用Java技術(shù)棧很少能脫離Spring。也因?yàn)楣δ軓?qiáng)大Spring Security被認(rèn)為非常重,這是不對的。認(rèn)真學(xué)習(xí)之后會(huì)發(fā)現(xiàn)其實(shí)也就是那么回事。兩種框架都是非常優(yōu)秀的安全框架,根據(jù)實(shí)際需要做技術(shù)選型。
如果你使用微服務(wù)建議使用 Spring Seucurity ,比較簡單的應(yīng)用可以使用Shiro。Spring Seucurity 學(xué)習(xí)起來也不難,我出了一個(gè)從零開始的Spring Security教程,目前廣受好評,你可以到我個(gè)人博客felord.cn去免費(fèi)獲取。
另外,即使是在微服務(wù)時(shí)代,shiro也很好用,可以改造stateless模式就可以達(dá)到和spring security一樣的效果了,重點(diǎn)是輕量級!上手快!
聯(lián)系客服