一、前言
資料庫認證(Database-provided authentication):應用通過資料庫擷取使用者認證資訊。
認證提供者(Authentication Provider):Spring提供了一系列認證方式,如LDAP、OpenID等,對應的認證服務都需要實作AuthenticationProvider接口,開發人員可以自定義AuthenticationProvider實作。
二、Spring配置
資料庫認證本質上與其它認證方式沒有差別,差別就是擷取使用者及其權限資訊的方式不同,資料庫認證需要從資料庫讀取使用者資訊,Spring已經預定義了使用者安全的相關表結構和操作實作,請參考下面兩個類的源碼,這些預設實作能滿足大部分應用需求,當然也很容易自己定制。
org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl
org.springframework.security.provisioning.JdbcUserDetailsManager
對于擷取使用者、使用者組、權限的查詢都提供了預設的SQL,是以這也不需要開發者定義,但需要了解Spring的預設實作,如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<code>public</code> <code>class</code> <code>JdbcDaoImpl </code><code>extends</code> <code>JdbcDaoSupport </code><code>implements</code> <code>UserDetailsService {</code>
<code> </code><code>//~ Static fields/initializers =====================================================================================</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_USERS_BY_USERNAME_QUERY =</code>
<code> </code><code>"select username,password,enabled "</code> <code>+</code>
<code> </code><code>"from users "</code> <code>+</code>
<code> </code><code>"where username = ?"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_AUTHORITIES_BY_USERNAME_QUERY =</code>
<code> </code><code>"select username,authority "</code> <code>+</code>
<code> </code><code>"from authorities "</code> <code>+</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY =</code>
<code> </code><code>"select g.id, g.group_name, ga.authority "</code> <code>+</code>
<code> </code><code>"from groups g, group_members gm, group_authorities ga "</code> <code>+</code>
<code> </code><code>"where gm.username = ? "</code> <code>+</code>
<code> </code><code>"and g.id = ga.group_id "</code> <code>+</code>
<code> </code><code>"and g.id = gm.group_id"</code><code>;</code>
我們可以看到Spring盡一切可能減少開發者的工作,但如果需求不能滿足,開發者需要自定義表結構并覆寫查詢SQL定義。
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<code>public</code> <code>class</code> <code>JdbcUserDetailsManager </code><code>extends</code> <code>JdbcDaoImpl </code><code>implements</code> <code>UserDetailsManager, GroupManager {</code>
<code> </code><code>// UserDetailsManager SQL</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_CREATE_USER_SQL =</code>
<code> </code><code>"insert into users (username, password, enabled) values (?,?,?)"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_DELETE_USER_SQL =</code>
<code> </code><code>"delete from users where username = ?"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_UPDATE_USER_SQL =</code>
<code> </code><code>"update users set password = ?, enabled = ? where username = ?"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_INSERT_AUTHORITY_SQL =</code>
<code> </code><code>"insert into authorities (username, authority) values (?,?)"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_DELETE_USER_AUTHORITIES_SQL =</code>
<code> </code><code>"delete from authorities where username = ?"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_USER_EXISTS_SQL =</code>
<code> </code><code>"select username from users where username = ?"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_CHANGE_PASSWORD_SQL =</code>
<code> </code><code>"update users set password = ? where username = ?"</code><code>;</code>
<code> </code><code>// GroupManager SQL</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_FIND_GROUPS_SQL =</code>
<code> </code><code>"select group_name from groups"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_FIND_USERS_IN_GROUP_SQL =</code>
<code> </code><code>"select username from group_members gm, groups g "</code> <code>+</code>
<code> </code><code>"where gm.group_id = g.id"</code> <code>+</code>
<code> </code><code>" and g.group_name = ?"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_INSERT_GROUP_SQL =</code>
<code> </code><code>"insert into groups (group_name) values (?)"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_FIND_GROUP_ID_SQL =</code>
<code> </code><code>"select id from groups where group_name = ?"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_INSERT_GROUP_AUTHORITY_SQL =</code>
<code> </code><code>"insert into group_authorities (group_id, authority) values (?,?)"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_DELETE_GROUP_SQL =</code>
<code> </code><code>"delete from groups where id = ?"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_DELETE_GROUP_AUTHORITIES_SQL =</code>
<code> </code><code>"delete from group_authorities where group_id = ?"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_DELETE_GROUP_MEMBERS_SQL =</code>
<code> </code><code>"delete from group_members where group_id = ?"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_RENAME_GROUP_SQL =</code>
<code> </code><code>"update groups set group_name = ? where group_name = ?"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_INSERT_GROUP_MEMBER_SQL =</code>
<code> </code><code>"insert into group_members (group_id, username) values (?,?)"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_DELETE_GROUP_MEMBER_SQL =</code>
<code> </code><code>"delete from group_members where group_id = ? and username = ?"</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_GROUP_AUTHORITIES_QUERY_SQL =</code>
<code> </code><code>"from groups g, group_authorities ga "</code> <code>+</code>
<code> </code><code>"where g.group_name = ? "</code> <code>+</code>
<code> </code><code>"and g.id = ga.group_id "</code><code>;</code>
<code> </code><code>public</code> <code>static</code> <code>final</code> <code>String DEF_DELETE_GROUP_AUTHORITY_SQL =</code>
<code> </code><code>"delete from group_authorities where group_id = ? and authority = ?"</code><code>;</code>
資料庫安全認證配置示例:
<code><?</code><code>xml</code> <code>version</code><code>=</code><code>"1.0"</code> <code>encoding</code><code>=</code><code>"UTF-8"</code><code>?></code>
<code><</code><code>beans</code> <code>xmlns</code><code>=</code><code>"http://www.springframework.org/schema/beans"</code>
<code> </code><code>xmlns:security</code><code>=</code><code>"http://www.springframework.org/schema/security"</code>
<code> </code><code>xmlns:jdbc</code><code>=</code><code>"http://www.springframework.org/schema/jdbc"</code> <code>xmlns:xsi</code><code>=</code><code>"http://www.w3.org/2001/XMLSchema-instance"</code>
<code> </code><code>xmlns:context</code><code>=</code><code>"http://www.springframework.org/schema/context"</code>
<code> </code><code>xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd</code>
<code> </code><code>http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.2.xsd</code>
<code> </code><code>http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd</code>
<code> </code><code>http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"></code>
<code> </code><code><</code><code>context:component-scan</code> <code>base-package</code><code>=</code><code>"com.stevex.demo"</code> <code>/></code>
<code> </code><code><</code><code>security:http</code> <code>auto-config</code><code>=</code><code>"true"</code><code>></code>
<code> </code><code><</code><code>security:intercept-url</code> <code>pattern</code><code>=</code><code>"/admin"</code> <code>access</code><code>=</code><code>"ROLE_ADMIN"</code> <code>/></code>
<code> </code><code><</code><code>security:intercept-url</code> <code>pattern</code><code>=</code><code>"/*"</code> <code>access</code><code>=</code><code>"ROLE_USER"</code> <code>/> </code>
<code> </code><code><</code><code>security:form-login</code> <code>/></code>
<code> </code><code></</code><code>security:http</code><code>></code>
<code> </code><code><</code><code>security:authentication-manager</code><code>></code>
<code> </code><code><</code><code>security:authentication-provider</code><code>></code>
<code> </code><code><</code><code>security:jdbc-user-service</code>
<code> </code><code>data-source-ref</code><code>=</code><code>"dataSource"</code>
<code> </code><code>group-authorities-by-username-query="select g.id, g.group_name, ga.authority</code>
<code> </code><code>from groups g, group_members gm, group_authorities ga</code>
<code> </code><code>where gm.username = ? and g.id = ga.group_id and g.id = gm.group_id" /></code>
<code> </code><code></</code><code>security:authentication-provider</code><code>></code>
<code> </code><code></</code><code>security:authentication-manager</code><code>></code>
<code> </code><code><</code><code>jdbc:embedded-database</code> <code>id</code><code>=</code><code>"dataSource"</code><code>></code>
<code> </code><code><</code><code>jdbc:script</code> <code>location</code><code>=</code><code>"classpath:security-schema.sql"</code> <code>/></code>
<code> </code><code><</code><code>jdbc:script</code> <code>location</code><code>=</code><code>"classpath:users.sql"</code> <code>/></code>
<code> </code><code></</code><code>jdbc:embedded-database</code><code>></code>
<code></</code><code>beans</code><code>></code>
embedded-database标簽:Spring預設使用hsql,如果使用其他記憶體資料庫,如Derby,需要指定。
jdbc-user-service标簽:注入基于JDBC的UserDetailsService實作,預設即JdbcUserDetailsManager。
group-authorities-by-username-query标簽:覆寫預設使用者組權限查詢SQL。
authentication-provider标簽:如果沒有設定ref屬性引用其他bean時,預設使用DaoAuthenticationProvider, DaoAuthenticationProvider會調用UserDetailsService接口擷取使用者資訊,并在登入時驗證使用者密碼。
三、後語
本文提供一個基本實作參考供下載下傳。
<a href="http://down.51cto.com/data/2364093" target="_blank">附件:http://down.51cto.com/data/2364093</a>
本文轉自sarchitect 51CTO部落格,原文連結:http://blog.51cto.com/stevex/1363802,如需轉載請自行聯系原作者