JdbcDaoImpl擁有衆多的可配置選項使其能夠在已存在的schema中使用,或對其功能進行更復雜地調整。在不少場景下,極可能咱們只需調整內置UserDetailsService類的配置而不須要寫本身的代碼。html
有一個很重要的功能就是在用戶(User)和權限(GrantedAuthority)之間添加一個隔離層(a level of indirection——找不到更好的譯法了),這經過將GrantedAuthority按照邏輯劃分紅集合即組(group)來實現。用戶可以被分配到一個或多個組,而組的成員被賦予了一系列的GrantedAuthority聲明。spring
正如在圖中所描述的那樣,中間的隔離層使得咱們能夠將相同集合的角色分派給不少人,而這隻須要指定新用戶到存在的組中便可。將這與咱們以前的作法對比,在之前的作法是將GrantedAuthority直接分配給單個的用戶。sql
這種將權限進行打包處理的方式可能在如下的場景中用到:數據庫
要將用戶分紅不一樣的組,而組之間有些角色是重疊的;安全
想要全局地修改一類用戶的權限。如,若是你擁有一個「供應商」的分組,而你想要修改他們可否訪問應用特定區域的設置;spa
擁有大量的用戶,你不須要用戶級別的受權配置。操作系統
除非你的應用用戶量頗有限,不然極可能要使用基於組的訪問控制。這種管理方式的簡便性和擴展性帶來的價值遠遠超過了它稍微增長的複雜性。這種將用戶權限集中到組中的技術一般叫作基於組的訪問控制(Group-Based Access Control ,GBAC)。code
【基於組的訪問控制幾乎在市面上任何安全的操做系統和軟件包中都能看到。微軟的活動目錄(Active Directory,AD)是大範圍使用GBAC的典型實現,它把AD的用戶歸入組中並給組受權權限。經過使用GBAC,可以指數級得簡化對大量基於AD組織的權限管理。想一下你所使用軟件的安全功能——用戶、分組以及權限是如何管理的?這種方式編寫安全功能的利弊是什麼?】xml
讓咱們對JBCP Pets添加一層抽象,並將基於組的受權理念應用於這個站點。htm
咱們會爲站點添加兩個組——普通用戶(咱們將其稱爲「Users」)和管理員(咱們將其稱爲「Administrators」)。經過修改用於啓動數據庫的SQL腳本,將已經存在的guest和admin帳號分配到合適的組中。
首先,咱們須要爲JdbcDaoImpl的自定義實現類設置屬性以啓用組的功能,並關閉對用戶直接受權的功能。在dogstore-base.xml中添加以下的bean聲明:
<bean id="jdbcUserService" class="com.packtpub.springsecurity.security.CustomJdbcDaoImpl"> <property name="dataSource" ref="dataSource"/> <property name="enableGroups" value="true"/> <property name="enableAuthorities" value="false"/> </bean>
注意的是,若是你一直跟着咱們的例子在作,而且使用了JdbcUserManager的代碼和配置,請對其進行修改,由於在本章的剩餘部分咱們將使用CustomJdbcDaoImpl。
咱們須要簡單修改構建數據庫的SQL語句:
定義咱們的組信息;
指定GrantedAuthority聲明到組中;
指定用戶到組中。
簡單起見,咱們聲明一個名爲test-users-groups-data.sql的新SQL腳本。
首先,添加組:
insert into groups(group_name) values ('Users'); insert into groups(group_name) values ('Administrators');
接下來,指定角色到組中:
insert into group_authorities(group_id, authority) select id,'ROLE_ USER' from groups where group_name='Users'; insert into group_authorities(group_id, authority) select id,'ROLE_ USER' from groups where group_name='Administrators'; insert into group_authorities(group_id, authority) select id,'ROLE_ ADMIN' from groups where group_name='Administrators';
接下來,建立用戶:
insert into users(username, password, enabled) values ('admin','admin',true); insert into users(username, password, enabled) values ('guest','guest',true);
最後,指定用戶到組中:
insert into group_members(group_id, username) select id,'guest' from groups where group_name='Users'; insert into group_members(group_id, username) select id,'admin' from groups where group_name='Administrators';
咱們須要更新嵌入式HSQL數據庫的建立配置指向這個腳本,而不是已經存在的test-data.sql腳本:
<jdbc:embedded-database id="dataSource" type="HSQL"> <jdbc:script location="classpath:security-schema.sql"/> <jdbc:script location="classpath:test-users-groups-data.sql"/> </jdbc:embedded-database>
要注意的是,security-schema.sql腳本已經包含了支持組功能的表聲明,因此咱們不須要修改這個腳本了。
到這裏,你能夠重啓JBCP Pets站點,它將與之前的表現徹底一致,可是,咱們在用戶和權限間添加的抽象層使得咱們可以更容易地開發開發複雜的用戶管理功能。
讓咱們暫時離開JBCP Pets的場景,瞭解在這個方面上一個更爲重要的配置。
使用遺留的或用戶自定義的schame實現基於數據庫的認證
一般來講,Spring Security的新用戶可能須要適配用戶、組和角色到已有的數據庫schema中。儘管遺留的數據庫並不匹配Spring Security要求的數據庫schema,但咱們仍是能夠經過配置JdbcDaoImpl來匹配它。
假設咱們擁有一個以下圖所示的遺留數據庫schema,要基於它實現Spring Security:
咱們可以很容易地修改JdbcDaoImpl的配置來使用這個schema並重寫咱們在JBCP Pets中使用的默認Spring Security表定義和列。
JdbcDaoImpl有三個SQL查詢,它們有定義良好的參數和返回列的集合。咱們必須機遇它們提供的功能,肯定每一個查詢的SQL。JdbcDaoImpl的每一個SQL查詢都是使用登陸時提供的用戶名做爲惟一的參數。
要注意的是,在一些場景中返回的列在默認的JdbcDaoImpl實現中並無用到,但咱們依舊須要將這些值返回。在進入下一章節前,請花費一點時間嘗試寫一下基於前面數據庫圖表中的查詢語句。
給不規範的數據庫使用自定義SQL查詢,咱們須要在Spring Bean的配置文件中修改JdbcDaoImpl的屬性。要注意的一點是,爲了給JdbcDaoImpl配置JDBC查詢,咱們不能使用<jdbc-user-service>聲明。必要要明確實例化這個bean,如同咱們在自定義JdbcDaoImpl實現時所做的那樣:
這是Spring Security從已存在且不符合默認schema的數據庫中讀取設置時,惟一須要配置的地方。須要記住的是,在使用已存在的schema時,一般會須要擴展JdbcDaoImpl以支持修改密碼、重命名用戶帳號以及其餘的用戶管理功能。
若是你使用JdbcUserDetailsManager來完成用戶管理的任務,這個類使用了大約20個可配置的SQL查詢。請參考Javadoc或源碼來了解JdbcUserDetailsManager使用的默認查詢。